taskgraph-ai 0.52.6 → 0.52.7
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 +2 -0
- package/dist/{ai-services-unified-BbSRBK0N.js → ai-services-unified-BoN4p2hA.js} +1 -1
- package/dist/ai-services-unified-CHZ3zO7j.js +1 -0
- package/dist/{commands-DOZyxFfM.js → commands-CVaRxzM_.js} +5 -5
- package/dist/config-manager-96j0so3y.js +1 -0
- package/dist/{config-manager-CKzRb4tZ.js → config-manager-BsFjnt24.js} +1 -1
- package/dist/{dependency-manager-BcQJdp1Y.js → dependency-manager-B8yi2Gx9.js} +124 -114
- package/dist/{init-S96FNSm7.js → init-C5edkNsj.js} +11 -5
- package/dist/mcp-server.js +2 -2
- package/dist/research-CL0Qp4qV.js +1 -0
- package/dist/response-language-CdItlKWm.js +1 -0
- package/dist/{response-language-Ln6H6G2z.js → response-language-HGhUMUxw.js} +1 -1
- package/dist/src-BEBHskRG.js +207 -0
- package/dist/{tag-management-BzAE-dVv.js → tag-management-gKDrWbhk.js} +1 -1
- package/dist/{task-manager-Utma-ZPy.js → task-manager-BkCMdf4Y.js} +1 -1
- package/dist/taskgraph.js +1 -1
- package/dist/update-subtask-by-id-D8UzfSSD.js +1 -0
- package/dist/update-task-by-id-D5vcjz54.js +1 -0
- package/dist/utils-CDh4OilX.js +1 -0
- package/package.json +12 -5
- package/dist/ai-services-unified-CQMZv2X-.js +0 -1
- package/dist/config-manager-BsUS_HoV.js +0 -1
- package/dist/research-cdWIHSpn.js +0 -1
- package/dist/response-language-Bjbf2_9z.js +0 -1
- package/dist/src-Cio2Sps9.js +0 -207
- package/dist/update-subtask-by-id-UcjCRJbf.js +0 -1
- package/dist/update-task-by-id-98Q5zy74.js +0 -1
- package/dist/utils-BzS6gmZZ.js +0 -1
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import{a as e,i as t,n,o as r,t as i}from"./ai-services-unified-
|
|
1
|
+
import{a as e,i as t,n,o as r,t as i}from"./ai-services-unified-BoN4p2hA.js";import{C as a,S as o,a as s,c,d as l,f as u,h as d,i as f,m as p,n as m,o as h,p as g,r as _,s as v,t as y,u as b,v as x,y as S}from"./src-BEBHskRG.js";import{$ as C,A as w,B as T,C as ee,Dt as E,G as D,J as O,K as k,M as A,N as te,Nt as j,Q as M,R as ne,T as re,V as ie,X as ae,Y as oe,Z as se,_t as N,a as ce,bt as le,c as ue,ct as P,d as de,dt as fe,ft as pe,g as me,gt as he,h as ge,ht as F,l as _e,m as ve,n as ye,nt as I,o as L,ot as be,p as xe,pt as R,q as Se,rt as Ce,st as we,tt as z,u as Te,v as Ee,vt as De,xt as B,y as Oe,yt as ke}from"./config-manager-BsFjnt24.js";import"./response-language-HGhUMUxw.js";import V from"chalk";import Ae,{resolve as je}from"node:path";import H from"path";import{spawn as Me}from"child_process";import{z as U}from"zod";import W,*as Ne from"fs";import G from"boxen";import Pe from"readline";import{Command as K}from"commander";import Fe from"figlet";import Ie from"gradient-string";import Le from"terminal-link";import{marked as Re}from"marked";import{markedTerminal as ze}from"marked-terminal";import Be from"turndown";import q from"cli-table3";import Ve from"ora";import He from"process";import Ue from"https";import We from"os";import Ge from"cli-progress";import Ke from"inquirer";import qe,{Separator as Je}from"@inquirer/search";import Ye from"fuse.js";import{smoothStream as Xe}from"ai";import Ze from"ajv";import Qe from"ajv-formats";import $e from"gpt-tokens";import"@streamparser/json";function et(e,t,n){return(n?.color?V[n.color]:V.cyan)(Le(e,t,{fallback:(e,t)=>n?.textOnlyFallback?e:`${e} (${t})`}))}function tt(e,t){return et(e,e,t)}function nt(e,t){return et(e,t,{color:`cyan`})}function rt(){return Le.isSupported}const it=Ie(he);function at(){return process.env.TM_HIDE_BANNER===`true`}function ot(){return process.stdout.columns||80}function st(e={}){if(at())return;let{version:t}=e;try{let e=Fe.textSync(`TaskGraph`,{font:`Standard`,horizontalLayout:`default`,verticalLayout:`default`});console.log(it(e))}catch{console.log(it(`=== TaskGraph ===`))}let n=`x.com/stephennmiller_`,r=et(n,`https://x.com/stephennmiller_`,{textOnlyFallback:!0}),i=V.dim(`by `)+V.cyan(r),a=t?t.replace(/^v/,``):``,o=`https://github.com/stephennmiller/taskgraph-ai/releases/tag/taskgraph-ai%40${a}`,s=t?et(`v${a}`,o,{color:`dim`,textOnlyFallback:!0}):``;if(s){let e=`by ${n}`.length,t=a.length+1,r=ot()-e-t-1;r>=2?console.log(i+` `.repeat(r)+s):(console.log(i),console.log(s))}else console.log(i);console.log(``)}function ct(){if(at())return;try{let e=Fe.textSync(`TaskGraph`,{font:`Standard`,horizontalLayout:`default`,verticalLayout:`default`});console.log(it(e))}catch{console.log(it(`=== TaskGraph ===`))}let e=et(`x.com/stephennmiller_`,`https://x.com/stephennmiller_`,{textOnlyFallback:!0});console.log(V.dim(`by `)+V.cyan(e)),console.log(``)}function lt(e){let{header:t,body:n,callToAction:r,footer:i,level:a=`warn`}=e,o=a===`info`?B.heading:V.yellow.bold,s=a===`info`?N:`yellow`,c=[o(t),...n.map(e=>B.text(e))];r&&r.label&&r.action&&c.push(V.cyan(r.label)+`
|
|
2
2
|
`+B.brand.underline(r.action)),i&&c.push(B.muted(i));let l=c.join(`
|
|
3
3
|
|
|
4
4
|
`);return G(l,{padding:1,borderColor:s,borderStyle:`round`,margin:{top:1,bottom:1}})}const J={done:V.green(`█`),cancelled:B.muted(`─`),deferred:B.muted(`─`),inProgress:B.active(`▓`),review:V.magenta(`▒`),pending:V.yellow(`░`),blocked:V.red(`!`)};function ut(e,t=30,n){if(!n){let n=Math.round(e/100*t),r=t-n;return J.done.repeat(n)+B.muted(`░`).repeat(r)}let r=``,i=0,a=[[n.done,J.done],[n.cancelled,J.cancelled],[n.deferred,J.deferred],[n[`in-progress`],J.inProgress],[n.review,J.review],[n.pending,J.pending],[n.blocked,J.blocked]];for(let[e,n]of a){if(!e||i>=t)continue;let a=Math.min(Math.round(e/100*t),t-i);a>0&&(r+=n.repeat(a),i+=a)}return i<t&&(r+=J.pending.repeat(t-i)),r}function dt(e){let t={total:e.length,done:0,inProgress:0,pending:0,blocked:0,deferred:0,cancelled:0,review:0,completionPercentage:0,completedCount:0};return e.forEach(e=>{switch(e.status){case`done`:t.done++;break;case`in-progress`:t.inProgress++;break;case`pending`:t.pending++;break;case`blocked`:t.blocked++;break;case`deferred`:t.deferred++;break;case`cancelled`:t.cancelled++;break;case`review`:t.review=(t.review||0)+1}}),t.completedCount=e.filter(e=>p(e.status)).length,t.completionPercentage=t.total>0?Math.round(t.completedCount/t.total*100):0,t}function ft(e){let t={total:0,done:0,inProgress:0,pending:0,blocked:0,deferred:0,cancelled:0,review:0,completionPercentage:0,completedCount:0},n=[];return e.forEach(e=>{e.subtasks&&e.subtasks.length>0&&e.subtasks.forEach(e=>{switch(t.total++,n.push(e),e.status){case`done`:t.done++;break;case`in-progress`:t.inProgress++;break;case`pending`:t.pending++;break;case`blocked`:t.blocked++;break;case`deferred`:t.deferred++;break;case`cancelled`:t.cancelled++;break;case`review`:t.review=(t.review||0)+1}})}),t.completedCount=n.filter(e=>p(e.status)).length,t.completionPercentage=t.total>0?Math.round(t.completedCount/t.total*100):0,t}function pt(e){let t=new Set(e.filter(e=>p(e.status)).map(e=>e.id)),n=e.filter(e=>!p(e.status)&&(!e.dependencies||e.dependencies.length===0)).length,r=e.filter(e=>!p(e.status)&&e.dependencies&&e.dependencies.length>0&&e.dependencies.every(e=>t.has(e))).length,i=e.filter(e=>!p(e.status)&&e.dependencies&&e.dependencies.length>0&&!e.dependencies.every(e=>t.has(e))).length,a={};e.forEach(e=>{e.dependencies&&e.dependencies.length>0&&e.dependencies.forEach(e=>{let t=String(e);a[t]=(a[t]||0)+1})});let o,s=0;for(let[e,t]of Object.entries(a))t>s&&(s=t,o=parseInt(e));let c=e.reduce((e,t)=>e+(t.dependencies?t.dependencies.length:0),0),l=e.length>0?c/e.length:0;return{tasksWithNoDeps:n,tasksReadyToWork:n+r,tasksBlockedByDeps:i,mostDependedOnTaskId:o,mostDependedOnCount:s,avgDependenciesPerTask:l}}function mt(e){let t={critical:0,high:0,medium:0,low:0};return e.forEach(e=>{let n=e.priority||`medium`;t[n]++}),t}function ht(e){return e.total===0?{}:{done:e.done/e.total*100,"in-progress":e.inProgress/e.total*100,pending:e.pending/e.total*100,blocked:e.blocked/e.total*100,deferred:e.deferred/e.total*100,cancelled:e.cancelled/e.total*100,review:(e.review||0)/e.total*100}}function gt(e,t=!1,n=!1){let r=[];t?r.push(`${J.done} Completed: ${V.green(`${e.completedCount}/${e.total}`)}`):r.push(`${J.done} Done: ${V.green(e.done)}`),r.push(`${J.cancelled} Cancelled: ${B.muted(e.cancelled)}`),r.push(`${J.deferred} Deferred: ${B.muted(e.deferred)}`);let i=e=>n?e.slice(0,2).join(` `)+(e.length>2?`
|
|
@@ -12,90 +12,91 @@ Subtasks Progress: ${c} ${V.cyan(u)}\n`+gt(t,!0,r)+`
|
|
|
12
12
|
${V.red(`•`)} ${B.text(`High priority:`)} ${n.high}\n${V.yellow(`•`)} ${B.text(`Medium priority:`)} ${n.medium}\n${V.green(`•`)} ${B.text(`Low priority:`)} ${n.low}`}function vt(e,t){return V.bold(`Dependency Status & Next Task`)+`
|
|
13
13
|
`+V.cyan.bold(`Dependency Metrics:`)+`
|
|
14
14
|
${V.green(`•`)} ${B.text(`Tasks with no dependencies:`)} ${e.tasksWithNoDeps}\n${V.green(`•`)} ${B.text(`Tasks ready to work on:`)} ${e.tasksReadyToWork}\n${V.yellow(`•`)} ${B.text(`Tasks blocked by dependencies:`)} ${e.tasksBlockedByDeps}\n${B.accent(`•`)} ${B.text(`Most depended-on task:`)} ${e.mostDependedOnTaskId?V.cyan(`#${e.mostDependedOnTaskId} (${e.mostDependedOnCount} dependents)`):B.muted(`None`)}\n${B.brand(`•`)} ${B.text(`Avg dependencies per task:`)} ${e.avgDependenciesPerTask.toFixed(1)}\n\n`+V.cyan.bold(`Next Task:`)+`
|
|
15
|
-
ID: ${t?V.cyan(String(t.id)):B.muted(`N/A`)} - ${t?V.bold(t.title):V.yellow(`No task available`)}\nPriority: ${t?.priority||B.muted(`N/A`)} Dependencies: ${t?.dependencies?.length?V.cyan(t.dependencies.join(`, `)):B.muted(`None`)}\nComplexity: ${t?.complexity===void 0?B.muted(`N/A`):
|
|
15
|
+
ID: ${t?V.cyan(String(t.id)):B.muted(`N/A`)} - ${t?V.bold(t.title):V.yellow(`No task available`)}\nPriority: ${t?.priority||B.muted(`N/A`)} Dependencies: ${t?.dependencies?.length?V.cyan(t.dependencies.join(`, `)):B.muted(`None`)}\nComplexity: ${t?.complexity===void 0?B.muted(`N/A`):ln(t.complexity)}`}function yt(e,t,n,r,i){let a=process.stdout.columns||80,o=a>=120,s=Math.floor(a/2),c=s-4,l=_t(e,t,n,(o?c:a)-8<60),u=vt(r,i);if(o){let e=G(l,{padding:1,borderColor:N,borderStyle:`round`,width:c,dimBorder:!1}),t=G(u,{padding:1,borderColor:N,borderStyle:`round`,width:c,dimBorder:!1}),n=e.split(`
|
|
16
16
|
`),r=t.split(`
|
|
17
17
|
`),i=Math.max(n.length,r.length),a=[];for(let e=0;e<i;e++){let t=e<n.length?n[e]:``,i=e<r.length?r[e]:``,o=t.padEnd(s,` `);a.push(o+i)}console.log(a.join(`
|
|
18
|
-
`))}else{let e=G(l,{padding:1,borderColor:N,borderStyle:`round`,margin:{top:0,bottom:1}}),t=G(u,{padding:1,borderColor:N,borderStyle:`round`,margin:{top:0,bottom:1}});console.log(e),console.log(t)}}function bt(e={}){let{filePath:t,tag:n}=e;if(n&&(console.log(`tag: ${V.cyan(n)}`),t)){let e=t.startsWith(`/`)?t:`${process.cwd()}/${t}`;console.log(`Listing tasks from: ${V.dim(e)}`)}}const
|
|
18
|
+
`))}else{let e=G(l,{padding:1,borderColor:N,borderStyle:`round`,margin:{top:0,bottom:1}}),t=G(u,{padding:1,borderColor:N,borderStyle:`round`,margin:{top:0,bottom:1}});console.log(e),console.log(t)}}const bt={done:{color:V.green,icon:`✓`,tableIcon:`✓`},pending:{color:V.yellow,icon:`○`,tableIcon:`○`},"in-progress":{color:B.active,icon:`▶`,tableIcon:`▶`},deferred:{color:B.muted,icon:`–`,tableIcon:`–`},review:{color:V.magenta,icon:`?`,tableIcon:`?`},cancelled:{color:B.muted,icon:`x`,tableIcon:`x`},blocked:{color:V.red,icon:`!`,tableIcon:`!`},completed:{color:V.green,icon:`✓`,tableIcon:`✓`}};function xt(e){let t=bt[e];return t?t.color(t.icon):V.red(`X`)}function St(e,t=!1){let n=bt[e]||{color:V.red,icon:`X`,tableIcon:`X`},r=t?n.tableIcon:n.icon;return n.color(`${r} ${e}`)}function Ct(e=.9,t=40){let n=process.stdout.columns||80;return Math.max(Math.floor(n*e),t)}function wt(){let e=process.stdout.columns;return e?Math.floor(e*.95):100}function Tt(e,t,n=20){let r=e=>e.reduce((e,t)=>e+(t.width===`flex`?n:t.width),0)+e.length+1,i=[...t],a=[],o=t.filter(e=>e.dropOrder!==void 0).sort((e,t)=>(e.dropOrder??0)-(t.dropOrder??0));for(let t of o){if(r(i)<=e)break;i=i.filter(e=>e!==t),a.push(t.key)}let s=i.reduce((e,t)=>e+(t.width===`flex`?0:t.width),0),c=Math.max(n,e-s-i.length-1);return{keys:i.map(e=>e.key),widths:i.map(e=>e.width===`flex`?c:e.width),hidden:a}}function Et(e,t){return e.length<=t?e:e.substring(0,t-3)+`...`}function Dt(e,t,n=30){if(t===0)return B.muted(`No tasks`);let r=Math.round(e/t*100),i=Math.round(e/t*n),a=n-i;return`${V.green(`█`).repeat(i)+B.muted(`░`).repeat(a)} ${V.cyan(`${r}%`)} (${e}/${t})`}const Ot=[[`done`,`done`],[`in-progress`,`in progress`],[`review`,`review`],[`pending`,`pending`],[`blocked`,`blocked`],[`deferred`,`deferred`],[`cancelled`,`cancelled`]],kt=e=>e.replace(/\x1b\[[0-9;]*m/g,``).length;function At(e,t={}){let n=t.width??100,r=t.nextId?String(t.nextId):null,i=r?.split(`.`)[0],a=[],o=/* @__PURE__ */ new Set,s=(e,t)=>{o.add(e.status);let a=e.id===i,s=[];e.alsoNeeds.length&&s.push(`needs ${e.alsoNeeds.join(`, `)}`);let c=e.missing.length?V.yellow(` · missing ${e.missing.join(`, `)}`):``,l=(s.length?B.muted(` · ${s.join(` · `)}`):``)+c+(a?B.brand.bold(r===i?` ← next`:` ← next: ${r}`):``),u=`${t}${xt(e.status)} ${B.brand(e.id)} `,d=Math.max(12,n-kt(u)-kt(l)),f=Et(e.title,d);return u+(a||e.status===`in-progress`?V.bold(f):e.status===`done`||e.status===`cancelled`?B.muted(f):f)+l},c=(e,t,n)=>{a.push(s(e,t+B.muted(n?`└─ `:`├─ `)));let r=t+B.muted(n?` `:`│ `);e.children.forEach((t,n)=>c(t,r,n===e.children.length-1))};if(e.roots.forEach((t,n)=>{let r=e.roots[n-1];r&&(r.children.length||t.children.length)&&a.push(``),a.push(s(t,``)),t.children.forEach((e,n)=>c(e,``,n===t.children.length-1))}),e.cyclic.length){a.push(``,V.yellow(`⚠ These tasks depend on each other in a loop:`));for(let t of e.cyclic)a.push(s(t,` `));let t=new Set(e.cyclic.map(e=>e.id)),n=e.cyclic[0],r=n.alsoNeeds.find(e=>t.has(e));r&&a.push(B.muted(` Break it with `)+B.brand(`taskgraph remove-dependency --id=${n.id} --depends-on=${r}`))}let l=Ot.filter(([e])=>o.has(e)).map(([e,t])=>`${xt(e)} ${B.muted(t)}`).join(` `);return l&&a.push(``,l),a}function jt(e={}){let{filePath:t,tag:n}=e;if(n&&(console.log(`tag: ${V.cyan(n)}`),t)){let e=t.startsWith(`/`)?t:`${process.cwd()}/${t}`;console.log(`Listing tasks from: ${V.dim(e)}`)}}const Mt=new Be({headingStyle:`atx`,codeBlockStyle:`fenced`,bulletListMarker:`-`});Re.use(ze({code:e=>e.split(`
|
|
19
19
|
`).map(e=>` `+V.cyan(e)).join(`
|
|
20
|
-
`),blockquote:B.muted.italic,html:B.muted,heading:B.text.bold,hr:B.muted,listitem:B.text,paragraph:B.text,strong:B.text.bold,em:B.text.italic,codespan:V.cyan,del:V.dim.strikethrough,link:B.brand,href:B.brand.underline,showSectionPrefix:!1,unescape:!0,emoji:!1,tab:4,width:120})),Re.setOptions({breaks:!0,gfm:!0});function
|
|
21
|
-
`).replace(/\\t/g,` `).replace(/\\"/g,`"`);/<[^>]+>/.test(t)&&(t=
|
|
22
|
-
`),u=[a,e.title,
|
|
23
|
-
`);r.push([l,u]),console.log(r.toString())}function
|
|
20
|
+
`),blockquote:B.muted.italic,html:B.muted,heading:B.text.bold,hr:B.muted,listitem:B.text,paragraph:B.text,strong:B.text.bold,em:B.text.italic,codespan:V.cyan,del:V.dim.strikethrough,link:B.brand,href:B.brand.underline,showSectionPrefix:!1,unescape:!0,emoji:!1,tab:4,width:120})),Re.setOptions({breaks:!0,gfm:!0});function Nt(e){if(!e)return``;let t=e.replace(/\\\\/g,`\\`).replace(/\\n/g,`
|
|
21
|
+
`).replace(/\\t/g,` `).replace(/\\"/g,`"`);/<[^>]+>/.test(t)&&(t=Mt.turndown(t));let n=Re(t);return typeof n==`string`?n.trim():t}function Pt(e,t,n){let r=String(e),i=r.includes(`.`),a=i?{command:`taskgraph update-subtask --id=${r} --prompt="..."`,description:`to log progress notes`}:{command:`taskgraph update-task --id=${r} --prompt="..."`,description:`to update details`},o=!i&&!n?[{command:`taskgraph expand --id=${r}`,description:`to break down into subtasks`}]:[];switch(t){case`in-progress`:return[a,{command:`taskgraph set-status --id=${r} --status=done`,description:`when it is finished`},...o];case`review`:return[{command:`taskgraph set-status --id=${r} --status=done`,description:`once the review passes`},{command:`taskgraph set-status --id=${r} --status=in-progress`,description:`if it needs more work`}];case`done`:case`completed`:case`cancelled`:return[{command:`taskgraph next`,description:`to find the next task to work on`}];case`blocked`:case`deferred`:return[{command:`taskgraph set-status --id=${r} --status=pending`,description:`when it is ready to pick up again`},a];default:return[{command:`taskgraph set-status --id=${r} --status=in-progress`,description:`to start working`},...o,a]}}function Ft(e){switch(e){case`create`:return V.green(`✚ CREATE`);case`modify`:return V.yellow(`✎ MODIFY`);case`reference`:return B.brand(`◇ REFER `);default:return B.muted(` FILE `)}}function It(e){return e}function Lt(e,t){console.log(G(V.bold(`Task: #${e} - ${t}`),{padding:{top:0,bottom:0,left:1,right:1},borderColor:N,borderStyle:`round`}))}function Rt(e,t){let n=wt(),r=new q({head:[],style:{head:[],border:le},colWidths:Tt(n,[{key:`label`,width:16},{key:`value`,width:`flex`}]).widths,wordWrap:!0}),i=e.dependencies&&e.dependencies.length>0?e.dependencies.map(e=>String(e)).join(`, `):`None`,a=t||String(e.id),o=Nt(e.description||``),s=e.category?`${It(e.category)}`:B.muted(`N/A`),c=e.skills&&e.skills.length>0?e.skills.map(e=>B.accent(`[${e}]`)).join(` `):B.muted(`N/A`),l=[V.cyan(`ID:`),V.cyan(`Title:`),V.cyan(`Status:`),V.cyan(`Priority:`),V.cyan(`Dependencies:`),V.cyan(`Complexity:`),V.cyan(`Category:`),V.cyan(`Skills:`),V.cyan(`Description:`)].join(`
|
|
22
|
+
`),u=[a,e.title,St(e.status),sn(e.priority),i,typeof e.complexity==`number`?ln(e.complexity):B.muted(`N/A`),s,c,o].join(`
|
|
23
|
+
`);r.push([l,u]),console.log(r.toString())}function zt(e){let t=wt(),n=Nt(e);console.log(G(V.bold(`Implementation Details:`)+`
|
|
24
24
|
|
|
25
|
-
`+n,{padding:1,borderStyle:`round`,borderColor:N,width:t}))}function
|
|
25
|
+
`+n,{padding:1,borderStyle:`round`,borderColor:N,width:t}))}function Bt(e){let t=wt(),n=Nt(e);console.log(G(V.bold(`Test Strategy:`)+`
|
|
26
26
|
|
|
27
|
-
`+n,{padding:1,borderStyle:`round`,borderColor:N,width:t}))}function
|
|
27
|
+
`+n,{padding:1,borderStyle:`round`,borderColor:N,width:t}))}function Vt(e,t){let n=wt();console.log(G(B.heading(`Subtasks`),{padding:{top:0,bottom:0,left:1,right:1},borderColor:N,borderStyle:`round`,margin:{top:1,bottom:0}}));let r=new q({head:[B.heading(`ID`),B.heading(`Status`),B.heading(`Title`),B.heading(`Deps`)],style:{head:[],border:le},colWidths:Tt(n,[{key:`id`,width:10},{key:`status`,width:15},{key:`title`,width:`flex`},{key:`deps`,width:8}]).widths,wordWrap:!0});e.forEach(e=>{let n=t?`${t}.${e.id}`:String(e.id),i=e.dependencies&&e.dependencies.length>0?e.dependencies.join(`, `):`None`;r.push([n,St(e.status),e.title,i])}),console.log(r.toString())}function Ht(e){let t=wt(),n=e.map(e=>`${Ft(e.action)} ${B.text(e.path)}\n ${B.muted(e.description)}`).join(`
|
|
28
28
|
|
|
29
29
|
`);console.log(G(V.bold(`Files to Touch:`)+`
|
|
30
30
|
|
|
31
|
-
`+n,{padding:1,borderStyle:`round`,borderColor:`yellow`,width:t}))}function
|
|
31
|
+
`+n,{padding:1,borderStyle:`round`,borderColor:`yellow`,width:t}))}function Ut(e){let t=wt(),n=e.map(e=>`${V.cyan.bold(e.name)} → ${B.muted(e.location)}\n ↳ ${B.text(e.usage)}`).join(`
|
|
32
32
|
|
|
33
33
|
`);console.log(G(V.bold(`Leverage Existing Code:`)+`
|
|
34
34
|
|
|
35
|
-
`+n,{padding:1,borderStyle:`round`,borderColor:N,width:t}))}function
|
|
35
|
+
`+n,{padding:1,borderStyle:`round`,borderColor:N,width:t}))}function Wt(e){let t=wt(),n=``;e.included&&(n+=V.green.bold(`✓ In Scope:
|
|
36
36
|
`),n+=B.text(` `+e.included)),e.excluded&&(n&&(n+=`
|
|
37
37
|
|
|
38
38
|
`),n+=V.red.bold(`✗ Out of Scope:
|
|
39
39
|
`),n+=B.muted(` `+e.excluded)),console.log(G(V.bold(`Scope Boundaries:`)+`
|
|
40
40
|
|
|
41
|
-
`+n,{padding:1,borderStyle:`round`,borderColor:N,width:t}))}function
|
|
41
|
+
`+n,{padding:1,borderStyle:`round`,borderColor:N,width:t}))}function Gt(e){let t=wt(),n=e.map(e=>B.text(`☐ ${e}`)).join(`
|
|
42
42
|
`);console.log(G(V.bold(`Acceptance Criteria:`)+`
|
|
43
43
|
|
|
44
|
-
`+n,{padding:1,borderStyle:`round`,borderColor:`green`,width:t}))}function
|
|
44
|
+
`+n,{padding:1,borderStyle:`round`,borderColor:`green`,width:t}))}function Kt(e){let t=wt(),n=e.map(e=>V.yellow(`▸ ${e}`)).join(`
|
|
45
45
|
`);console.log(G(V.bold(`Technical Constraints:`)+`
|
|
46
46
|
|
|
47
|
-
`+n,{padding:1,borderStyle:`round`,borderColor:`red`,width:t}))}function
|
|
47
|
+
`+n,{padding:1,borderStyle:`round`,borderColor:`red`,width:t}))}function qt(e){let t=wt(),n=Nt(e);console.log(G(V.bold(`Implementation Approach:`)+`
|
|
48
48
|
|
|
49
|
-
`+n,{padding:1,borderStyle:`round`,borderColor:N,width:t}))}function
|
|
49
|
+
`+n,{padding:1,borderStyle:`round`,borderColor:N,width:t}))}function Jt(e){let t=wt(),n=e.map(e=>B.text(`• ${e}`)).join(`
|
|
50
50
|
`);console.log(G(V.bold(`Codebase Patterns:`)+`
|
|
51
51
|
|
|
52
|
-
`+n,{padding:1,borderStyle:`round`,...ke,width:t}))}function
|
|
53
|
-
`+n)}function
|
|
52
|
+
`+n,{padding:1,borderStyle:`round`,...ke,width:t}))}function Yt(e,t){let n=``;e&&(n+=B.muted(`Category: `)+V.cyan(`[${It(e)}]`)),t&&t.length>0&&(n&&(n+=` `),n+=B.muted(`Skills: `)+t.map(e=>B.accent(`[${e}]`)).join(` `)),n&&console.log(`
|
|
53
|
+
`+n)}function Xt(e){(e.relevantFiles||e.existingInfrastructure||e.scopeBoundaries||e.acceptanceCriteria||e.technicalConstraints||e.implementationApproach||e.codebasePatterns)&&(e.implementationApproach&&(console.log(),qt(e.implementationApproach)),e.relevantFiles&&e.relevantFiles.length>0&&(console.log(),Ht(e.relevantFiles)),e.existingInfrastructure&&e.existingInfrastructure.length>0&&(console.log(),Ut(e.existingInfrastructure)),e.codebasePatterns&&e.codebasePatterns.length>0&&(console.log(),Jt(e.codebasePatterns)),e.scopeBoundaries&&(console.log(),Wt(e.scopeBoundaries)),e.technicalConstraints&&e.technicalConstraints.length>0&&(console.log(),Kt(e.technicalConstraints)),e.acceptanceCriteria&&e.acceptanceCriteria.length>0&&(console.log(),Gt(e.acceptanceCriteria)))}function Zt(e,t,n=!1){let r=Pt(e,t,n).map((e,t)=>`${V.cyan(`${t+1}.`)} Run ${V.yellow(e.command)} ${e.description}`);console.log(G(V.bold(`Suggested Actions:`)+`
|
|
54
54
|
|
|
55
55
|
`+r.join(`
|
|
56
|
-
`),{padding:1,margin:{top:1},borderStyle:`round`,borderColor:`green`,width:wt()}))}function
|
|
57
|
-
`),{padding:1,margin:{top:1,bottom:1},borderStyle:`round`,borderColor:N,title:B.heading(`Next task`),titleAlignment:`center`,width:Ct(.97),fullscreen:!1}))}function
|
|
58
|
-
`)[0].split(`.`)[0]}function
|
|
56
|
+
`),{padding:1,margin:{top:1},borderStyle:`round`,borderColor:`green`,width:wt()}))}function Qt(e,t){let{statusFilter:n,showSuggestedActions:r=!1,customHeader:i,headerColor:a=N,originalTaskId:o}=t||{};if(i?console.log(G(V.bold(i),{padding:{top:0,bottom:0,left:1,right:1},borderColor:a,borderStyle:`round`,margin:{top:1}})):Lt(o||e.id,e.title),Rt(e,o),e.details&&(console.log(),zt(e.details)),`testStrategy`in e&&e.testStrategy&&(console.log(),Bt(e.testStrategy)),Xt(e),e.subtasks&&e.subtasks.length>0){let t=n?e.subtasks.filter(e=>e.status===n):e.subtasks;t.length===0&&n?(console.log(),console.log(B.muted(` No subtasks with status '${n}'`))):t.length>0&&(console.log(),Vt(t,e.id))}r&&(console.log(),Zt(o||e.id,e.status,!!(e.subtasks&&e.subtasks.length>0)))}function $t(e,t){if(!e){console.log(t?V.yellow(`✓ All tasks are either completed, blocked by dependencies, or in progress.`):G(V.yellow(`No tasks found in this project.`),{padding:1,borderStyle:`round`,borderColor:`yellow`,title:`No tasks available`,titleAlignment:`center`}));return}let n=[];n.push(`${B.heading(`Next task:`)} ${V.yellow(`#${e.id}`)}${B.heading(` - ${e.title}`)}`),n.push(``);let r=[];if(e.priority){let t=e.priority===`high`?V.red:e.priority===`medium`?V.yellow:B.muted;r.push(`Priority: ${t.bold(e.priority)}`)}if(e.status){let t=e.status===`pending`?V.yellow(`○ pending`):e.status===`in-progress`?B.brand(`▶ in-progress`):B.muted(e.status);r.push(`Status: ${t}`)}n.push(r.join(` `));let i=!e.dependencies||e.dependencies.length===0?B.muted(`None`):V.cyan(e.dependencies.join(`, `));n.push(`Dependencies: ${i}`),typeof e.complexity==`number`&&n.push(`Complexity: ${ln(e.complexity)}`),e.description&&(n.push(``),n.push(`Description: ${B.text(Nt(e.description))}`)),n.push(``);for(let t of Pt(e.id,e.status,!0).slice(0,2))n.push(`${V.cyan(`Next step:`)} ${V.yellow(t.command)} ${B.muted(t.description)}`);n.push(`${V.cyan(`View details:`)} ${V.yellow(`taskgraph show ${e.id}`)}`),console.log(G(n.join(`
|
|
57
|
+
`),{padding:1,margin:{top:1,bottom:1},borderStyle:`round`,borderColor:N,title:B.heading(`Next task`),titleAlignment:`center`,width:Ct(.97),fullscreen:!1}))}function en(e){if(`description`in e&&e.description)return e.description;if(`details`in e&&e.details)return e.details.split(`
|
|
58
|
+
`)[0].split(`.`)[0]}function tn(){let e=[`${V.cyan(`1.`)} Run ${V.yellow(`taskgraph next`)} to see what to work on next`,`${V.cyan(`2.`)} Run ${V.yellow(`taskgraph expand --id=<id>`)} to break down a task into subtasks`,`${V.cyan(`3.`)} Run ${V.yellow(`taskgraph set-status --id=<id> --status=done`)} to mark a task as complete`];console.log(G(V.bold(`Suggested Next Steps:`)+`
|
|
59
59
|
|
|
60
60
|
`+e.join(`
|
|
61
|
-
`),{padding:1,margin:{top:0,bottom:1},borderStyle:`round`,...ke,width:Ct(.97)}))}const
|
|
61
|
+
`),{padding:1,margin:{top:0,bottom:1},borderStyle:`round`,...ke,width:Ct(.97)}))}const nn=`tasks.json`;function rn(e){let t=h(e);console.log(V.dim(`\nWatching ${nn} for changes...`)),console.log(B.muted(`Last synced: ${t}`)),console.log(V.dim(`Press Ctrl+C to exit`))}function an(e){let t=h(e);console.log(B.brand(`\nℹ ${nn} updated at ${t}`))}const on={critical:V.red.bold,high:V.red,medium:V.yellow,low:B.muted};function sn(e){return(on[e]||B.text)(e)}function cn(e){return e>=7?{color:V.red,label:`High`}:e>=4?{color:V.yellow,label:`Medium`}:{color:V.green,label:`Low`}}function ln(e){let t=typeof e==`string`?Number(e.trim()):e;if(isNaN(t))return B.muted(`N/A`);let{color:n}=cn(t);return n(`● ${t}`)}function un(e){if(typeof e!=`number`)return B.muted(`N/A`);let{color:t,label:n}=cn(e);return t(`${e}/10 (${n})`)}function dn(e,t){if(!e||e.length===0)return B.muted(`none`);let n=new Map(t.map(e=>[e.id.toString(),e]));return e.map(e=>{let t=n.get(e.toString());return t?`${e}${t.status===`done`?`✓`:t.status===`in-progress`?`►`:`○`}`:V.red(`${e} (not found)`)}).join(`, `)}const fn=[`⠋`,`⠙`,`⠹`,`⠸`,`⠼`,`⠴`,`⠦`,`⠧`,`⠇`,`⠏`];function pn(e=V.hex(De.accent)){return{interval:80,frames:fn.map(t=>e(t))}}function mn(e={}){let t=Ve({...typeof e==`string`?{text:e}:e,spinner:pn(),color:!1}),n=e=>n=>t.stopAndPersist({symbol:e,text:n});return t.succeed=n(V.green(`✓`)),t.fail=n(V.red(`✗`)),t.warn=n(V.yellow(`⚠`)),t}function hn(e=`TaskGraph`){console.log(G(V.bold(e),{padding:1,margin:{top:1,bottom:1},borderStyle:`round`,borderColor:N,textAlignment:`center`}))}function gn(e,t){let n=Ct();console.error(G(V.red.bold(`X Error: `)+B.text(e)+(t?`
|
|
62
62
|
|
|
63
|
-
`+B.muted(t):``),{padding:1,borderStyle:`round`,borderColor:`red`,width:n}))}const
|
|
64
|
-
`+B.muted(`Hidden to fit width: ${l.hidden.map(e=>
|
|
65
|
-
Stack trace:`)),console.error(B.muted(e.stack)))}else{let n=e?.message??String(e);console.error(V.red(`\nError: ${n}`)),(
|
|
66
|
-
Stack trace:`)),console.error(B.muted(e.stack)))}t.skipExit||process.exit(1)}function Cn(e){return e?je(e):c()}var wn=class e extends K{tmCore;lastResult;constructor(e){super(e||`list`),this.description(`List tasks with optional filtering`).alias(`ls`).argument(`[status]`,`Filter by status (e.g., pending, done, in-progress) or "all" to show with subtasks`).option(`-s, --status <status>`,`Filter by status (fallback if not using positional)`).option(`-t, --tag <tag>`,`Filter by tag`).option(`--with-subtasks`,`Include subtasks in the output`).option(`-f, --format <format>`,`Output format (text, json, compact)`,`text`).option(`--json`,`Output in JSON format (shorthand for --format json)`).option(`-c, --compact`,`Output in compact format (shorthand for --format compact)`).option(`--no-header`,`Hide the command header`).option(`--silent`,`Suppress output (useful for programmatic usage)`).option(`-p, --project <path>`,`Project root directory (auto-detected if not provided)`).option(`-w, --watch`,`Watch for changes and update list automatically`).option(`--ready`,`Show only tasks ready to work on (dependencies satisfied)`).option(`--blocking`,`Show only tasks that block other tasks`).option(`--all-tags`,`Show tasks from all tags (combine with --ready for actionable tasks)`).action(async(e,t)=>{let n=e||t?.status,r=t?.withSubtasks||!1;e===`all`&&(n=void 0,r=!0);let i={...t,status:n,withSubtasks:r};await this.executeCommand(i)})}async executeCommand(e){try{if(this.validateOptions(e)||process.exit(1),await this.initializeCore(Cn(e.project)),e.watch)await this.watchTasks(e);else{let t=e.allTags?await this.getTasksFromAllTags(e):await this.getTasks(e);this.setLastResult(t),e.silent||this.displayResults(t,e)}}catch(e){Y(e)}}async watchTasks(e){if(!this.tmCore)throw Error(`TmCore not initialized`);let t=await this.getTasks(e),n=/* @__PURE__ */ new Date;console.clear(),this.displayResults(t,e),Zt(n);let r;try{r=await this.tmCore.tasks.watch(async r=>{if(r.type===`change`)try{t=await this.getTasks(e),n=/* @__PURE__ */ new Date,console.clear(),this.displayResults(t,e),Qt(n),Zt(n)}catch(e){let t=e instanceof Error?e.message:String(e);console.error(V.yellow(`\nWarning: Failed to refresh tasks: ${t}`))}else r.type===`error`&&r.error&&console.error(V.red(`\n⚠ Watch error: ${r.error.message}`))},{tag:e.tag});let i=()=>{r?.unsubscribe(),process.exit(0)};process.on(`SIGINT`,i),process.on(`SIGTERM`,i),await new Promise(()=>{})}catch(e){throw console.error(V.red(`Watch mode error: ${e.message}`)),e}}validateOptions(e){if(e.format&&!l.includes(e.format))return console.error(V.red(`Invalid format: ${e.format}`)),console.error(B.muted(`Valid formats: ${l.join(`, `)}`)),!1;if(e.status){let t=e.status.split(`,`).map(e=>e.trim());for(let e of t)if(e!==`all`&&!g.includes(e))return console.error(V.red(`Invalid status: ${e}`)),console.error(B.muted(`Valid statuses: ${g.join(`, `)}`)),!1}return e.allTags&&e.watch?(console.error(V.red(`--all-tags cannot be used with --watch mode`)),console.error(B.muted(`Use --all-tags without --watch, or --watch without --all-tags`)),!1):!0}async initializeCore(e){this.tmCore||=await b({projectPath:e})}async getTasks(e){if(!this.tmCore)throw Error(`TmCore not initialized`);let t=e.status&&e.status!==`all`?e.status.split(`,`).map(e=>e.trim()):void 0,n=e.ready||e.blocking,r=t&&!n?{status:t}:void 0,i=await this.tmCore.tasks.list({tag:e.tag,filter:r,includeSubtasks:e.withSubtasks}),{blocksMap:a,invalidDependencies:o}=y(i.tasks);this.displayInvalidDependencyWarnings(o);let s=i.tasks.map(e=>({...e,blocks:a.get(String(e.id))||[]}));return e.ready&&(s=_(s)),e.blocking&&(s=m(s)),t&&n&&(s=s.filter(e=>t.includes(e.status))),{...i,tasks:s,filtered:s.length}}async getTasksFromAllTags(e){if(!this.tmCore)throw Error(`TmCore not initialized`);let t=await this.tmCore.tasks.getTagsWithStats(),n=[],r=0,i=[];for(let a of t.tags){let t=a.name;try{let i=await this.tmCore.tasks.list({tag:t,includeSubtasks:e.withSubtasks});r+=i.tasks.length;let{blocksMap:a,invalidDependencies:o}=y(i.tasks);this.displayInvalidDependencyWarnings(o,t);let s=i.tasks.map(e=>({...e,blocks:a.get(String(e.id))||[],tagName:t})),c=e.ready?_(s):s;n.push(...c)}catch(e){let n=e instanceof Error?e.message:String(e);i.push({name:t,error:n});continue}}if(i.length>0&&(console.warn(V.yellow(`\nWarning: Could not fetch tasks from ${i.length} tag(s):`)),i.forEach(({name:e,error:t})=>{console.warn(B.muted(` ${e}: ${t}`))})),i.length===t.tags.length&&t.tags.length>0)throw Error(`Failed to fetch tasks from any tag. First error: ${i[0].error}`);let a=n;if(e.blocking&&(a=a.filter(e=>e.blocks.length>0)),e.status&&e.status!==`all`){let t=e.status.split(`,`).map(e=>e.trim());a=a.filter(e=>t.includes(e.status))}return{tasks:a,total:r,filtered:a.length,allTags:!0}}displayInvalidDependencyWarnings(e,t){if(e.length===0)return;let n=t?` (tag: ${t})`:``;console.warn(V.yellow(`\nWarning: ${e.length} invalid dependency reference(s) found${n}:`)),e.slice(0,5).forEach(({taskId:e,depId:t})=>{console.warn(B.muted(` Task ${e} depends on non-existent task ${t}`))}),e.length>5&&console.warn(B.muted(` ...and ${e.length-5} more`))}displayResults(e,t){let n=t.format||`text`;switch(t.json?n=`json`:t.compact&&(n=`compact`),n){case`json`:this.displayJson(e);break;case`compact`:this.displayCompact(e,t);break;default:this.displayText(e,t)}}displayJson(e){console.log(JSON.stringify({tasks:e.tasks,metadata:{total:e.total,filtered:e.filtered,tag:e.allTags?`all`:e.tag,allTags:e.allTags||!1}},null,2))}displayCompact(e,t){let{tasks:n,tag:r,allTags:i}=e;t.noHeader!==!0&&xn({tag:i?`all tags`:r||`master`});for(let e of n){let n=u[e.status],r=i&&`tagName`in e?B.accent(`[${e.tagName}] `):``;if(console.log(`${r}${V.cyan(e.id)} ${n} ${e.title}`),t.withSubtasks&&e.subtasks?.length)for(let t of e.subtasks){let e=u[t.status];console.log(` ${B.muted(String(t.id))} ${e} ${B.muted(t.title)}`)}}}displayText(e,t){let{tasks:n,tag:r,allTags:i}=e;if(t.noHeader!==!0&&xn({tag:i?`all tags`:r||`master`}),n.length===0){hn(`No tasks found matching the criteria.`);return}let a=dt(n),o=ft(n),s=pt(n),c=mt(n),l=this.findNextTask(n),u=l?n.find(e=>String(e.id)===String(l.id)):void 0,d=t.ready||t.blocking||i;if(d||yt(a,o,c,s,u),console.log(vn(n,{showSubtasks:t.withSubtasks,showDependencies:!0,showBlocks:!0,showComplexity:!0,showTag:i})),!d){if(u){let e=Jt(u);qt({id:u.id,title:u.title,priority:u.priority,status:u.status,dependencies:u.dependencies,description:e,complexity:u.complexity})}Yt()}}setLastResult(e){this.lastResult=e}findNextTask(e){let t={critical:4,high:3,medium:2,low:1},n=/* @__PURE__ */ new Set;e.forEach(e=>{p(e.status)&&n.add(String(e.id)),e.subtasks&&e.subtasks.forEach(t=>{p(t.status)&&n.add(`${e.id}.${t.id}`)})});let r=[];if(e.filter(e=>e.status===`in-progress`&&e.subtasks&&e.subtasks.length>0).forEach(e=>{e.subtasks.forEach(t=>{let i=(t.status||`pending`).toLowerCase();if(i!==`pending`&&i!==`in-progress`)return;let a=t.dependencies?.map(t=>typeof t==`string`&&t.includes(`.`)?t:`${e.id}.${t}`)??[];(a.length===0||a.every(e=>n.has(String(e))))&&r.push({id:`${e.id}.${t.id}`,title:t.title||`Subtask ${t.id}`,priority:t.priority||e.priority||`medium`,dependencies:a.map(e=>String(e))})})}),r.length>0)return r.sort((e,n)=>{let r=t[e.priority||`medium`]??2,i=t[n.priority||`medium`]??2;if(i!==r)return i-r;let a=e.dependencies?.length||0,o=n.dependencies?.length||0;return a===o?String(e.id).localeCompare(String(n.id)):a-o}),r[0];let i=e.filter(e=>{let t=(e.status||`pending`).toLowerCase();if(t!==`pending`&&t!==`in-progress`)return!1;let r=e.dependencies||[];return r.length===0||r.every(e=>n.has(String(e)))});if(i.length===0)return;i.sort((e,n)=>{let r=t[e.priority||`medium`]??2,i=t[n.priority||`medium`]??2;if(i!==r)return i-r;let a=e.dependencies?.length||0,o=n.dependencies?.length||0;return a===o?Number(e.id)-Number(n.id):a-o});let a=i[0];return{id:a.id,title:a.title,priority:a.priority,dependencies:a.dependencies?.map(e=>String(e))}}getLastResult(){return this.lastResult}async cleanup(){this.tmCore&&=void 0}static register(t,n){let r=new e(n);return t.addCommand(r),r}},Tn=class e extends K{tmCore;lastResult;constructor(e){super(e||`show`),this.description(`Display detailed information about one or more tasks`).argument(`[id]`,`Task ID(s) to show (comma-separated for multiple)`).option(`-i, --id <id>`,`Task ID(s) to show (comma-separated for multiple)`).option(`-s, --status <status>`,`Filter subtasks by status`).option(`-f, --format <format>`,`Output format (text, json)`,`text`).option(`--json`,`Output in JSON format (shorthand for --format json)`).option(`--silent`,`Suppress output (useful for programmatic usage)`).option(`-p, --project <path>`,`Project root directory (auto-detected if not provided)`).action(async(e,t)=>{await this.executeCommand(e,t)})}async executeCommand(e,t){try{this.validateOptions(t)||process.exit(1),await this.initializeCore(Cn(t.project));let n=e||t.id;n||(console.error(V.red(`Error: Please provide a task ID`)),process.exit(1));let r=n.split(`,`).map(e=>e.trim()).filter(e=>e.length>0),i=[];for(let e of r){let t=s.safeParse(e);t.success||(console.error(V.red(`Invalid task ID: ${e}`),B.muted(`- ${t.error.issues[0]?.message}`)),process.exit(1)),i.push(t.data)}let a=i.length>1?await this.getMultipleTasks(i,t):await this.getSingleTask(i[0],t);this.setLastResult(a),t.silent||this.displayResults(a,t)}catch(e){Y(e)}}validateOptions(e){return e.format&&![`text`,`json`].includes(e.format)?(console.error(V.red(`Invalid format: ${e.format}`)),console.error(B.muted(`Valid formats: text, json`)),!1):!0}async initializeCore(e){this.tmCore||=await b({projectPath:e})}async getSingleTask(e,t){if(!this.tmCore)throw Error(`TmCore not initialized`);let n=await this.tmCore.tasks.get(e);return{task:n.task,found:n.task!==null,originalTaskId:n.isSubtask?e:void 0}}async getMultipleTasks(e,t){if(!this.tmCore)throw Error(`TmCore not initialized`);let n=[],r=[];for(let t of e){let e=await this.tmCore.tasks.get(t);e.task?n.push(e.task):r.push(t)}return{tasks:n,notFound:r}}displayResults(e,t){switch(t.json?`json`:t.format||`text`){case`json`:this.displayJson(e);break;default:`task`in e?this.displaySingleTask(e,t):this.displayMultipleTasks(e,t)}}displayJson(e){console.log(JSON.stringify(e,null,2))}displaySingleTask(e,t){!e.found||!e.task?console.log(G(V.yellow(`Task not found!`),{padding:{top:0,bottom:0,left:1,right:1},borderColor:`yellow`,borderStyle:`round`,margin:{top:1}})):(xn({tag:this.tmCore?.config.getActiveTag()||`master`}),console.log(),Kt(e.task,{statusFilter:t.status,showSuggestedActions:!0,originalTaskId:e.originalTaskId}))}displayMultipleTasks(e,t){xn({tag:this.tmCore?.config.getActiveTag()||`master`}),e.notFound.length>0&&console.log(V.yellow(`\n⚠ Not found: ${e.notFound.join(`, `)}`)),e.tasks.length===0?hn(`No tasks found matching the criteria.`):(console.log(B.brand.bold(`
|
|
63
|
+
`+B.muted(t):``),{padding:1,borderStyle:`round`,borderColor:`red`,width:n}))}const _n=gn;function vn(e){let t=Ct();console.log(G(V.green.bold(`√ `)+B.text(e),{padding:1,borderStyle:`round`,borderColor:`green`,width:t}))}function yn(e){let t=Ct();console.log(G(V.yellow.bold(`⚠ `)+B.text(e),{padding:1,borderStyle:`round`,borderColor:`yellow`,width:t}))}function bn(e){let t=Ct();console.log(G(B.brand.bold(`i `)+B.text(e),{padding:1,borderStyle:`round`,borderColor:N,width:t}))}const xn=[{key:`tag`,header:`Tag`,width:12},{key:`id`,header:`ID`,width:10},{key:`title`,header:`Title`,width:`flex`},{key:`status`,header:`Status`,width:15},{key:`priority`,header:`Priority`,width:10},{key:`dependencies`,header:`Dependencies`,width:14,dropOrder:3},{key:`blocks`,header:`Blocks`,width:10,dropOrder:0},{key:`complexity`,header:`Complexity`,width:12,dropOrder:1}];function Sn(e,t){let{showSubtasks:n=!1,showComplexity:r=!1,showDependencies:i=!0,showBlocks:a=!1,showTag:o=!1}=t||{},s={tag:o,dependencies:i,blocks:a,complexity:r},c=xn.filter(e=>s[e.key]??!0),l=Tt(wt(),c),u=e=>l.widths[l.keys.indexOf(e)],d=new q({head:l.keys.map(e=>B.brand.bold(xn.find(t=>t.key===e)?.header??e)),style:{head:[],border:[]},colWidths:l.widths,wordWrap:!0}),f=e=>l.keys.map(t=>e[t]??``);e.forEach(e=>{let t=e.blocks?.join(`, `)??``;d.push(f({tag:B.accent(e.tagName||`-`),id:V.cyan(e.id.toString()),title:Et(e.title,u(`title`)-3),status:St(e.status,!0),priority:sn(e.priority),dependencies:!e.dependencies||e.dependencies.length===0?B.muted(`-`):V.cyan(e.dependencies.map(e=>String(e)).join(`, `)),blocks:t?p(e.status)?B.muted(t):V.yellow(t):B.muted(`-`),complexity:typeof e.complexity==`number`?ln(e.complexity):B.muted(`N/A`)})),n&&e.subtasks&&e.subtasks.length>0&&e.subtasks.forEach(e=>{d.push(f({tag:B.muted(`-`),id:B.muted(` └─ ${e.id}`),title:B.muted(Et(e.title,u(`title`)-6)),status:B.muted(St(e.status,!0)),priority:B.muted(e.priority||`medium`),dependencies:B.muted(e.dependencies&&e.dependencies.length>0?e.dependencies.map(e=>String(e)).join(`, `):`-`),blocks:B.muted(`-`),complexity:B.muted(typeof e.complexity==`number`?ln(e.complexity):`--`)}))})});let m=l.hidden.length>0?`
|
|
64
|
+
`+B.muted(`Hidden to fit width: ${l.hidden.map(e=>xn.find(t=>t.key===e)?.header).join(`, `)}`):``;return d.toString()+m}var Cn=/* @__PURE__ */ r({BANNER_GRADIENT:()=>he,BORDER_COLOR:()=>N,BRAND_COLORS:()=>De,MUTED_BOX_BORDER:()=>ke,TABLE_BORDER:()=>le,brandSpinner:()=>pn,calculateDependencyStatistics:()=>pt,calculateSubtaskStatistics:()=>ft,calculateTaskStatistics:()=>dt,createLink:()=>et,createProgressBar:()=>Dt,createSpinner:()=>mn,createTaskLink:()=>nt,createTaskTable:()=>Sn,createUrlLink:()=>tt,displayAcceptanceCriteria:()=>Gt,displayAsciiBanner:()=>st,displayBanner:()=>hn,displayCardBox:()=>lt,displayCodebasePatterns:()=>Jt,displayDashboards:()=>yt,displayDependencyDashboard:()=>vt,displayError:()=>_n,displayErrorBox:()=>gn,displayExistingInfrastructure:()=>Ut,displayHeader:()=>jt,displayImplementationApproach:()=>qt,displayImplementationDetails:()=>zt,displayImplementationMetadata:()=>Xt,displayInfo:()=>bn,displayInitBanner:()=>ct,displayProjectDashboard:()=>_t,displayRecommendedNextTask:()=>$t,displayRelevantFiles:()=>Ht,displayScopeBoundaries:()=>Wt,displaySkillsAndCategory:()=>Yt,displaySubtasks:()=>Vt,displaySuccess:()=>vn,displaySuggestedActions:()=>Zt,displaySuggestedNextSteps:()=>tn,displaySyncMessage:()=>an,displayTaskDetails:()=>Qt,displayTaskHeader:()=>Lt,displayTaskProperties:()=>Rt,displayTechnicalConstraints:()=>Kt,displayTestStrategy:()=>Bt,displayWarning:()=>yn,displayWatchFooter:()=>rn,formatDependenciesWithStatus:()=>dn,formatStatusLine:()=>gt,getBoxWidth:()=>Ct,getComplexityWithColor:()=>ln,getComplexityWithScore:()=>un,getPriorityBreakdown:()=>mt,getPriorityWithColor:()=>sn,getStatusWithColor:()=>St,getSuggestedActions:()=>Pt,getTaskDescription:()=>en,renderDependencyTree:()=>At,supportsLinks:()=>rt,theme:()=>B,truncate:()=>Et});const wn=Ae.join(`.taskgraph`,`tasks`,`tasks.json`);function Tn(e){jt({tag:e.tag||`master`,filePath:wn})}function En(){return process.env.DEBUG===`true`||process.env.DEBUG===`1`}function Y(e,t={}){if(e?.getSanitizedDetails){let n=e.getSanitizedDetails();console.error(V.red(`\n${n.message}`)),(En()||t.forceStack)&&e.stack&&(console.error(B.muted(`
|
|
65
|
+
Stack trace:`)),console.error(B.muted(e.stack)))}else{let n=e?.message??String(e);console.error(V.red(`\nError: ${n}`)),(En()||t.forceStack)&&e?.stack&&(console.error(B.muted(`
|
|
66
|
+
Stack trace:`)),console.error(B.muted(e.stack)))}t.skipExit||process.exit(1)}function X(e){return e?je(e):c()}var Dn=class e extends K{tmCore;lastResult;constructor(e){super(e||`list`),this.description(`List tasks with optional filtering`).alias(`ls`).argument(`[status]`,`Filter by status (e.g., pending, done, in-progress) or "all" to show with subtasks`).option(`-s, --status <status>`,`Filter by status (fallback if not using positional)`).option(`-t, --tag <tag>`,`Filter by tag`).option(`--with-subtasks`,`Include subtasks in the output`).option(`-f, --format <format>`,`Output format (text, json, compact)`,`text`).option(`--json`,`Output in JSON format (shorthand for --format json)`).option(`-c, --compact`,`Output in compact format (shorthand for --format compact)`).option(`--no-header`,`Hide the command header`).option(`--silent`,`Suppress output (useful for programmatic usage)`).option(`-p, --project <path>`,`Project root directory (auto-detected if not provided)`).option(`-w, --watch`,`Watch for changes and update list automatically`).option(`--ready`,`Show only tasks ready to work on (dependencies satisfied)`).option(`--blocking`,`Show only tasks that block other tasks`).option(`--all-tags`,`Show tasks from all tags (combine with --ready for actionable tasks)`).action(async(e,t)=>{let n=e||t?.status,r=t?.withSubtasks||!1;e===`all`&&(n=void 0,r=!0);let i={...t,status:n,withSubtasks:r};await this.executeCommand(i)})}async executeCommand(e){try{if(this.validateOptions(e)||process.exit(1),await this.initializeCore(X(e.project)),e.watch)await this.watchTasks(e);else{let t=e.allTags?await this.getTasksFromAllTags(e):await this.getTasks(e);this.setLastResult(t),e.silent||this.displayResults(t,e)}}catch(e){Y(e)}}async watchTasks(e){if(!this.tmCore)throw Error(`TmCore not initialized`);let t=await this.getTasks(e),n=/* @__PURE__ */ new Date;console.clear(),this.displayResults(t,e),rn(n);let r;try{r=await this.tmCore.tasks.watch(async r=>{if(r.type===`change`)try{t=await this.getTasks(e),n=/* @__PURE__ */ new Date,console.clear(),this.displayResults(t,e),an(n),rn(n)}catch(e){let t=e instanceof Error?e.message:String(e);console.error(V.yellow(`\nWarning: Failed to refresh tasks: ${t}`))}else r.type===`error`&&r.error&&console.error(V.red(`\n⚠ Watch error: ${r.error.message}`))},{tag:e.tag});let i=()=>{r?.unsubscribe(),process.exit(0)};process.on(`SIGINT`,i),process.on(`SIGTERM`,i),await new Promise(()=>{})}catch(e){throw console.error(V.red(`Watch mode error: ${e.message}`)),e}}validateOptions(e){if(e.format&&!l.includes(e.format))return console.error(V.red(`Invalid format: ${e.format}`)),console.error(B.muted(`Valid formats: ${l.join(`, `)}`)),!1;if(e.status){let t=e.status.split(`,`).map(e=>e.trim());for(let e of t)if(e!==`all`&&!g.includes(e))return console.error(V.red(`Invalid status: ${e}`)),console.error(B.muted(`Valid statuses: ${g.join(`, `)}`)),!1}return e.allTags&&e.watch?(console.error(V.red(`--all-tags cannot be used with --watch mode`)),console.error(B.muted(`Use --all-tags without --watch, or --watch without --all-tags`)),!1):!0}async initializeCore(e){this.tmCore||=await b({projectPath:e})}async getTasks(e){if(!this.tmCore)throw Error(`TmCore not initialized`);let t=e.status&&e.status!==`all`?e.status.split(`,`).map(e=>e.trim()):void 0,n=e.ready||e.blocking,r=t&&!n?{status:t}:void 0,i=await this.tmCore.tasks.list({tag:e.tag,filter:r,includeSubtasks:e.withSubtasks}),{blocksMap:a,invalidDependencies:o}=y(i.tasks);this.displayInvalidDependencyWarnings(o);let s=i.tasks.map(e=>({...e,blocks:a.get(String(e.id))||[]}));return e.ready&&(s=_(s)),e.blocking&&(s=m(s)),t&&n&&(s=s.filter(e=>t.includes(e.status))),{...i,tasks:s,filtered:s.length}}async getTasksFromAllTags(e){if(!this.tmCore)throw Error(`TmCore not initialized`);let t=await this.tmCore.tasks.getTagsWithStats(),n=[],r=0,i=[];for(let a of t.tags){let t=a.name;try{let i=await this.tmCore.tasks.list({tag:t,includeSubtasks:e.withSubtasks});r+=i.tasks.length;let{blocksMap:a,invalidDependencies:o}=y(i.tasks);this.displayInvalidDependencyWarnings(o,t);let s=i.tasks.map(e=>({...e,blocks:a.get(String(e.id))||[],tagName:t})),c=e.ready?_(s):s;n.push(...c)}catch(e){let n=e instanceof Error?e.message:String(e);i.push({name:t,error:n});continue}}if(i.length>0&&(console.warn(V.yellow(`\nWarning: Could not fetch tasks from ${i.length} tag(s):`)),i.forEach(({name:e,error:t})=>{console.warn(B.muted(` ${e}: ${t}`))})),i.length===t.tags.length&&t.tags.length>0)throw Error(`Failed to fetch tasks from any tag. First error: ${i[0].error}`);let a=n;if(e.blocking&&(a=a.filter(e=>e.blocks.length>0)),e.status&&e.status!==`all`){let t=e.status.split(`,`).map(e=>e.trim());a=a.filter(e=>t.includes(e.status))}return{tasks:a,total:r,filtered:a.length,allTags:!0}}displayInvalidDependencyWarnings(e,t){if(e.length===0)return;let n=t?` (tag: ${t})`:``;console.warn(V.yellow(`\nWarning: ${e.length} invalid dependency reference(s) found${n}:`)),e.slice(0,5).forEach(({taskId:e,depId:t})=>{console.warn(B.muted(` Task ${e} depends on non-existent task ${t}`))}),e.length>5&&console.warn(B.muted(` ...and ${e.length-5} more`))}displayResults(e,t){let n=t.format||`text`;switch(t.json?n=`json`:t.compact&&(n=`compact`),n){case`json`:this.displayJson(e);break;case`compact`:this.displayCompact(e,t);break;default:this.displayText(e,t)}}displayJson(e){console.log(JSON.stringify({tasks:e.tasks,metadata:{total:e.total,filtered:e.filtered,tag:e.allTags?`all`:e.tag,allTags:e.allTags||!1}},null,2))}displayCompact(e,t){let{tasks:n,tag:r,allTags:i}=e;t.noHeader!==!0&&Tn({tag:i?`all tags`:r||`master`});for(let e of n){let n=u[e.status],r=i&&`tagName`in e?B.accent(`[${e.tagName}] `):``;if(console.log(`${r}${V.cyan(e.id)} ${n} ${e.title}`),t.withSubtasks&&e.subtasks?.length)for(let t of e.subtasks){let e=u[t.status];console.log(` ${B.muted(String(t.id))} ${e} ${B.muted(t.title)}`)}}}displayText(e,t){let{tasks:n,tag:r,allTags:i}=e;if(t.noHeader!==!0&&Tn({tag:i?`all tags`:r||`master`}),n.length===0){yn(`No tasks found matching the criteria.`);return}let a=dt(n),o=ft(n),s=pt(n),c=mt(n),l=this.findNextTask(n),u=l?n.find(e=>String(e.id)===String(l.id)):void 0,d=t.ready||t.blocking||i;if(d||yt(a,o,c,s,u),console.log(Sn(n,{showSubtasks:t.withSubtasks,showDependencies:!0,showBlocks:!0,showComplexity:!0,showTag:i})),!d){if(u){let e=en(u);$t({id:u.id,title:u.title,priority:u.priority,status:u.status,dependencies:u.dependencies,description:e,complexity:u.complexity})}tn()}}setLastResult(e){this.lastResult=e}findNextTask(e){let t={critical:4,high:3,medium:2,low:1},n=/* @__PURE__ */ new Set;e.forEach(e=>{p(e.status)&&n.add(String(e.id)),e.subtasks&&e.subtasks.forEach(t=>{p(t.status)&&n.add(`${e.id}.${t.id}`)})});let r=[];if(e.filter(e=>e.status===`in-progress`&&e.subtasks&&e.subtasks.length>0).forEach(e=>{e.subtasks.forEach(t=>{let i=(t.status||`pending`).toLowerCase();if(i!==`pending`&&i!==`in-progress`)return;let a=t.dependencies?.map(t=>typeof t==`string`&&t.includes(`.`)?t:`${e.id}.${t}`)??[];(a.length===0||a.every(e=>n.has(String(e))))&&r.push({id:`${e.id}.${t.id}`,title:t.title||`Subtask ${t.id}`,priority:t.priority||e.priority||`medium`,dependencies:a.map(e=>String(e))})})}),r.length>0)return r.sort((e,n)=>{let r=t[e.priority||`medium`]??2,i=t[n.priority||`medium`]??2;if(i!==r)return i-r;let a=e.dependencies?.length||0,o=n.dependencies?.length||0;return a===o?String(e.id).localeCompare(String(n.id)):a-o}),r[0];let i=e.filter(e=>{let t=(e.status||`pending`).toLowerCase();if(t!==`pending`&&t!==`in-progress`)return!1;let r=e.dependencies||[];return r.length===0||r.every(e=>n.has(String(e)))});if(i.length===0)return;i.sort((e,n)=>{let r=t[e.priority||`medium`]??2,i=t[n.priority||`medium`]??2;if(i!==r)return i-r;let a=e.dependencies?.length||0,o=n.dependencies?.length||0;return a===o?Number(e.id)-Number(n.id):a-o});let a=i[0];return{id:a.id,title:a.title,priority:a.priority,dependencies:a.dependencies?.map(e=>String(e))}}getLastResult(){return this.lastResult}async cleanup(){this.tmCore&&=void 0}static register(t,n){let r=new e(n);return t.addCommand(r),r}},On=class e extends K{tmCore;lastResult;constructor(e){super(e||`show`),this.description(`Display detailed information about one or more tasks`).argument(`[id]`,`Task ID(s) to show (comma-separated for multiple)`).option(`-i, --id <id>`,`Task ID(s) to show (comma-separated for multiple)`).option(`-s, --status <status>`,`Filter subtasks by status`).option(`-f, --format <format>`,`Output format (text, json)`,`text`).option(`--json`,`Output in JSON format (shorthand for --format json)`).option(`--silent`,`Suppress output (useful for programmatic usage)`).option(`-p, --project <path>`,`Project root directory (auto-detected if not provided)`).action(async(e,t)=>{await this.executeCommand(e,t)})}async executeCommand(e,t){try{this.validateOptions(t)||process.exit(1),await this.initializeCore(X(t.project));let n=e||t.id;n||(console.error(V.red(`Error: Please provide a task ID`)),process.exit(1));let r=n.split(`,`).map(e=>e.trim()).filter(e=>e.length>0),i=[];for(let e of r){let t=s.safeParse(e);t.success||(console.error(V.red(`Invalid task ID: ${e}`),B.muted(`- ${t.error.issues[0]?.message}`)),process.exit(1)),i.push(t.data)}let a=i.length>1?await this.getMultipleTasks(i,t):await this.getSingleTask(i[0],t);this.setLastResult(a),t.silent||this.displayResults(a,t)}catch(e){Y(e)}}validateOptions(e){return e.format&&![`text`,`json`].includes(e.format)?(console.error(V.red(`Invalid format: ${e.format}`)),console.error(B.muted(`Valid formats: text, json`)),!1):!0}async initializeCore(e){this.tmCore||=await b({projectPath:e})}async getSingleTask(e,t){if(!this.tmCore)throw Error(`TmCore not initialized`);let n=await this.tmCore.tasks.get(e);return{task:n.task,found:n.task!==null,originalTaskId:n.isSubtask?e:void 0}}async getMultipleTasks(e,t){if(!this.tmCore)throw Error(`TmCore not initialized`);let n=[],r=[];for(let t of e){let e=await this.tmCore.tasks.get(t);e.task?n.push(e.task):r.push(t)}return{tasks:n,notFound:r}}displayResults(e,t){switch(t.json?`json`:t.format||`text`){case`json`:this.displayJson(e);break;default:`task`in e?this.displaySingleTask(e,t):this.displayMultipleTasks(e,t)}}displayJson(e){console.log(JSON.stringify(e,null,2))}displaySingleTask(e,t){!e.found||!e.task?console.log(G(V.yellow(`Task not found!`),{padding:{top:0,bottom:0,left:1,right:1},borderColor:`yellow`,borderStyle:`round`,margin:{top:1}})):(Tn({tag:this.tmCore?.config.getActiveTag()||`master`}),console.log(),Qt(e.task,{statusFilter:t.status,showSuggestedActions:!0,originalTaskId:e.originalTaskId}))}displayMultipleTasks(e,t){Tn({tag:this.tmCore?.config.getActiveTag()||`master`}),e.notFound.length>0&&console.log(V.yellow(`\n⚠ Not found: ${e.notFound.join(`, `)}`)),e.tasks.length===0?yn(`No tasks found matching the criteria.`):(console.log(B.brand.bold(`
|
|
67
67
|
Tasks:
|
|
68
|
-
`)),console.log(
|
|
68
|
+
`)),console.log(Sn(e.tasks,{showSubtasks:!0,showDependencies:!0})))}setLastResult(e){this.lastResult=e}getLastResult(){return this.lastResult}async cleanup(){this.tmCore&&=void 0}static register(t,n){let r=new e(n);return t.addCommand(r),r}},kn=class e extends K{tmCore;lastResult;constructor(e){super(e||`next`),this.description(`Find the next available task to work on`).option(`-t, --tag <tag>`,`Filter by tag`).option(`-f, --format <format>`,`Output format (text, json)`,`text`).option(`--silent`,`Suppress output (useful for programmatic usage)`).option(`-p, --project <path>`,`Project root directory (auto-detected if not provided)`).action(async e=>{await this.executeCommand(e)})}async executeCommand(e){let t=!1;try{this.validateOptions(e),await this.initializeCore(X(e.project));let t=await this.getNextTask(e);this.setLastResult(t),e.silent||this.displayResults(t,e)}catch(e){t=!0,Y(e,{skipExit:!0})}finally{await this.cleanup()}t&&process.exit(1)}validateOptions(e){if(e.format&&![`text`,`json`].includes(e.format))throw Error(`Invalid format: ${e.format}. Valid formats are: text, json`)}async initializeCore(e){if(!this.tmCore){let t=Ae.resolve(e);this.tmCore=await b({projectPath:t})}}async getNextTask(e){if(!this.tmCore)throw Error(`TmCore not initialized`);let t=await this.tmCore.tasks.getNext(e.tag),n=e.tag||this.tmCore.config.getActiveTag(),r=await this.tmCore.tasks.list({tag:e.tag}),i=r&&r.tasks.length>0;return{task:t,found:t!==null,tag:n,hasAnyTasks:i}}displayResults(e,t){switch(t.format||`text`){case`json`:this.displayJson(e);break;default:this.displayText(e)}}displayJson(e){console.log(JSON.stringify(e,null,2))}displayText(e){if(Tn({tag:e.tag||`master`}),!e.found||!e.task){e.hasAnyTasks?(console.log(V.yellow(`✓ All tasks are either completed, blocked by dependencies, or in progress.`)),console.log(`\n${V.dim(`Tip: Try`)} ${V.cyan(`taskgraph list`)} ${V.dim(`to see all tasks`)}`)):(console.log(G(V.yellow(`No tasks found in this project.`),{padding:1,borderStyle:`round`,borderColor:`yellow`,title:`No tasks available`,titleAlignment:`center`})),console.log(`\n${V.dim(`Tip: Create tasks with`)} ${V.cyan(`taskgraph parse-prd`)} ${V.dim(`or`)} ${V.cyan(`taskgraph add-task`)}`));return}let t=e.task;Qt(t,{customHeader:`Next Task: #${t.id} - ${t.title}`,headerColor:`green`,showSuggestedActions:!0})}setLastResult(e){this.lastResult=e}getLastResult(){return this.lastResult}async cleanup(){this.tmCore&&=void 0}static register(t,n){let r=new e(n);return t.addCommand(r),r}},An=class e extends K{tmCore;constructor(e){super(e||`graph`),this.description(`Show tasks as a dependency tree`).option(`-i, --id <id>`,`Show only this task and what depends on it`).option(`-t, --tag <tag>`,`Use a specific tag`).option(`-f, --format <format>`,`Output format (text, json)`,`text`).option(`-p, --project <path>`,`Project root directory (auto-detected if not provided)`).action(async e=>{await this.executeCommand(e)})}async executeCommand(e){let t=!1;try{if(e.format&&![`text`,`json`].includes(e.format))throw Error(`Invalid format: ${e.format}. Valid formats are: text, json`);let t=Ae.resolve(X(e.project));this.tmCore=await b({projectPath:t});let n=await this.tmCore.tasks.getDependencyTree({tag:e.tag,rootId:e.id}),r=await this.tmCore.tasks.getNext(e.tag),i={...n,tag:e.tag||this.tmCore.config.getActiveTag(),nextId:r?String(r.id):null};e.format===`json`?console.log(JSON.stringify(i,null,2)):this.displayText(i)}catch(e){t=!0,Y(e,{skipExit:!0})}finally{this.tmCore=void 0}t&&process.exit(1)}displayText(e){if(Tn({tag:e.tag}),e.total===0){console.log(V.yellow(`No tasks yet.`)),console.log(`${B.muted(`Create some with`)} ${B.brand(`taskgraph parse-prd`)} ${B.muted(`or`)} ${B.brand(`taskgraph add-task`)}`);return}console.log();let t=At(e,{nextId:e.nextId,width:wt()});console.log(t.join(`
|
|
69
|
+
`))}static register(t,n){let r=new e(n);return t.addCommand(r),r}},jn=class e extends K{tmCore;lastResult;constructor(e){super(e||`start`),this.description(`Start working on a task by launching claude-code with context`).argument(`[id]`,`Task ID to start working on`).option(`-i, --id <id>`,`Task ID to start working on`).option(`-f, --format <format>`,`Output format (text, json)`,`text`).option(`-p, --project <path>`,`Project root directory (auto-detected if not provided)`).option(`--dry-run`,`Show what would be executed without launching claude-code`).option(`--force`,`Force start even if another task is already in-progress`).option(`--no-status-update`,`Do not automatically update task status to in-progress`).action(async(e,t)=>{await this.executeCommand(e,t)})}async executeCommand(e,t){let n=null;try{this.validateOptions(t)||process.exit(1),n=mn(`Initializing TaskGraph...`).start(),await this.initializeCore(X(t.project)),n.succeed(`TaskGraph initialized`);let r=e||t.id||null;r||(n=mn(`Finding next available task...`).start(),r=await this.performGetNextTask(),r?n.succeed(`Found next task: #${r}`):n.fail(`No available tasks found`)),r||(_n(`No task ID provided and no available tasks found`),process.exit(1)),t.dryRun||await this.showPreLaunchMessage(r),n=mn(`Preparing task execution...`).start();let i=await this.performStartTask(r,t);i.started?n.succeed(t.dryRun?`Dry run completed`:`Task prepared - launching Claude...`):n.fail(`Task execution failed`),!t.dryRun&&i.command&&(n&&!n.isSpinning&&console.log(),await this.executeChildProcess(i.command));let a=i;this.setLastResult(a),(t.dryRun||!i.started)&&this.displayResults(a,t)}catch(e){n&&n.fail(`Operation failed`),Y(e)}}validateOptions(e){return e.format&&![`text`,`json`].includes(e.format)?(console.error(V.red(`Invalid format: ${e.format}`)),console.error(B.muted(`Valid formats: text, json`)),!1):!0}async initializeCore(e){this.tmCore||=await b({projectPath:e})}async performGetNextTask(){if(!this.tmCore)throw Error(`TmCore not initialized`);return this.tmCore.tasks.getNextAvailable()}async showPreLaunchMessage(e){if(!this.tmCore)return;let{task:t,isSubtask:n}=await this.tmCore.tasks.get(e);if(t){let r=n?`Subtask #${e} - ${t.title}`:`Task #${t.id} - ${t.title}`;console.log(V.green(`Starting: `)+V.bold(r)),console.log(B.muted(`Launching Claude Code...`)),console.log()}}async performStartTask(e,t){if(!this.tmCore)throw Error(`TmCore not initialized`);let n=null;!t.noStatusUpdate&&!t.dryRun&&(n=mn(`Updating task status to in-progress...`).start());let r=await this.tmCore.tasks.start(e,{dryRun:t.dryRun,force:t.force,updateStatus:!t.noStatusUpdate});if(n&&(r.started?n.succeed(`Task status updated`):n.warn(`Task status update skipped`)),!r)throw Error(`Failed to start task - core result is undefined`);return r}async executeChildProcess(e){return new Promise((t,n)=>{console.log(V.green(`Launching Claude Code…`)),console.log();let r=Me(e.executable,e.args,{cwd:e.cwd,stdio:`inherit`,shell:!1});r.on(`close`,e=>{e===0?t():n(/* @__PURE__ */ Error(`Process exited with code ${e}`))}),r.on(`error`,e=>{n(/* @__PURE__ */ Error(`Failed to spawn process: ${e.message}`))});let i=()=>{r&&!r.killed&&r.kill(`SIGTERM`)};process.on(`SIGINT`,i),process.on(`SIGTERM`,i),process.on(`exit`,i)})}displayResults(e,t){switch(t.format||`text`){case`json`:this.displayJson(e);break;default:this.displayTextResult(e,t)}}displayJson(e){console.log(JSON.stringify(e,null,2))}displayTextResult(e,t){if(!e.found||!e.task){console.log(G(V.yellow(`Task not found!`),{padding:{top:0,bottom:0,left:1,right:1},borderColor:`yellow`,borderStyle:`round`,margin:{top:1}}));return}let n=e.task;if(t.dryRun){let t=`Dry Run: Starting Task #${n.id} - ${n.title}`;e.subtask&&e.subtaskId&&(t=`Dry Run: Starting Subtask #${n.id}.${e.subtaskId} - ${e.subtask.title}`),Qt(n,{customHeader:t,headerColor:`yellow`}),e.executionOutput&&(console.log(),console.log(G(V.bold(`Claude-Code Prompt:`)+`
|
|
69
70
|
|
|
70
71
|
`+e.executionOutput,{padding:1,borderStyle:`round`,borderColor:N,width:process.stdout.columns*.95||100}))),console.log(),console.log(G(V.yellow(`Dry run - claude-code would be launched with the above prompt`),{padding:{top:0,bottom:0,left:1,right:1},borderColor:`yellow`,borderStyle:`round`}))}else if(e.started){let t=`Task: #${n.id} - ${n.title}`,r=n.id;e.subtask&&e.subtaskId&&(t=`Subtask: #${n.id}.${e.subtaskId} - ${e.subtask.title}`,r=`${n.id}.${e.subtaskId}`),console.log(G(V.green.bold(`✓ Task session complete`)+`
|
|
71
72
|
|
|
72
73
|
`+B.text(t)+`
|
|
73
74
|
|
|
74
75
|
`+V.cyan(`Next steps:`)+`
|
|
75
|
-
• Run ${V.yellow(`tm show `+n.id)} to review task details\n• Run ${V.yellow(`tm set-status --id=`+r+` --status=done`)} when complete\n• Run ${V.yellow(`tm next`)} to find the next available task\n• Run ${V.yellow(`tm start`)} to begin the next task`,{padding:1,borderStyle:`round`,borderColor:`green`,width:process.stdout.columns*.95||100,margin:{top:1}}))}else console.log(G(V.red(`✗ Failed to launch claude-code`+(e.error?`\nError: ${e.error}`:``)),{padding:{top:0,bottom:0,left:1,right:1},borderColor:`red`,borderStyle:`round`}))}setLastResult(e){this.lastResult=e}getLastResult(){return this.lastResult}async cleanup(){this.tmCore&&=void 0}static register(t,n){let r=new e(n);return t.addCommand(r),r}};const
|
|
76
|
+
• Run ${V.yellow(`tm show `+n.id)} to review task details\n• Run ${V.yellow(`tm set-status --id=`+r+` --status=done`)} when complete\n• Run ${V.yellow(`tm next`)} to find the next available task\n• Run ${V.yellow(`tm start`)} to begin the next task`,{padding:1,borderStyle:`round`,borderColor:`green`,width:process.stdout.columns*.95||100,margin:{top:1}}))}else console.log(G(V.red(`✗ Failed to launch claude-code`+(e.error?`\nError: ${e.error}`:``)),{padding:{top:0,bottom:0,left:1,right:1},borderColor:`red`,borderStyle:`round`}))}setLastResult(e){this.lastResult=e}getLastResult(){return this.lastResult}async cleanup(){this.tmCore&&=void 0}static register(t,n){let r=new e(n);return t.addCommand(r),r}};const Mn=[`pending`,`in-progress`,`done`,`deferred`,`cancelled`,`blocked`,`review`];var Nn=class e extends K{tmCore;lastResult;constructor(e){super(e||`set-status`),this.description(`Update the status of one or more tasks`).alias(`status`).argument(`[id]`,`Task ID(s) - comma-separated for multiple (e.g., 1 or 1,1.1,2)`).argument(`[status]`,`Status - ${Mn.join(`, `)}`).option(`-i, --id <id>`,`Task ID(s) (fallback if not using positional)`).option(`-s, --status <status>`,`Status (fallback if not using positional)`).option(`-f, --format <format>`,`Output format (text, json)`,`text`).option(`--silent`,`Suppress output (useful for programmatic usage)`).option(`-p, --project <path>`,`Project root directory (auto-detected if not provided)`).action(async(e,t,n)=>{let r={...n,id:e||n?.id,status:t||n?.status};await this.executeCommand(r)})}async executeCommand(e){let t=!1;try{e.id||(console.error(V.red(`Error: Task ID is required`)),console.log(V.yellow(`Usage examples:
|
|
76
77
|
tm set-status 1 done
|
|
77
78
|
tm set-status 1.2 in-progress
|
|
78
79
|
tm set-status --id=1 --status=done`)),process.exit(1)),e.status||(console.error(V.red(`Error: Status is required`)),console.log(V.yellow(`Usage examples:
|
|
79
80
|
tm set-status 1 done
|
|
80
81
|
tm set-status 1,1.1 in-progress
|
|
81
|
-
tm set-status --id=1 --status=done`)),process.exit(1)),
|
|
82
|
+
tm set-status --id=1 --status=done`)),process.exit(1)),Mn.includes(e.status)||(console.error(V.red(`Error: Invalid status "${e.status}". Valid options: ${Mn.join(`, `)}`)),process.exit(1)),this.tmCore=await b({projectPath:X(e.project)});let n=e.id.split(`,`).map(e=>e.trim()),r=[];for(let e of n){let t=s.safeParse(e);t.success||(console.error(V.red(`Invalid task ID: ${e}`),B.muted(`- ${t.error.issues[0]?.message}`)),process.exit(1)),r.push(t.data)}let i=[];for(let n of r)try{let t=await this.tmCore.tasks.updateStatus(n,e.status);i.push({taskId:t.taskId,oldStatus:t.oldStatus,newStatus:t.newStatus})}catch(r){if(t=!0,e.format===`json`){let e=r?.getSanitizedDetails?r.getSanitizedDetails().message:r instanceof Error?r.message:String(r);console.log(JSON.stringify({success:!1,error:e,taskId:n,timestamp:(/* @__PURE__ */ new Date()).toISOString()}))}else e.silent||(console.error(V.red(`\nFailed to update task ${n}:`)),Y(r,{skipExit:!0}));break}this.lastResult={success:!0,updatedTasks:i},this.displayResults(this.lastResult,e)}catch(n){if(t=!0,e.format===`json`){let e=n instanceof Error?n.message:`Unknown error occurred`;console.log(JSON.stringify({success:!1,error:e}))}else e.silent||Y(n,{skipExit:!0})}finally{this.tmCore}t&&process.exit(1)}displayResults(e,t){switch(t.format||`text`){case`json`:console.log(JSON.stringify(e,null,2));break;default:t.silent||this.displayTextResults(e)}}displayTextResults(e){if(e.updatedTasks.length===1){let t=e.updatedTasks[0];console.log(G(V.bold(`✓ Updated task ${t.taskId}`)+`
|
|
82
83
|
|
|
83
84
|
${B.brand(`From:`)} ${this.getStatusDisplay(t.oldStatus)}\n${B.brand(`To:`)} ${this.getStatusDisplay(t.newStatus)}`,{padding:1,borderColor:`green`,borderStyle:`round`,margin:{top:1}}))}else console.log(G(V.bold(`✓ Updated ${e.updatedTasks.length} tasks`)+`
|
|
84
85
|
|
|
85
86
|
`+e.updatedTasks.map(e=>`${V.cyan(e.taskId)}: ${this.getStatusDisplay(e.oldStatus)} → ${this.getStatusDisplay(e.newStatus)}`).join(`
|
|
86
|
-
`),{padding:1,borderColor:`green`,borderStyle:`round`,margin:{top:1}}))}getStatusDisplay(e){return({pending:V.yellow,"in-progress":B.brand,done:V.green,deferred:B.muted,cancelled:V.red,blocked:V.red,review:V.magenta,completed:V.green}[e]||B.text)(e)}getLastResult(){return this.lastResult}static register(t,n){let r=new e(n);return t.addCommand(r),r}};const
|
|
87
|
+
`),{padding:1,borderColor:`green`,borderStyle:`round`,margin:{top:1}}))}getStatusDisplay(e){return({pending:V.yellow,"in-progress":B.brand,done:V.green,deferred:B.muted,cancelled:V.red,blocked:V.red,review:V.magenta,completed:V.green}[e]||B.text)(e)}getLastResult(){return this.lastResult}static register(t,n){let r=new e(n);return t.addCommand(r),r}};const Pn=`taskgraph-ai`,Fn=`stephennmiller/taskgraph-ai`;function In(e,t,n){let r=`${B.brand.bold(`Update Available!`)} ${V.dim(e)} → ${V.green(t)}`;if(n&&n.length>0){r+=`
|
|
87
88
|
|
|
88
89
|
`+V.bold(`What's New:`);for(let e of n)r+=`
|
|
89
90
|
`+V.cyan(`• `)+e;r+=`
|
|
90
91
|
|
|
91
92
|
Auto-updating to the latest version...`}else r+=`
|
|
92
93
|
|
|
93
|
-
Auto-updating to the latest version with new features and bug fixes...`;let i=G(r,{padding:1,margin:{top:1,bottom:1},borderColor:`yellow`,borderStyle:`round`});console.log(i)}function
|
|
94
|
+
Auto-updating to the latest version with new features and bug fixes...`;let i=G(r,{padding:1,margin:{top:1,bottom:1},borderColor:`yellow`,borderStyle:`round`});console.log(i)}function Ln(e){return e<1024?`${e} B`:e<1048576?`${(e/1024).toFixed(1)} KB`:`${(e/1048576).toFixed(1)} MB`}async function Rn(e){return new Promise(t=>{let n={hostname:`registry.npmjs.org`,path:`/${Pn}/${e}`,method:`GET`,headers:{Accept:`application/json`,"User-Agent":`${Pn}/${e}`}},r=Ue.request(n,e=>{let n=``;e.on(`data`,e=>{n+=e}),e.on(`end`,()=>{try{if(e.statusCode!==200){t(null);return}let r=JSON.parse(n),i=r.dist?.tarball,a=r.dist?.unpackedSize;if(!i){t(null);return}t({url:i,size:a||0})}catch{t(null)}})});r.on(`error`,()=>{t(null)}),r.setTimeout(1e4,()=>{r.destroy(),t(null)}),r.end()})}async function zn(e,t,n,r=5){return r<=0?(console.error(V.red(`Too many redirects`)),Promise.resolve(!1)):new Promise(i=>{let a=new URL(e),o={hostname:a.hostname,path:a.pathname,method:`GET`,headers:{"User-Agent":`${Pn}/${n}`}},s=Ue.request(o,e=>{if(e.statusCode===301||e.statusCode===302){let a=e.headers.location;if(a){zn(a,t,n,r-1).then(i).catch(()=>i(!1));return}i(!1);return}if(e.statusCode!==200){i(!1);return}let a=Number.parseInt(e.headers[`content-length`]||`0`,10),o=0,s=new Ge.SingleBar({format:`${B.brand(`Downloading`)} ${V.cyan(`{bar}`)} {percentage}% | {downloaded}/{total}`,barCompleteChar:`█`,barIncompleteChar:`░`,hideCursor:!0,clearOnComplete:!0},Ge.Presets.shades_classic);a>0?s.start(a,0,{downloaded:Ln(0),total:Ln(a)}):console.log(B.brand(`Downloading ${Pn}@${n}...`));let c=W.createWriteStream(t);e.on(`data`,e=>{o+=e.length,a>0&&s.update(o,{downloaded:Ln(o),total:Ln(a)})}),e.pipe(c),c.on(`finish`,()=>{a>0&&s.stop(),c.close(()=>{console.log(V.green(`✓`)+V.dim(` Downloaded ${Ln(o)}`)),i(!0)})}),c.on(`error`,e=>{a>0&&s.stop(),console.error(V.red(`Download error:`),e.message),W.unlink(t,()=>{}),i(!1)})});s.on(`error`,e=>{console.error(V.red(`Request error:`),e.message),i(!1)}),s.setTimeout(12e4,()=>{s.destroy(),console.error(V.red(`Download timeout`)),i(!1)}),s.end()})}const Bn=[{name:`Extracting package`,weight:15},{name:`Resolving dependencies`,weight:25},{name:`Building dependency tree`,weight:20},{name:`Linking package`,weight:25},{name:`Finalizing installation`,weight:15}],Vn=Bn.reduce((e,t)=>e+t.weight,0);function Hn(e){let t=e.toLowerCase();return t.includes(`extract`)||t.includes(`unpack`)?0:t.includes(`resolv`)||t.includes(`fetch`)?1:t.includes(`build`)||t.includes(`tree`)?2:t.includes(`link`)||t.includes(`bin`)?3:t.includes(`added`)||t.includes(`done`)?4:-1}function Un(e,t){if(e<0||e>=Bn.length)return e>=Bn.length?100:0;let n=0;for(let t=0;t<e;t++)n+=Bn[t].weight;let r=Bn[e].weight*t/100;return Math.round((n+r)/Vn*100)}async function Wn(e){let t=new Ge.SingleBar({format:`${B.brand(`Installing`)} ${V.cyan(`{bar}`)} {percentage}% | {phase}`,barCompleteChar:`█`,barIncompleteChar:`░`,hideCursor:!0,clearOnComplete:!0},Ge.Presets.shades_classic);t.start(100,0,{phase:Bn[0].name});let n=0,r=0,i=Date.now(),a=setInterval(()=>{let e=Date.now()-i,a=1e4,o=0,s=0;for(let t=0;t<Bn.length;t++){let n=Bn[t].weight/Vn*a;if(e<s+n){o=t;break}s+=n,o=t}o>n&&(n=o);let c=Bn.slice(0,n).reduce((e,t)=>e+t.weight,0)/Vn*a,l=Bn[n].weight/Vn*a,u=e-c,d=Math.min(u/l*100,95),f=Un(n,d);f>r&&(r=f,t.update(r,{phase:Bn[n].name}))},100);return new Promise(i=>{let o=Me(`npm`,[`install`,`-g`,e,`--no-fund`,`--no-audit`],{stdio:[`ignore`,`pipe`,`pipe`]}),s=``;o.stdout.on(`data`,e=>{let i=Hn(e.toString());if(i>n){n=i;let e=Un(n,0);e>r&&(r=e,t.update(r,{phase:Bn[n].name}))}}),o.stderr.on(`data`,e=>{let i=e.toString();s+=i;let a=Hn(i);if(a>n){n=a;let e=Un(n,0);e>r&&(r=e,t.update(r,{phase:Bn[n].name}))}}),o.on(`close`,n=>{if(clearInterval(a),t.update(100,{phase:`Complete`}),t.stop(),W.existsSync(e)&&W.unlink(e,()=>{}),n===0)console.log(V.green(`✓`)+V.green(` Update installed successfully`)),i(!0);else{if(console.log(V.red(`✗`)+V.red(` Installation failed`)),s){let e=s.split(`
|
|
94
95
|
`).filter(e=>e.includes(`ERR`)||e.includes(`error`)||e.includes(`WARN`)).join(`
|
|
95
|
-
`).trim();e&&console.log(V.dim(`Error: ${e}`))}i(!1)}}),o.on(`error`,n=>{clearInterval(a),t.stop(),W.unlink(e,()=>{}),console.log(V.red(`✗`)+V.red(` Installation failed`)),console.log(V.red(`Error:`),n.message),i(!1)})})}async function
|
|
96
|
-
`));let n=Me(`taskgraph`,t,{stdio:`inherit`,detached:!1,shell:He.platform===`win32`});n.on(`exit`,(e,t)=>{t?He.kill(He.pid,t):He.exit(e??0)}),n.on(`error`,e=>{console.error(V.red(`Failed to restart with new version:`),e.message),console.log(V.yellow(`Please run your command again manually.`)),He.exit(1)})}function
|
|
96
|
+
`).trim();e&&console.log(V.dim(`Error: ${e}`))}i(!1)}}),o.on(`error`,n=>{clearInterval(a),t.stop(),W.unlink(e,()=>{}),console.log(V.red(`✗`)+V.red(` Installation failed`)),console.log(V.red(`Error:`),n.message),i(!1)})})}async function Gn(e){let t=mn(B.brand(`Updating ${Pn} to version ${V.green(e)}`)).start();return new Promise(n=>{let r=Me(`npm`,[`install`,`-g`,`${Pn}@${e}`,`--no-fund`,`--no-audit`,`--loglevel=warn`],{stdio:[`ignore`,`pipe`,`pipe`]}),i=``;r.stdout.on(`data`,()=>{t.text=B.brand(`Installing ${Pn}@${e}...`)}),r.stderr.on(`data`,e=>{i+=e.toString()}),r.on(`close`,r=>{r===0?(t.succeed(V.green(`Successfully updated to version ${V.bold(e)}`)),n(!0)):(t.fail(V.red(`Auto-update failed`)),console.log(V.cyan(`Please run manually: npm install -g ${Pn}@${e}`)),i&&console.log(V.dim(`Error: ${i.trim()}`)),n(!1))}),r.on(`error`,r=>{t.fail(V.red(`Auto-update failed`)),console.log(V.red(`Error:`),r.message),console.log(V.cyan(`Please run manually: npm install -g ${Pn}@${e}`)),n(!1)})})}async function Kn(e){if(He.env.TASKGRAPH_SKIP_AUTO_UPDATE===`1`||He.env.CI||He.env.NODE_ENV===`test`){let e=He.env.TASKGRAPH_SKIP_AUTO_UPDATE===`1`?`TASKGRAPH_SKIP_AUTO_UPDATE=1`:He.env.CI?`CI environment`:`NODE_ENV=test`;return console.log(V.dim(`Skipping auto-update (${e})`)),!1}let t=await Rn(e);if(!t)return Gn(e);let n=We.tmpdir(),r=H.join(n,`${Pn}-${e}.tgz`);return await zn(t.url,r,e)?await Wn(r)?(console.log(V.green(`Successfully updated to version ${V.bold(e)}`)),!0):(console.log(V.cyan(`Please run manually: npm install -g ${Pn}@${e}`)),!1):(console.log(V.dim(`Falling back to npm install...`)),Gn(e))}function qn(e){let t=e.slice(2);console.log(V.dim(`Restarting with updated version...
|
|
97
|
+
`));let n=Me(`taskgraph`,t,{stdio:`inherit`,detached:!1,shell:He.platform===`win32`});n.on(`exit`,(e,t)=>{t?He.kill(He.pid,t):He.exit(e??0)}),n.on(`error`,e=>{console.error(V.red(`Failed to restart with new version:`),e.message),console.log(V.yellow(`Please run your command again manually.`)),He.exit(1)})}function Jn(e,t=null){let n={high:3,medium:2,low:1},r=(e,t)=>typeof t==`string`&&t.includes(`.`)?t:`${e}.${t}`,i=/* @__PURE__ */ new Set;e.forEach(e=>{(e.status===`done`||e.status===`completed`)&&i.add(String(e.id)),Array.isArray(e.subtasks)&&e.subtasks.forEach(t=>{(t.status===`done`||t.status===`completed`)&&i.add(`${e.id}.${t.id}`)})});let a=[];if(e.filter(e=>e.status===`in-progress`&&Array.isArray(e.subtasks)).forEach(e=>{e.subtasks.forEach(t=>{let n=(t.status||`pending`).toLowerCase();if(n!==`pending`&&n!==`in-progress`)return;let o=t.dependencies?.map(t=>r(e.id,t))??[];(o.length===0||o.every(e=>i.has(String(e))))&&a.push({id:`${e.id}.${t.id}`,title:t.title||`Subtask ${t.id}`,status:t.status||`pending`,priority:t.priority||e.priority||`medium`,dependencies:o,parentId:e.id})})}),a.length>0){a.sort((e,t)=>{let r=n[e.priority]??2,i=n[t.priority]??2;if(i!==r)return i-r;if(e.dependencies.length!==t.dependencies.length)return e.dependencies.length-t.dependencies.length;let[a,o]=e.id.split(`.`).map(Number),[s,c]=t.id.split(`.`).map(Number);return a===s?o-c:a-s});let e=a[0];return e&&t&&T(e,t),e}let o=e.filter(e=>{let t=(e.status||`pending`).toLowerCase();return t!==`pending`&&t!==`in-progress`?!1:(e.dependencies??[]).every(e=>i.has(String(e)))});if(o.length===0)return null;let s=o.sort((e,t)=>{let r=n[e.priority||`medium`]??2,i=n[t.priority||`medium`]??2;if(i!==r)return i-r;let a=(e.dependencies??[]).length,o=(t.dependencies??[]).length;return a===o?e.id-t.id:a-o})[0];return s&&t&&T(s,t),s}async function Yn(e,t,n={},r={},i=`text`){let{mcpLog:a,projectRoot:o}=r,{copyFromCurrent:s=!1,copyFromTag:c,description:l}=n,u=a||{info:(...e)=>I(`info`,...e),warn:(...e)=>I(`warn`,...e),error:(...e)=>I(`error`,...e),debug:(...e)=>I(`debug`,...e),success:(...e)=>I(`success`,...e)};try{if(!t||typeof t!=`string`)throw Error(`Tag name is required and must be a string`);if(!/^[a-zA-Z0-9_-]+$/.test(t))throw Error(`Tag name can only contain letters, numbers, hyphens, and underscores`);if([`master`,`main`,`default`].includes(t.toLowerCase()))throw Error(`"${t}" is a reserved tag name`);u.info(`Creating new tag: ${t}`);let n=P(e,o);if(!n)throw Error(`Could not read tasks file at ${e}`);let r;if(n._rawTaggedData)r=n._rawTaggedData;else if(n.tasks&&!n.master)r={master:{tasks:n.tasks,metadata:n.metadata||{created:(/* @__PURE__ */ new Date()).toISOString(),updated:(/* @__PURE__ */ new Date()).toISOString(),description:`Tasks live here by default`}}};else{r={};for(let[e,t]of Object.entries(n))e!==`_rawTaggedData`&&e!==`tag`&&(r[e]=t)}if(r[t])throw Error(`Tag "${t}" already exists`);let a=[];if(s||c){let e=c||M(o);a=C(r,e),c&&a.length===0&&u.warn(`Source tag "${c}" not found or has no tasks`),u.info(`Copying ${a.length} tasks from tag "${e}"`)}else u.info(`Creating empty tag (no tasks copied)`);r[t]={tasks:[...a],metadata:{created:(/* @__PURE__ */ new Date()).toISOString(),updated:(/* @__PURE__ */ new Date()).toISOString(),description:l||`Tag created on ${(/* @__PURE__ */ new Date()).toLocaleDateString()}`}};let d={};for(let[e,t]of Object.entries(r))e!==`_rawTaggedData`&&(d[e]=t);return F(e,d,o),u.success(`Successfully created tag "${t}"`),i===`json`||i===`text`&&console.log(G(V.green.bold(`✓ Tag Created Successfully`)+`\n\nTag Name: ${V.cyan(t)}\nTasks Copied: ${V.yellow(a.length)}`+(s||c?`\nSource Tag: ${V.cyan(c||M(o))}`:``)+(l?`\nDescription: ${B.muted(l)}`:``),{padding:1,borderColor:`green`,borderStyle:`round`,margin:{top:1,bottom:1}})),{tagName:t,created:!0,tasksCopied:a.length,sourceTag:s||c?c||M(o):null,description:l||`Tag created on ${(/* @__PURE__ */ new Date()).toLocaleDateString()}`}}catch(e){throw u.error(`Error creating tag: ${e.message}`),e}}async function Xn(e,t,n={},r={},i=`text`){let{mcpLog:a,projectRoot:o}=r,{yes:s=!1}=n,c=a||{info:(...e)=>I(`info`,...e),warn:(...e)=>I(`warn`,...e),error:(...e)=>I(`error`,...e),debug:(...e)=>I(`debug`,...e),success:(...e)=>I(`success`,...e)};try{if(!t||typeof t!=`string`)throw Error(`Tag name is required and must be a string`);if(t===`master`)throw Error(`Cannot delete the "master" tag`);c.info(`Deleting tag: ${t}`);let n=P(e,o);if(!n)throw Error(`Could not read tasks file at ${e}`);let r;if(n._rawTaggedData)r=n._rawTaggedData;else if(n.tasks&&!n.master)r={master:{tasks:n.tasks,metadata:n.metadata||{created:(/* @__PURE__ */ new Date()).toISOString(),updated:(/* @__PURE__ */ new Date()).toISOString(),description:`Tasks live here by default`}}};else{r={};for(let[e,t]of Object.entries(n))e!==`_rawTaggedData`&&e!==`tag`&&(r[e]=t)}if(!r[t])throw Error(`Tag "${t}" does not exist`);let a=M(o)===t,l=C(r,t).length;if(!s&&l>0&&i===`text`){if(console.log(G(V.yellow.bold(`⚠ WARNING: Tag Deletion`)+`\n\nYou are about to delete tag "${V.cyan(t)}"\nThis will permanently delete ${V.red.bold(l)} tasks
|
|
97
98
|
|
|
98
|
-
This action cannot be undone!`,{padding:1,borderColor:`yellow`,borderStyle:`round`,margin:{top:1,bottom:1}})),!(await Ke.prompt([{type:`confirm`,name:`proceed`,message:`Are you sure you want to delete tag "${t}" and its ${l} tasks?`,default:!1}])).proceed)throw c.info(`Tag deletion cancelled by user`),Error(`Tag deletion cancelled`);if((await Ke.prompt([{type:`input`,name:`tagNameConfirm`,message:`To confirm deletion, please type the tag name "${t}":`,validate:e=>e===t||`Please type exactly "${t}" to confirm deletion`}])).tagNameConfirm!==t)throw c.info(`Tag deletion cancelled - incorrect tag name confirmation`),Error(`Tag deletion cancelled`);c.info(`Double confirmation received, proceeding with deletion...`)}delete r[t],a&&(await Qn(o,`master`),c.info(`Switched current tag to "master"`));let u={};for(let[e,t]of Object.entries(r))e!==`_rawTaggedData`&&(u[e]=t);return F(e,u,o),c.success(`Successfully deleted tag "${t}"`),i===`json`||i===`text`&&console.log(G(V.red.bold(`✓ Tag Deleted Successfully`)+`\n\nTag Name: ${V.cyan(t)}\nTasks Deleted: ${V.yellow(l)}`+(a?`\n${V.yellow(`⚠ Switched current tag to "master"`)}`:``),{padding:1,borderColor:`red`,borderStyle:`round`,margin:{top:1,bottom:1}})),{tagName:t,deleted:!0,tasksDeleted:l,wasCurrentTag:a,switchedToMaster:a}}catch(e){throw c.error(`Error deleting tag: ${e.message}`),e}}async function qn(e,t,n={}){let r=!1;try{let i;try{let t=W.statSync(e);i=t.birthtime<t.mtime?t.birthtime:t.mtime}catch{i=/* @__PURE__ */ new Date}for(let[e,n]of Object.entries(t))e!==`tasks`&&e!==`tag`&&e!==`_rawTaggedData`&&n&&typeof n==`object`&&Array.isArray(n.tasks)&&(n.metadata||(n.metadata={},r=!0),n.metadata.created||(n.metadata.created=i.toISOString(),r=!0),n.metadata.description||(e===`master`?n.metadata.description=`Tasks live here by default`:n.metadata.description=`Tag created on ${new Date(n.metadata.created).toLocaleDateString()}`,r=!0),n.metadata.updated||(n.metadata.updated=n.metadata.created,r=!0));if(r){let r={};for(let[e,n]of Object.entries(t))e!==`_rawTaggedData`&&(r[e]=n);F(e,r,n.projectRoot)}}catch(e){(n.mcpLog||{warn:(...e)=>I(`warn`,...e)}).warn(`Could not enhance tag metadata: ${e.message}`)}return r}async function Jn(e,t={},n={},r=`text`){let{mcpLog:i,projectRoot:a}=n,{showTaskCounts:o=!0,showMetadata:s=!1,ready:c=!1}=t,l=i||{info:(...e)=>I(`info`,...e),warn:(...e)=>I(`warn`,...e),error:(...e)=>I(`error`,...e),debug:(...e)=>I(`debug`,...e),success:(...e)=>I(`success`,...e)};try{l.info(`Listing available tags`),l.info(`Using file storage for tags`);let t=P(e,a);if(!t)throw Error(`Could not read tasks file at ${e}`);let i=M(a),u=t._rawTaggedData||t;await qn(e,u,n);let d=[];for(let[e,t]of Object.entries(u)){if(e===`tasks`||e===`tag`||e===`_rawTaggedData`||!t||typeof t!=`object`||!Array.isArray(t.tasks))continue;let n=t.tasks||[],r=t.metadata||{},a=n.map(e=>({...e,blocks:[]})),o=_(a);d.push({name:e,isCurrent:e===i,completedTasks:n.filter(e=>p(e.status)).length,readyTasks:o.length,tasks:n||[],created:r.created||`Unknown`,description:r.description||`No description`})}d.sort((e,t)=>e.isCurrent?-1:t.isCurrent?1:e.name.localeCompare(t.name));let f=d;if(c&&(f=d.filter(e=>e.readyTasks>0),l.info(`Filtered to ${f.length} tags with ready tasks`)),l.success(`Found ${f.length} tags`),r===`json`)return{tags:f,currentTag:i,totalTags:f.length};if(r===`text`){if(f.length===0){let e=c?`No tags with ready tasks found`:`No tags found`;return console.log(G(V.yellow(e),{padding:1,borderColor:`yellow`,borderStyle:`round`,margin:{top:1,bottom:1}})),{tags:[],currentTag:i,totalTags:0}}let e=[V.cyan.bold(`Tag Name`)];o&&(e.push(V.cyan.bold(`Tasks`)),e.push(V.cyan.bold(`Ready`)),e.push(V.cyan.bold(`Done`))),s&&(e.push(V.cyan.bold(`Created`)),e.push(V.cyan.bold(`Description`)));let t=Math.max(process.stdout.columns||120,80),n=Math.floor(t*.95),r;r=s?[.22,.08,.08,.08,.14,.38].map((e,t)=>Math.max(Math.floor(n*e),t===0?15:6)):[.6,.13,.13,.13].map((e,t)=>Math.max(Math.floor(n*e),t===0?20:8));let a=new q({head:e,colWidths:r,wordWrap:!0,style:{border:le}});f.forEach(e=>{let t=[],n=e.isCurrent?`${V.green(`●`)} ${V.green.bold(e.name)} ${B.muted(`(current)`)}`:` ${e.name}`;if(t.push(n),o&&(t.push(B.text(e.tasks.length.toString())),t.push(e.readyTasks>0?V.yellow(e.readyTasks.toString()):B.muted(`0`)),t.push(V.green(e.completedTasks.toString()))),s){let n=e.created===`Unknown`?`Unknown`:new Date(e.created).toLocaleDateString();t.push(B.muted(n)),t.push(B.muted(R(e.description,50)))}a.push(t)}),console.log(a.toString())}return{tags:f,currentTag:i,totalTags:f.length}}catch(e){throw l.error(`Error listing tags: ${e.message}`),e}}async function Yn(e,t,n={},r={},i=`text`){let{mcpLog:a,projectRoot:o}=r,s=a||{info:(...e)=>I(`info`,...e),warn:(...e)=>I(`warn`,...e),error:(...e)=>I(`error`,...e),debug:(...e)=>I(`debug`,...e),success:(...e)=>I(`success`,...e)};try{if(!t||typeof t!=`string`)throw Error(`Tag name is required and must be a string`);s.info(`Switching to tag: ${t}`),s.info(`Using file storage for tag switch`);let n=P(e,o);if(!n)throw Error(`Could not read tasks file at ${e}`);if(!(n._rawTaggedData||n)[t])throw Error(`Tag "${t}" does not exist`);let r=M(o);await Qn(o,t);let a=P(e,o,t),c=a&&a.tasks||[],l=c.length,u=Wn(c);if(s.success(`Successfully switched to tag "${t}"`),i===`json`)return{previousTag:r,currentTag:t,switched:!0,taskCount:l,nextTask:u};if(i===`text`){let e=``;e=u?`\nNext Task: ${V.cyan(`#${u.id}`)} - ${B.text(u.title)}`:`\nNext Task: ${B.muted(`No eligible tasks available`)}`,console.log(G(V.green.bold(`✓ Tag Switched Successfully`)+`\n\nPrevious Tag: ${V.cyan(r)}\nCurrent Tag: ${V.green.bold(t)}\nAvailable Tasks: ${V.yellow(l)}`+e,{padding:1,borderColor:`green`,borderStyle:`round`,margin:{top:1,bottom:1}}))}return{previousTag:r,currentTag:t,switched:!0,taskCount:l,nextTask:u}}catch(e){throw s.error(`Error switching tag: ${e.message}`),e}}async function Xn(e,t,n,r={},i={},a=`text`){let{mcpLog:o,projectRoot:s}=i,c=o||{info:(...e)=>I(`info`,...e),warn:(...e)=>I(`warn`,...e),error:(...e)=>I(`error`,...e),debug:(...e)=>I(`debug`,...e),success:(...e)=>I(`success`,...e)};try{if(!t||typeof t!=`string`)throw Error(`Old tag name is required and must be a string`);if(!n||typeof n!=`string`)throw Error(`New tag name is required and must be a string`);if(!/^[a-zA-Z0-9_-]+$/.test(n))throw Error(`New tag name can only contain letters, numbers, hyphens, and underscores`);if(t===`master`)throw Error(`Cannot rename the "master" tag`);if([`master`,`main`,`default`].includes(n.toLowerCase()))throw Error(`"${n}" is a reserved tag name`);c.info(`Renaming tag from "${t}" to "${n}"`);let r=P(e,s);if(!r)throw Error(`Could not read tasks file at ${e}`);let i=r._rawTaggedData||r;if(!i[t])throw Error(`Tag "${t}" does not exist`);if(i[n])throw Error(`Tag "${n}" already exists`);let o=M(s)===t;i[n]={...i[t]},i[n].metadata&&(i[n].metadata.renamed={from:t,date:(/* @__PURE__ */ new Date()).toISOString()}),delete i[t],o&&(await Qn(s,n),c.info(`Updated current tag reference to "${n}"`));let l={};for(let[e,t]of Object.entries(i))e!==`_rawTaggedData`&&(l[e]=t);F(e,l,s);let u=C(i,n).length;return c.success(`Successfully renamed tag from "${t}" to "${n}"`),a===`json`||a===`text`&&console.log(G(V.green.bold(`✓ Tag Renamed Successfully`)+`\n\nOld Name: ${V.cyan(t)}\nNew Name: ${V.green.bold(n)}\nTasks: ${V.yellow(u)}`+(o?`\n${V.green(`✓ Current tag updated`)}`:``),{padding:1,borderColor:`green`,borderStyle:`round`,margin:{top:1,bottom:1}})),{oldName:t,newName:n,renamed:!0,taskCount:u,wasCurrentTag:o,isCurrentTag:o}}catch(e){throw c.error(`Error renaming tag: ${e.message}`),e}}async function Zn(e,t,n,r={},i={},a=`text`){let{mcpLog:o,projectRoot:s}=i,{description:c}=r,l=o||{info:(...e)=>I(`info`,...e),warn:(...e)=>I(`warn`,...e),error:(...e)=>I(`error`,...e),debug:(...e)=>I(`debug`,...e),success:(...e)=>I(`success`,...e)};try{if(!t||typeof t!=`string`)throw Error(`Source tag name is required and must be a string`);if(!n||typeof n!=`string`)throw Error(`Target tag name is required and must be a string`);if(!/^[a-zA-Z0-9_-]+$/.test(n))throw Error(`Target tag name can only contain letters, numbers, hyphens, and underscores`);if([`master`,`main`,`default`].includes(n.toLowerCase()))throw Error(`"${n}" is a reserved tag name`);l.info(`Copying tag from "${t}" to "${n}"`);let r=P(e,s);if(!r)throw Error(`Could not read tasks file at ${e}`);let i=r._rawTaggedData||r;if(!i[t])throw Error(`Source tag "${t}" does not exist`);if(i[n])throw Error(`Target tag "${n}" already exists`);let o=C(i,t);i[n]={tasks:JSON.parse(JSON.stringify(o)),metadata:{created:(/* @__PURE__ */ new Date()).toISOString(),updated:(/* @__PURE__ */ new Date()).toISOString(),description:c||`Copy of "${t}" created on ${(/* @__PURE__ */ new Date()).toLocaleDateString()}`,copiedFrom:{tag:t,date:(/* @__PURE__ */ new Date()).toISOString()}}};let u={};for(let[e,t]of Object.entries(i))e!==`_rawTaggedData`&&(u[e]=t);return F(e,u,s),l.success(`Successfully copied tag from "${t}" to "${n}"`),a===`json`||a===`text`&&console.log(G(V.green.bold(`✓ Tag Copied Successfully`)+`\n\nSource Tag: ${V.cyan(t)}\nTarget Tag: ${V.green.bold(n)}\nTasks Copied: ${V.yellow(o.length)}`+(c?`\nDescription: ${B.muted(c)}`:``),{padding:1,borderColor:`green`,borderStyle:`round`,margin:{top:1,bottom:1}})),{sourceName:t,targetName:n,copied:!0,description:c||`Copy of "${t}" created on ${(/* @__PURE__ */ new Date()).toLocaleDateString()}`}}catch(e){throw l.error(`Error copying tag: ${e.message}`),e}}async function Qn(e,t){try{let n=H.join(e,`.taskgraph`,`state.json`),r={};if(W.existsSync(n)){let e=W.readFileSync(n,`utf8`);r=JSON.parse(e)}r.currentTag=t,r.lastSwitched=(/* @__PURE__ */ new Date()).toISOString(),r.branchTagMapping||(r.branchTagMapping={}),r.migrationNoticeShown===void 0&&(r.migrationNoticeShown=!1),W.writeFileSync(n,JSON.stringify(r,null,2),`utf8`)}catch(e){I(`warn`,`Could not update current tag in state.json: ${e.message}`)}}async function $n(e,t,n){try{let r=H.join(e,`.taskgraph`,`state.json`),i={};if(W.existsSync(r)){let e=W.readFileSync(r,`utf8`);i=JSON.parse(e)}i.branchTagMapping||(i.branchTagMapping={}),i.branchTagMapping[t]=n,W.writeFileSync(r,JSON.stringify(i,null,2),`utf8`)}catch(e){I(`warn`,`Could not update branch-tag mapping: ${e.message}`)}}async function er(e,t,n={},r={},i=`text`){let{mcpLog:a,projectRoot:o}=r,{copyFromCurrent:s,copyFromTag:c,description:l,autoSwitch:u}=n,{sanitizeBranchNameForTag:d,isValidBranchForTag:f}=await import(`./git-utils-BezpEZd4.js`),p=a||{info:(...e)=>I(`info`,...e),warn:(...e)=>I(`warn`,...e),error:(...e)=>I(`error`,...e),debug:(...e)=>I(`debug`,...e),success:(...e)=>I(`success`,...e)};try{if(!t||typeof t!=`string`)throw Error(`Branch name is required and must be a string`);if(!f(t))throw Error(`Branch "${t}" cannot be converted to a valid tag name`);let n=d(t);p.info(`Creating tag "${n}" from git branch "${t}"`);let a=await Gn(e,n,{copyFromCurrent:s,copyFromTag:c,description:l||`Tag created from git branch "${t}"`},r,i);return await $n(o,t,n),p.info(`Updated branch-tag mapping: ${t} -> ${n}`),u&&(await Qn(o,n),p.info(`Automatically switched to tag "${n}"`)),i===`json`?{...a,branchName:t,tagName:n,mappingUpdated:!0,autoSwitched:u||!1}:{branchName:t,tagName:n,created:!0,mappingUpdated:!0,autoSwitched:u||!1}}catch(e){throw p.error(`Error creating tag from branch: ${e.message}`),e}}var tr=class e extends K{tmCore;lastResult;throwOnError=!1;constructor(e){super(e||`tags`),this.description(`Manage tags for task organization`).option(`--show-metadata`,`Show additional tag metadata`).option(`--ready`,`Show only tags with ready tasks available`),this.addListCommand(),this.addAddCommand(),this.addUseCommand(),this.addRemoveCommand(),this.addRenameCommand(),this.addCopyCommand(),this.action(async e=>{await this.executeList(e)})}addListCommand(){this.command(`list`).description(`List all tags with statistics (default action)`).option(`--show-metadata`,`Show additional tag metadata`).option(`--ready`,`Show only tags with ready tasks available`).addHelpText(`after`,`
|
|
99
|
+
This action cannot be undone!`,{padding:1,borderColor:`yellow`,borderStyle:`round`,margin:{top:1,bottom:1}})),!(await Ke.prompt([{type:`confirm`,name:`proceed`,message:`Are you sure you want to delete tag "${t}" and its ${l} tasks?`,default:!1}])).proceed)throw c.info(`Tag deletion cancelled by user`),Error(`Tag deletion cancelled`);if((await Ke.prompt([{type:`input`,name:`tagNameConfirm`,message:`To confirm deletion, please type the tag name "${t}":`,validate:e=>e===t||`Please type exactly "${t}" to confirm deletion`}])).tagNameConfirm!==t)throw c.info(`Tag deletion cancelled - incorrect tag name confirmation`),Error(`Tag deletion cancelled`);c.info(`Double confirmation received, proceeding with deletion...`)}delete r[t],a&&(await nr(o,`master`),c.info(`Switched current tag to "master"`));let u={};for(let[e,t]of Object.entries(r))e!==`_rawTaggedData`&&(u[e]=t);return F(e,u,o),c.success(`Successfully deleted tag "${t}"`),i===`json`||i===`text`&&console.log(G(V.red.bold(`✓ Tag Deleted Successfully`)+`\n\nTag Name: ${V.cyan(t)}\nTasks Deleted: ${V.yellow(l)}`+(a?`\n${V.yellow(`⚠ Switched current tag to "master"`)}`:``),{padding:1,borderColor:`red`,borderStyle:`round`,margin:{top:1,bottom:1}})),{tagName:t,deleted:!0,tasksDeleted:l,wasCurrentTag:a,switchedToMaster:a}}catch(e){throw c.error(`Error deleting tag: ${e.message}`),e}}async function Zn(e,t,n={}){let r=!1;try{let i;try{let t=W.statSync(e);i=t.birthtime<t.mtime?t.birthtime:t.mtime}catch{i=/* @__PURE__ */ new Date}for(let[e,n]of Object.entries(t))e!==`tasks`&&e!==`tag`&&e!==`_rawTaggedData`&&n&&typeof n==`object`&&Array.isArray(n.tasks)&&(n.metadata||(n.metadata={},r=!0),n.metadata.created||(n.metadata.created=i.toISOString(),r=!0),n.metadata.description||(e===`master`?n.metadata.description=`Tasks live here by default`:n.metadata.description=`Tag created on ${new Date(n.metadata.created).toLocaleDateString()}`,r=!0),n.metadata.updated||(n.metadata.updated=n.metadata.created,r=!0));if(r){let r={};for(let[e,n]of Object.entries(t))e!==`_rawTaggedData`&&(r[e]=n);F(e,r,n.projectRoot)}}catch(e){(n.mcpLog||{warn:(...e)=>I(`warn`,...e)}).warn(`Could not enhance tag metadata: ${e.message}`)}return r}async function Qn(e,t={},n={},r=`text`){let{mcpLog:i,projectRoot:a}=n,{showTaskCounts:o=!0,showMetadata:s=!1,ready:c=!1}=t,l=i||{info:(...e)=>I(`info`,...e),warn:(...e)=>I(`warn`,...e),error:(...e)=>I(`error`,...e),debug:(...e)=>I(`debug`,...e),success:(...e)=>I(`success`,...e)};try{l.info(`Listing available tags`),l.info(`Using file storage for tags`);let t=P(e,a);if(!t)throw Error(`Could not read tasks file at ${e}`);let i=M(a),u=t._rawTaggedData||t;await Zn(e,u,n);let d=[];for(let[e,t]of Object.entries(u)){if(e===`tasks`||e===`tag`||e===`_rawTaggedData`||!t||typeof t!=`object`||!Array.isArray(t.tasks))continue;let n=t.tasks||[],r=t.metadata||{},a=n.map(e=>({...e,blocks:[]})),o=_(a);d.push({name:e,isCurrent:e===i,completedTasks:n.filter(e=>p(e.status)).length,readyTasks:o.length,tasks:n||[],created:r.created||`Unknown`,description:r.description||`No description`})}d.sort((e,t)=>e.isCurrent?-1:t.isCurrent?1:e.name.localeCompare(t.name));let f=d;if(c&&(f=d.filter(e=>e.readyTasks>0),l.info(`Filtered to ${f.length} tags with ready tasks`)),l.success(`Found ${f.length} tags`),r===`json`)return{tags:f,currentTag:i,totalTags:f.length};if(r===`text`){if(f.length===0){let e=c?`No tags with ready tasks found`:`No tags found`;return console.log(G(V.yellow(e),{padding:1,borderColor:`yellow`,borderStyle:`round`,margin:{top:1,bottom:1}})),{tags:[],currentTag:i,totalTags:0}}let e=[V.cyan.bold(`Tag Name`)];o&&(e.push(V.cyan.bold(`Tasks`)),e.push(V.cyan.bold(`Ready`)),e.push(V.cyan.bold(`Done`))),s&&(e.push(V.cyan.bold(`Created`)),e.push(V.cyan.bold(`Description`)));let t=Math.max(process.stdout.columns||120,80),n=Math.floor(t*.95),r;r=s?[.22,.08,.08,.08,.14,.38].map((e,t)=>Math.max(Math.floor(n*e),t===0?15:6)):[.6,.13,.13,.13].map((e,t)=>Math.max(Math.floor(n*e),t===0?20:8));let a=new q({head:e,colWidths:r,wordWrap:!0,style:{border:le}});f.forEach(e=>{let t=[],n=e.isCurrent?`${V.green(`●`)} ${V.green.bold(e.name)} ${B.muted(`(current)`)}`:` ${e.name}`;if(t.push(n),o&&(t.push(B.text(e.tasks.length.toString())),t.push(e.readyTasks>0?V.yellow(e.readyTasks.toString()):B.muted(`0`)),t.push(V.green(e.completedTasks.toString()))),s){let n=e.created===`Unknown`?`Unknown`:new Date(e.created).toLocaleDateString();t.push(B.muted(n)),t.push(B.muted(R(e.description,50)))}a.push(t)}),console.log(a.toString())}return{tags:f,currentTag:i,totalTags:f.length}}catch(e){throw l.error(`Error listing tags: ${e.message}`),e}}async function $n(e,t,n={},r={},i=`text`){let{mcpLog:a,projectRoot:o}=r,s=a||{info:(...e)=>I(`info`,...e),warn:(...e)=>I(`warn`,...e),error:(...e)=>I(`error`,...e),debug:(...e)=>I(`debug`,...e),success:(...e)=>I(`success`,...e)};try{if(!t||typeof t!=`string`)throw Error(`Tag name is required and must be a string`);s.info(`Switching to tag: ${t}`),s.info(`Using file storage for tag switch`);let n=P(e,o);if(!n)throw Error(`Could not read tasks file at ${e}`);if(!(n._rawTaggedData||n)[t])throw Error(`Tag "${t}" does not exist`);let r=M(o);await nr(o,t);let a=P(e,o,t),c=a&&a.tasks||[],l=c.length,u=Jn(c);if(s.success(`Successfully switched to tag "${t}"`),i===`json`)return{previousTag:r,currentTag:t,switched:!0,taskCount:l,nextTask:u};if(i===`text`){let e=``;e=u?`\nNext Task: ${V.cyan(`#${u.id}`)} - ${B.text(u.title)}`:`\nNext Task: ${B.muted(`No eligible tasks available`)}`,console.log(G(V.green.bold(`✓ Tag Switched Successfully`)+`\n\nPrevious Tag: ${V.cyan(r)}\nCurrent Tag: ${V.green.bold(t)}\nAvailable Tasks: ${V.yellow(l)}`+e,{padding:1,borderColor:`green`,borderStyle:`round`,margin:{top:1,bottom:1}}))}return{previousTag:r,currentTag:t,switched:!0,taskCount:l,nextTask:u}}catch(e){throw s.error(`Error switching tag: ${e.message}`),e}}async function er(e,t,n,r={},i={},a=`text`){let{mcpLog:o,projectRoot:s}=i,c=o||{info:(...e)=>I(`info`,...e),warn:(...e)=>I(`warn`,...e),error:(...e)=>I(`error`,...e),debug:(...e)=>I(`debug`,...e),success:(...e)=>I(`success`,...e)};try{if(!t||typeof t!=`string`)throw Error(`Old tag name is required and must be a string`);if(!n||typeof n!=`string`)throw Error(`New tag name is required and must be a string`);if(!/^[a-zA-Z0-9_-]+$/.test(n))throw Error(`New tag name can only contain letters, numbers, hyphens, and underscores`);if(t===`master`)throw Error(`Cannot rename the "master" tag`);if([`master`,`main`,`default`].includes(n.toLowerCase()))throw Error(`"${n}" is a reserved tag name`);c.info(`Renaming tag from "${t}" to "${n}"`);let r=P(e,s);if(!r)throw Error(`Could not read tasks file at ${e}`);let i=r._rawTaggedData||r;if(!i[t])throw Error(`Tag "${t}" does not exist`);if(i[n])throw Error(`Tag "${n}" already exists`);let o=M(s)===t;i[n]={...i[t]},i[n].metadata&&(i[n].metadata.renamed={from:t,date:(/* @__PURE__ */ new Date()).toISOString()}),delete i[t],o&&(await nr(s,n),c.info(`Updated current tag reference to "${n}"`));let l={};for(let[e,t]of Object.entries(i))e!==`_rawTaggedData`&&(l[e]=t);F(e,l,s);let u=C(i,n).length;return c.success(`Successfully renamed tag from "${t}" to "${n}"`),a===`json`||a===`text`&&console.log(G(V.green.bold(`✓ Tag Renamed Successfully`)+`\n\nOld Name: ${V.cyan(t)}\nNew Name: ${V.green.bold(n)}\nTasks: ${V.yellow(u)}`+(o?`\n${V.green(`✓ Current tag updated`)}`:``),{padding:1,borderColor:`green`,borderStyle:`round`,margin:{top:1,bottom:1}})),{oldName:t,newName:n,renamed:!0,taskCount:u,wasCurrentTag:o,isCurrentTag:o}}catch(e){throw c.error(`Error renaming tag: ${e.message}`),e}}async function tr(e,t,n,r={},i={},a=`text`){let{mcpLog:o,projectRoot:s}=i,{description:c}=r,l=o||{info:(...e)=>I(`info`,...e),warn:(...e)=>I(`warn`,...e),error:(...e)=>I(`error`,...e),debug:(...e)=>I(`debug`,...e),success:(...e)=>I(`success`,...e)};try{if(!t||typeof t!=`string`)throw Error(`Source tag name is required and must be a string`);if(!n||typeof n!=`string`)throw Error(`Target tag name is required and must be a string`);if(!/^[a-zA-Z0-9_-]+$/.test(n))throw Error(`Target tag name can only contain letters, numbers, hyphens, and underscores`);if([`master`,`main`,`default`].includes(n.toLowerCase()))throw Error(`"${n}" is a reserved tag name`);l.info(`Copying tag from "${t}" to "${n}"`);let r=P(e,s);if(!r)throw Error(`Could not read tasks file at ${e}`);let i=r._rawTaggedData||r;if(!i[t])throw Error(`Source tag "${t}" does not exist`);if(i[n])throw Error(`Target tag "${n}" already exists`);let o=C(i,t);i[n]={tasks:JSON.parse(JSON.stringify(o)),metadata:{created:(/* @__PURE__ */ new Date()).toISOString(),updated:(/* @__PURE__ */ new Date()).toISOString(),description:c||`Copy of "${t}" created on ${(/* @__PURE__ */ new Date()).toLocaleDateString()}`,copiedFrom:{tag:t,date:(/* @__PURE__ */ new Date()).toISOString()}}};let u={};for(let[e,t]of Object.entries(i))e!==`_rawTaggedData`&&(u[e]=t);return F(e,u,s),l.success(`Successfully copied tag from "${t}" to "${n}"`),a===`json`||a===`text`&&console.log(G(V.green.bold(`✓ Tag Copied Successfully`)+`\n\nSource Tag: ${V.cyan(t)}\nTarget Tag: ${V.green.bold(n)}\nTasks Copied: ${V.yellow(o.length)}`+(c?`\nDescription: ${B.muted(c)}`:``),{padding:1,borderColor:`green`,borderStyle:`round`,margin:{top:1,bottom:1}})),{sourceName:t,targetName:n,copied:!0,description:c||`Copy of "${t}" created on ${(/* @__PURE__ */ new Date()).toLocaleDateString()}`}}catch(e){throw l.error(`Error copying tag: ${e.message}`),e}}async function nr(e,t){try{let n=H.join(e,`.taskgraph`,`state.json`),r={};if(W.existsSync(n)){let e=W.readFileSync(n,`utf8`);r=JSON.parse(e)}r.currentTag=t,r.lastSwitched=(/* @__PURE__ */ new Date()).toISOString(),r.branchTagMapping||(r.branchTagMapping={}),r.migrationNoticeShown===void 0&&(r.migrationNoticeShown=!1),W.writeFileSync(n,JSON.stringify(r,null,2),`utf8`)}catch(e){I(`warn`,`Could not update current tag in state.json: ${e.message}`)}}async function rr(e,t,n){try{let r=H.join(e,`.taskgraph`,`state.json`),i={};if(W.existsSync(r)){let e=W.readFileSync(r,`utf8`);i=JSON.parse(e)}i.branchTagMapping||(i.branchTagMapping={}),i.branchTagMapping[t]=n,W.writeFileSync(r,JSON.stringify(i,null,2),`utf8`)}catch(e){I(`warn`,`Could not update branch-tag mapping: ${e.message}`)}}async function ir(e,t,n={},r={},i=`text`){let{mcpLog:a,projectRoot:o}=r,{copyFromCurrent:s,copyFromTag:c,description:l,autoSwitch:u}=n,{sanitizeBranchNameForTag:d,isValidBranchForTag:f}=await import(`./git-utils-BezpEZd4.js`),p=a||{info:(...e)=>I(`info`,...e),warn:(...e)=>I(`warn`,...e),error:(...e)=>I(`error`,...e),debug:(...e)=>I(`debug`,...e),success:(...e)=>I(`success`,...e)};try{if(!t||typeof t!=`string`)throw Error(`Branch name is required and must be a string`);if(!f(t))throw Error(`Branch "${t}" cannot be converted to a valid tag name`);let n=d(t);p.info(`Creating tag "${n}" from git branch "${t}"`);let a=await Yn(e,n,{copyFromCurrent:s,copyFromTag:c,description:l||`Tag created from git branch "${t}"`},r,i);return await rr(o,t,n),p.info(`Updated branch-tag mapping: ${t} -> ${n}`),u&&(await nr(o,n),p.info(`Automatically switched to tag "${n}"`)),i===`json`?{...a,branchName:t,tagName:n,mappingUpdated:!0,autoSwitched:u||!1}:{branchName:t,tagName:n,created:!0,mappingUpdated:!0,autoSwitched:u||!1}}catch(e){throw p.error(`Error creating tag from branch: ${e.message}`),e}}var ar=class e extends K{tmCore;lastResult;throwOnError=!1;constructor(e){super(e||`tags`),this.description(`Manage tags for task organization`).option(`--show-metadata`,`Show additional tag metadata`).option(`--ready`,`Show only tags with ready tasks available`),this.addListCommand(),this.addAddCommand(),this.addUseCommand(),this.addRemoveCommand(),this.addRenameCommand(),this.addCopyCommand(),this.action(async e=>{await this.executeList(e)})}addListCommand(){this.command(`list`).description(`List all tags with statistics (default action)`).option(`--show-metadata`,`Show additional tag metadata`).option(`--ready`,`Show only tags with ready tasks available`).addHelpText(`after`,`
|
|
99
100
|
Examples:
|
|
100
101
|
$ tm tags # List all tags (default)
|
|
101
102
|
$ tm tags list # List all tags (explicit)
|
|
@@ -123,28 +124,37 @@ Examples:
|
|
|
123
124
|
Examples:
|
|
124
125
|
$ tm tags copy sprint-1 sprint-2
|
|
125
126
|
$ tm tags copy sprint-1 sprint-2 --description "Next sprint tasks"
|
|
126
|
-
`).action(async(e,t,n)=>{await this.executeCopy(e,t,n)})}async initTmCore(){this.tmCore||=await b({projectPath:process.cwd()})}async executeList(e){try{await this.initTmCore();let{projectRoot:t,tasksPath:n}=v(),r=await
|
|
127
|
+
`).action(async(e,t,n)=>{await this.executeCopy(e,t,n)})}async initTmCore(){this.tmCore||=await b({projectPath:process.cwd()})}async executeList(e){try{await this.initTmCore();let{projectRoot:t,tasksPath:n}=v(),r=await Qn(n,{showTaskCounts:!0,showMetadata:e?.showMetadata||!1,ready:e?.ready||!1},{projectRoot:t},`text`);this.setLastResult({success:!0,action:`list`,tags:r.tags,currentTag:r.currentTag,message:`Found ${r.totalTags} tag(s)`})}catch(e){Y(e),this.setLastResult({success:!1,action:`list`,message:e.message}),this.handleError(e instanceof Error?e:Error(e.message||String(e)))}}async executeAdd(e,t){try{await this.initTmCore();let{projectRoot:n,tasksPath:r}=v();await Yn(r,e,{description:t?.description,copyFromTag:t?.copyFrom,fromBranch:t?.fromBranch},{projectRoot:n},`text`),this.setLastResult({success:!0,action:`add`,message:`Created tag: ${e}`})}catch(e){Y(e),this.setLastResult({success:!1,action:`add`,message:e.message}),this.handleError(e instanceof Error?e:Error(e.message||String(e)))}}async executeUse(e){try{await this.initTmCore();let{projectRoot:t,tasksPath:n}=v(),r=await $n(n,e,{},{projectRoot:t},`text`);this.setLastResult({success:!0,action:`use`,currentTag:r.currentTag,message:`Switched to tag: ${e}`})}catch(e){Y(e),this.setLastResult({success:!1,action:`use`,message:e.message}),this.handleError(e instanceof Error?e:Error(e.message||String(e)))}}async executeRemove(e,t){try{await this.initTmCore();let{projectRoot:n,tasksPath:r}=v();await Xn(r,e,{yes:t?.yes||!1},{projectRoot:n},`text`),this.setLastResult({success:!0,action:`remove`,message:`Removed tag: ${e}`})}catch(e){Y(e),this.setLastResult({success:!1,action:`remove`,message:e.message}),this.handleError(e instanceof Error?e:Error(e.message||String(e)))}}async executeRename(e,t){try{await this.initTmCore();let{projectRoot:n,tasksPath:r}=v();await er(r,e,t,{},{projectRoot:n},`text`),this.setLastResult({success:!0,action:`rename`,message:`Renamed tag from "${e}" to "${t}"`})}catch(e){Y(e),this.setLastResult({success:!1,action:`rename`,message:e.message}),this.handleError(e instanceof Error?e:Error(e.message||String(e)))}}async executeCopy(e,t,n){try{await this.initTmCore();let{projectRoot:r,tasksPath:i}=v();await tr(i,e,t,{description:n?.description},{projectRoot:r},`text`),this.setLastResult({success:!0,action:`copy`,message:`Copied tag from "${e}" to "${t}"`})}catch(e){Y(e),this.setLastResult({success:!1,action:`copy`,message:e.message}),this.handleError(e instanceof Error?e:Error(e.message||String(e)))}}setLastResult(e){this.lastResult=e}getLastResult(){return this.lastResult}setThrowOnError(e){return this.throwOnError=e,this}handleError(e){if(this.throwOnError)throw e;process.exit(1)}static register(t,n){let r=new e(n);return t.addCommand(r),r}},or=class e extends K{tmCore;constructor(e){super(e||`loop`),this.description(`Run Claude Code in a loop, one task per iteration`).option(`-n, --iterations <number>`,`Maximum iterations`).option(`-p, --prompt <preset|path>`,`Preset name (${S.join(`, `)}) or path to custom prompt file`,`default`).option(`--progress-file <path>`,`Path to progress log file`,`.taskgraph/progress.txt`).option(`-t, --tag <tag>`,`Only work on tasks with this tag`).option(`--project <path>`,`Project root directory (auto-detected if not provided)`).option(`--sandbox`,`Run Claude in Docker sandbox mode`).option(`--no-output`,`Exclude full Claude output from iteration results`).option(`-v, --verbose`,`Show Claude's work in real-time`).action(e=>this.execute(e))}async execute(e){let t=e.prompt||`default`,n=e.progressFile||`.taskgraph/progress.txt`;try{let r=Ae.resolve(X(e.project));this.tmCore=await b({projectPath:r});let i=t==="default"?await this.tmCore.tasks.getCount(`pending`,e.tag):void 0,a=this.tmCore.loop.resolveIterations({userIterations:e.iterations?parseInt(e.iterations,10):void 0,preset:t,pendingTaskCount:i});if(this.validateIterations(String(a)),Tn({tag:e.tag||`master`}),e.sandbox&&this.handleSandboxAuth(),console.log(V.cyan(`Starting TaskGraph Loop...`)),console.log(V.dim(`Preset: ${t}`)),console.log(V.dim(`Max iterations: ${a}`)),console.log(V.dim(`Mode: ${e.sandbox?`Docker sandbox`:`Claude CLI`}`)),t==="default"){let t=await this.tmCore.tasks.getNext(e.tag);console.log(t?B.text(`Next task to work on: ${B.text(t.id)} - ${t.title}`):V.yellow(`No pending tasks found`))}console.log();let o={iterations:a,prompt:t,progressFile:n,tag:e.tag,sandbox:e.sandbox,includeOutput:e.output??!0,verbose:e.verbose??!1,callbacks:this.createOutputCallbacks()},s=await this.tmCore.loop.run(o);this.displayResult(s)}catch(e){Y(e,{skipExit:!0}),process.exit(1)}}handleSandboxAuth(){console.log(V.dim(`Checking sandbox auth...`));let e=this.tmCore.loop.checkSandboxAuth();if(e.error)throw Error(e.error);if(e.ready){console.log(V.green(`✓ Sandbox ready`));return}console.log(V.yellow(`Sandbox needs authentication. Starting interactive session...`)),console.log(V.dim(`Please complete auth, then Ctrl+C to continue.
|
|
127
128
|
`));let t=this.tmCore.loop.runInteractiveAuth();if(!t.success)throw Error(t.error||`Interactive authentication failed`);console.log(V.green(`✓ Auth complete
|
|
128
|
-
`))}validateIterations(e){let t=Number(e);if(!Number.isInteger(t)||t<1)throw Error(`Invalid iterations: ${e}. Must be a positive integer.`)}createOutputCallbacks(){return{onIterationStart:(e,t)=>{console.log(),console.log(V.cyan(`━━━ Iteration ${e} of ${t} ━━━`))},onText:e=>{console.log(e)},onToolUse:e=>{console.log(V.dim(` → ${e}`))},onError:(e,t)=>{console.error(t===`warning`?V.yellow(`[Loop Warning] ${e}`):V.red(`[Loop Error] ${e}`))},onStderr:(e,t)=>{process.stderr.write(V.dim(`[Iteration ${e}] `)+t)},onOutput:e=>{console.log(e)},onIterationEnd:e=>{let t=e.status===`success`?V.green:e.status===`error`?V.red:V.yellow;console.log(t(` Iteration ${e.iteration} completed: ${e.status}`))}}}displayResult(e){console.log(),console.log(V.bold(`Loop Complete`)),console.log(V.dim(`─`.repeat(40))),console.log(`Total iterations: ${e.totalIterations}`),console.log(`Tasks completed: ${e.tasksCompleted}`),console.log(`Final status: ${this.formatStatus(e.finalStatus)}`),e.errorMessage&&console.log(V.red(`Error: ${e.errorMessage}`))}formatStatus(e){return{all_complete:V.green(`All tasks complete`),max_iterations:V.yellow(`Max iterations reached`),blocked:V.red(`Blocked`),error:V.red(`Error`)}[e]}static register(t,n){let r=new e(n);return t.addCommand(r),r}},
|
|
129
|
-
`)[0],subtask:{id:i.currentSubtask.id,title:i.currentSubtask.title},progress:h.progress,nextAction:g?`All subtasks complete. Run: autopilot status`:`Start next subtask with RED phase`})}catch(e){r.error(e.message),n.verbose&&console.error(e.stack),process.exit(1)}}},or=class extends K{constructor(){super(`complete`),this.description(`Complete the current TDD phase with result validation`).option(`-r, --results <json>`,`Test results JSON (with total, passed, failed, skipped)`).option(`-c, --coverage <percent>`,`Coverage percentage`).action(async e=>{await this.execute(e)})}async execute(e){let t=this.parent?.opts(),n={...t,...e,projectRoot:Cn(e.projectRoot||t?.projectRoot)},r=new rr(n.json||!1);try{let e=n.projectRoot,t=await b({projectPath:e});await t.workflow.hasWorkflow()||(r.error(`No active workflow`,{suggestion:`Start a workflow with: autopilot start <taskId>`}),process.exit(1)),await t.workflow.resume();let i=t.workflow.getStatus(),a=i.tddPhase,o=i.currentSubtask;if(a||(r.error(`Not in a TDD phase`,{phase:i.phase}),process.exit(1)),a===`RED`||a===`GREEN`){n.results||(r.error(`Test results required for RED/GREEN phase`,{usage:`--results '{"total":10,"passed":9,"failed":1,"skipped":0}'`}),process.exit(1));let e;try{let t=JSON.parse(n.results);e={total:t.total||0,passed:t.passed||0,failed:t.failed||0,skipped:t.skipped||0,phase:a}}catch(e){r.error(`Invalid test results JSON`,{error:e.message}),process.exit(1)}a===`RED`&&e.failed===0&&(r.error(`RED phase validation failed`,{reason:`At least one test must be failing`,actual:{passed:e.passed,failed:e.failed}}),process.exit(1)),a===`GREEN`&&e.failed!==0&&(r.error(`GREEN phase validation failed`,{reason:`All tests must pass`,actual:{passed:e.passed,failed:e.failed}}),process.exit(1));let i=await t.workflow.completePhase(e);a===`RED`?r.success(`RED phase completed`,{nextPhase:i.tddPhase||`GREEN`,testResults:e,subtask:o?.title}):r.success(`GREEN phase completed`,{nextPhase:i.tddPhase||`COMMIT`,testResults:e,subtask:o?.title,suggestion:`Run: autopilot commit`})}else a===`COMMIT`&&(r.error(`Use "autopilot commit" to complete COMMIT phase`),process.exit(1))}catch(e){r.error(e.message),n.verbose&&console.error(e.stack),process.exit(1)}}},sr=class extends K{constructor(){super(`finalize`),this.description(`Finalize and complete the workflow. Validates working tree is clean.`).action(async e=>{await this.execute(e)})}async execute(e){let t=this.parent?.opts(),n={...t,...e,projectRoot:``},r=new rr(e.json||t?.json||!1);try{let i=Cn(e.projectRoot||t?.projectRoot);n={...n,projectRoot:i};let a=await b({projectPath:i});await a.workflow.hasWorkflow()||(r.error(`No active workflow`,{suggestion:`Start a workflow with: autopilot start <taskId>`}),process.exit(1)),await a.workflow.resume();let o=a.workflow.getStatus();o.phase!==`FINALIZE`&&(r.error(`Cannot finalize: workflow is in ${o.phase} phase`,{suggestion:`Complete all subtasks first`}),process.exit(1)),r.info(`Validating working tree and finalizing workflow...`);let s=await a.workflow.finalize();r.success(`Workflow completed`,{taskId:s.taskId,phase:s.phase,branchName:s.branchName,progress:s.progress})}catch(e){r.error(e.message),n.verbose&&console.error(e.stack),process.exit(1)}}},cr=class extends K{constructor(){super(`next`),this.description(`Get the next action to perform in the TDD workflow`).action(async e=>{await this.execute(e)})}async execute(e){let t=this.parent?.opts(),n={...t,...e,projectRoot:``},r=new rr(e.json||t?.json||!1);try{let i=Cn(e.projectRoot||t?.projectRoot);n={...n,projectRoot:i};let a=await b({projectPath:i});await a.workflow.hasWorkflow()||(r.error(`No active workflow`,{suggestion:`Start a workflow with: autopilot start <taskId>`}),process.exit(1)),await a.workflow.resume();let o=a.workflow.getStatus(),s=a.workflow.getNextAction(),c=a.workflow.getContext(),l=o.phase,u=o.tddPhase,d=o.currentSubtask;if(l===`COMPLETE`){r.success(`Workflow complete`,{message:`All subtasks have been completed`,taskId:o.taskId});return}let f={action:s.action,description:s.description,phase:l,tddPhase:u,taskId:o.taskId,branchName:o.branchName,subtask:d?{id:d.id,title:d.title,attempts:d.attempts}:null,nextSteps:s.nextSteps,lastTestResults:c.lastTestResults};n.json?r.output(f):r.success(`Next action`,f)}catch(e){r.error(e.message),n.verbose&&console.error(e.stack),process.exit(1)}}},lr=class extends K{constructor(){super(`resume`),this.description(`Resume a previously started TDD workflow`).action(async e=>{await this.execute(e)})}async execute(e){let t=this.parent?.opts(),n={...t,...e,projectRoot:Cn(e.projectRoot||t?.projectRoot)},r=new rr(n.json||!1);try{let e=n.projectRoot,t=await b({projectPath:e});await t.workflow.hasWorkflow()||(r.error(`No workflow state found`,{suggestion:`Start a new workflow with: autopilot start <taskId>`}),process.exit(1)),r.info(`Loading workflow state...`);let i=await t.workflow.resume();r.success(`Workflow resumed`,{taskId:i.taskId,phase:i.phase,tddPhase:i.tddPhase,branchName:i.branchName,progress:i.progress,currentSubtask:i.currentSubtask?{id:i.currentSubtask.id,title:i.currentSubtask.title,attempts:i.currentSubtask.attempts}:null})}catch(e){r.error(e.message),n.verbose&&console.error(e.stack),process.exit(1)}}},ur=class extends K{constructor(){super(`start`),this.description(`Initialize and start a new TDD workflow for a task`).argument(`<taskId>`,`Task ID to start workflow for`).option(`-f, --force`,`Force start even if workflow state exists`).option(`--max-attempts <number>`,`Maximum attempts per subtask`,`3`).action(async(e,t)=>{await this.execute(e,t)})}async execute(e,t){let n=this.parent?.opts(),r={...n,...t,projectRoot:Cn(t.projectRoot||n?.projectRoot)},i=new rr(r.json||!1);try{let t=f.safeParse(e);t.success||(i.error(`Invalid task ID format`,{taskId:e,error:t.error.issues[0]?.message}),process.exit(1));let n=t.data,a=r.projectRoot,o=await b({projectPath:a});await o.workflow.hasWorkflow()&&!r.force&&(i.error(`Workflow state already exists. Use --force to overwrite or resume with "autopilot resume"`),process.exit(1));let s=o.config.getActiveTag();i.info(`Loading task ${n}...`);let{task:c}=await o.tasks.get(n);c||(i.error(`Task not found`,{taskId:n}),process.exit(1)),(!c.subtasks||c.subtasks.length===0)&&(i.error(`Task has no subtasks. Expand task first.`,{taskId:n,suggestion:`Run: taskgraph expand --id=${n}`}),process.exit(1));let l=parseInt(r.maxAttempts||`3`,10);i.info(`Starting TDD workflow...`);let u=await o.workflow.start({taskId:n,taskTitle:c.title,subtasks:c.subtasks.map(e=>({id:e.id,title:e.title,status:e.status,maxAttempts:l})),maxAttempts:l,force:r.force,tag:s});i.success(`TDD workflow started`,{taskId:u.taskId,title:c.title,phase:u.phase,tddPhase:u.tddPhase,branchName:u.branchName,subtasks:c.subtasks.length,currentSubtask:u.currentSubtask?.title})}catch(e){i.error(e.message),r.verbose&&console.error(e.stack),process.exit(1)}}},dr=class extends K{constructor(){super(`status`),this.description(`Show current TDD workflow status and progress`).action(async e=>{await this.execute(e)})}async execute(e){let t=this.parent?.opts(),n={...t,...e,projectRoot:Cn(e.projectRoot||t?.projectRoot)},r=new rr(n.json||!1);try{let e=n.projectRoot,t=await b({projectPath:e});if(!await t.workflow.hasWorkflow()){n.json?r.output({active:!1,message:`No active workflow`}):(r.info(`No active workflow`),console.log(`Start a workflow with: autopilot start <taskId>`));return}await t.workflow.resume();let i=t.workflow.getStatus(),a=t.workflow.getContext(),o={taskId:i.taskId,phase:i.phase,tddPhase:i.tddPhase,branchName:i.branchName,progress:i.progress,currentSubtask:i.currentSubtask?{id:i.currentSubtask.id,title:i.currentSubtask.title,attempts:i.currentSubtask.attempts,maxAttempts:i.currentSubtask.maxAttempts}:null,subtasks:a.subtasks.map(e=>({id:e.id,title:e.title,status:e.status,attempts:e.attempts})),errors:a.errors&&a.errors.length>0?a.errors:void 0,metadata:a.metadata};n.json?r.output(o):r.success(`Workflow status`,o)}catch(e){r.error(e.message),n.verbose&&console.error(e.stack),process.exit(1)}}},fr=class e extends K{constructor(){super(`autopilot`),this.description(`AI agent orchestration for TDD workflow execution`).alias(`ap`).option(`--json`,`Output in JSON format for machine parsing`).option(`-v, --verbose`,`Enable verbose output`).option(`-p, --project-root <path>`,`Project root directory (auto-detected if not specified)`),this.registerSubcommands()}registerSubcommands(){this.addCommand(new ur),this.addCommand(new lr),this.addCommand(new cr),this.addCommand(new or),this.addCommand(new ar),this.addCommand(new dr),this.addCommand(new sr),this.addCommand(new ir)}static register(t){let n=new e;return t.addCommand(n),n}},pr=class e extends K{tmCore;lastResult;constructor(e){super(e||`generate`),this.description(`Generate individual task files from tasks.json`).option(`-t, --tag <tag>`,`Tag context for task operations`).option(`-o, --output <dir>`,`Output directory for generated files (defaults to .taskgraph/tasks)`).option(`-p, --project <path>`,`Project root directory (auto-detected if not provided)`).option(`-f, --format <format>`,`Output format (text, json)`,`text`).action(async e=>{await this.executeCommand(e)})}async executeCommand(e){let t=!1;try{this.validateOptions(e);let t=Cn(e.project);await this.initializeCore(t);let n=await this.generateFiles(t,e);this.lastResult=n,this.displayResults(n,e)}catch(e){t=!0,Y(e,{skipExit:!0})}finally{await this.cleanup()}t&&process.exit(1)}validateOptions(e){if(e.format&&![`text`,`json`].includes(e.format))throw Error(`Invalid format: ${e.format}. Valid formats are: text, json`)}async initializeCore(e){if(!this.tmCore){let t=Ae.resolve(e);this.tmCore=await b({projectPath:t})}}async generateFiles(e,t){if(!this.tmCore)throw Error(`TmCore not initialized`);let n=t.output?Ae.resolve(e,t.output):void 0;return this.tmCore.tasks.generateTaskFiles({tag:t.tag,outputDir:n})}displayResults(e,t){switch(t.format||`text`){case`json`:this.displayJson(e);break;default:this.displayText(e,t)}}displayJson(e){console.log(JSON.stringify(e,null,2))}displayText(e,t){if(this.tmCore&&xn({tag:t.tag||this.tmCore.config.getActiveTag()}),!e.success){console.log(G(V.red(`Error: ${e.error||`Unknown error`}`),{padding:1,borderStyle:`round`,borderColor:`red`,title:`Generation failed`,titleAlignment:`center`}));return}if(e.count===0){console.log(G(V.yellow(`No tasks found to generate files for.`),{padding:1,borderStyle:`round`,borderColor:`yellow`,title:`No tasks`,titleAlignment:`center`}));return}let n=`${V.green(`✓`)} Generated ${V.cyan(e.count)} task file(s)`;n+=`\n\n${V.dim(`Output directory:`)} ${e.directory}`,e.orphanedFilesRemoved>0&&(n+=`\n${V.dim(`Orphaned files removed:`)} ${e.orphanedFilesRemoved}`),console.log(G(n,{padding:1,borderStyle:`round`,borderColor:`green`,title:`Task files generated`,titleAlignment:`center`}))}getLastResult(){return this.lastResult}async cleanup(){this.tmCore&&=void 0}static register(t,n){let r=new e(n);return t.addCommand(r),r}};const mr={create:V.green,update:V.yellow,skip:B.muted,close:V.red};function hr(e){let t={create:0,update:0,skip:0,close:0};for(let n of e.steps)t[n.action]++;return t}function gr(e){let t=hr(e);return t.create+t.update+t.close>0}function _r(e){let t=mr[e.action](e.action.padEnd(6)),n=e.issueNumber?` -> #${e.issueNumber}`:``,r=e.reason?B.muted(` (${e.reason})`):``;return` ${t} [${e.tag}] ${e.taskId} ${e.title}${n}${r}`}function vr(e){let t=hr(e),n=[V.bold(`Plan for ${e.repo}`),` ${t.create} to create, ${t.update} to update, ${t.skip} unchanged, ${t.close} to close`];for(let t of e.steps.filter(e=>e.action!==`skip`))n.push(_r(t));if(e.orphans.length>0){n.push(``,V.yellow(`${e.orphans.length} open issue(s) have no local task (pass --close-orphans to close them):`));for(let t of e.orphans)n.push(` #${t.issueNumber} ${t.title}`)}return n.join(`
|
|
130
|
-
`)}function
|
|
131
|
-
`)}function
|
|
132
|
-
`)}function
|
|
133
|
-
`)}
|
|
129
|
+
`))}validateIterations(e){let t=Number(e);if(!Number.isInteger(t)||t<1)throw Error(`Invalid iterations: ${e}. Must be a positive integer.`)}createOutputCallbacks(){return{onIterationStart:(e,t)=>{console.log(),console.log(V.cyan(`━━━ Iteration ${e} of ${t} ━━━`))},onText:e=>{console.log(e)},onToolUse:e=>{console.log(V.dim(` → ${e}`))},onError:(e,t)=>{console.error(t===`warning`?V.yellow(`[Loop Warning] ${e}`):V.red(`[Loop Error] ${e}`))},onStderr:(e,t)=>{process.stderr.write(V.dim(`[Iteration ${e}] `)+t)},onOutput:e=>{console.log(e)},onIterationEnd:e=>{let t=e.status===`success`?V.green:e.status===`error`?V.red:V.yellow;console.log(t(` Iteration ${e.iteration} completed: ${e.status}`))}}}displayResult(e){console.log(),console.log(V.bold(`Loop Complete`)),console.log(V.dim(`─`.repeat(40))),console.log(`Total iterations: ${e.totalIterations}`),console.log(`Tasks completed: ${e.tasksCompleted}`),console.log(`Final status: ${this.formatStatus(e.finalStatus)}`),e.errorMessage&&console.log(V.red(`Error: ${e.errorMessage}`))}formatStatus(e){return{all_complete:V.green(`All tasks complete`),max_iterations:V.yellow(`Max iterations reached`),blocked:V.red(`Blocked`),error:V.red(`Error`)}[e]}static register(t,n){let r=new e(n);return t.addCommand(r),r}},sr=class{useJson;constructor(e){this.useJson=e}output(e){this.useJson?console.log(JSON.stringify(e,null,2)):this.outputText(e)}outputText(e){for(let[t,n]of Object.entries(e))typeof n==`object`&&n?(console.log(V.cyan(`${t}:`)),this.outputObject(n,` `)):console.log(B.text(`${t}: ${n}`))}outputObject(e,t){for(let[n,r]of Object.entries(e))typeof r==`object`&&r?(console.log(V.cyan(`${t}${n}:`)),this.outputObject(r,t+` `)):console.log(B.muted(`${t}${n}: ${r}`))}error(e,t){if(this.useJson)console.error(JSON.stringify({error:e,...t},null,2));else if(console.error(V.red(`Error: ${e}`)),t)for(let[e,n]of Object.entries(t))console.error(B.muted(` ${e}: ${n}`))}success(e,t){this.useJson?console.log(JSON.stringify({success:!0,message:e,...t},null,2)):(console.log(V.green(`✓ ${e}`)),t&&this.output(t))}warning(e){this.useJson?console.warn(JSON.stringify({warning:e},null,2)):console.warn(V.yellow(`⚠ ${e}`))}info(e){this.useJson||console.log(B.brand(`ℹ ${e}`))}},cr=class extends K{constructor(){super(`abort`),this.description(`Abort the current TDD workflow and clean up state`).option(`-f, --force`,`Force abort without confirmation`).action(async e=>{await this.execute(e)})}async execute(e){let t=this.parent?.opts(),n={...t,...e,projectRoot:``},r=new sr(e.json||t?.json||!1);try{let i=X(e.projectRoot||t?.projectRoot);n={...n,projectRoot:i};let a=await b({projectPath:i});if(!await a.workflow.hasWorkflow()){r.warning(`No active workflow to abort`);return}await a.workflow.resume();let o=a.workflow.getStatus();if(!n.force&&!n.json){let{confirmed:e}=await Ke.prompt([{type:`confirm`,name:`confirmed`,message:`This will abort the workflow for task ${o.taskId}. Progress: ${o.progress?.completed||0}/${o.progress?.total||0} subtasks completed. Continue?`,default:!1}]);if(!e){r.info(`Abort cancelled`);return}}await a.workflow.abort(),r.success(`Workflow aborted`,{taskId:o.taskId,branchName:o.branchName,progress:o.progress,lastSubtask:o.currentSubtask?{id:o.currentSubtask.id,title:o.currentSubtask.title}:null,note:`Branch and commits remain. Clean up manually if needed.`})}catch(e){r.error(e.message),n.verbose&&console.error(e.stack),process.exit(1)}}},lr=class extends K{constructor(){super(`commit`),this.description(`Create a commit for the completed GREEN phase`).action(async e=>{await this.execute(e)})}async execute(e){let t=this.parent?.opts(),n={...t,...e,projectRoot:X(e.projectRoot||t?.projectRoot)},r=new sr(n.json||!1);try{let e=n.projectRoot,t=await b({projectPath:e});await t.workflow.hasWorkflow()||(r.error(`No active workflow`,{suggestion:`Start a workflow with: autopilot start <taskId>`}),process.exit(1)),await t.workflow.resume();let i=t.workflow.getStatus(),s=t.workflow.getContext();i.tddPhase!==`COMMIT`&&(r.error(`Not in COMMIT phase`,{currentPhase:i.tddPhase||i.phase,suggestion:`Complete RED and GREEN phases first`}),process.exit(1)),i.currentSubtask||(r.error(`No current subtask`),process.exit(1));let c=new a(e);await c.ensureGitRepository(),await c.hasStagedChanges()||(r.info(`No staged changes, staging all changes...`),await c.stageFiles([`.`]));let l=await c.getStatus(),u=[...l.staged,...l.modified],d=new o,f=s.lastTestResults,p=d.generateMessage({type:`feat`,description:i.currentSubtask.title,changedFiles:u,taskId:i.taskId,phase:i.tddPhase,tag:s.metadata.tag||void 0,testsPassing:f?.passed,testsFailing:f?.failed,coveragePercent:void 0});await c.createCommit(p,{metadata:{taskId:i.taskId,subtaskId:i.currentSubtask.id,phase:`COMMIT`,tddCycle:`complete`}});let m=await c.getLastCommit(),h=await t.workflow.commit(),g=h.phase===`COMPLETE`;r.success(`Commit created`,{commitHash:m.hash.substring(0,7),message:p.split(`
|
|
130
|
+
`)[0],subtask:{id:i.currentSubtask.id,title:i.currentSubtask.title},progress:h.progress,nextAction:g?`All subtasks complete. Run: autopilot status`:`Start next subtask with RED phase`})}catch(e){r.error(e.message),n.verbose&&console.error(e.stack),process.exit(1)}}},ur=class extends K{constructor(){super(`complete`),this.description(`Complete the current TDD phase with result validation`).option(`-r, --results <json>`,`Test results JSON (with total, passed, failed, skipped)`).option(`-c, --coverage <percent>`,`Coverage percentage`).action(async e=>{await this.execute(e)})}async execute(e){let t=this.parent?.opts(),n={...t,...e,projectRoot:X(e.projectRoot||t?.projectRoot)},r=new sr(n.json||!1);try{let e=n.projectRoot,t=await b({projectPath:e});await t.workflow.hasWorkflow()||(r.error(`No active workflow`,{suggestion:`Start a workflow with: autopilot start <taskId>`}),process.exit(1)),await t.workflow.resume();let i=t.workflow.getStatus(),a=i.tddPhase,o=i.currentSubtask;if(a||(r.error(`Not in a TDD phase`,{phase:i.phase}),process.exit(1)),a===`RED`||a===`GREEN`){n.results||(r.error(`Test results required for RED/GREEN phase`,{usage:`--results '{"total":10,"passed":9,"failed":1,"skipped":0}'`}),process.exit(1));let e;try{let t=JSON.parse(n.results);e={total:t.total||0,passed:t.passed||0,failed:t.failed||0,skipped:t.skipped||0,phase:a}}catch(e){r.error(`Invalid test results JSON`,{error:e.message}),process.exit(1)}a===`RED`&&e.failed===0&&(r.error(`RED phase validation failed`,{reason:`At least one test must be failing`,actual:{passed:e.passed,failed:e.failed}}),process.exit(1)),a===`GREEN`&&e.failed!==0&&(r.error(`GREEN phase validation failed`,{reason:`All tests must pass`,actual:{passed:e.passed,failed:e.failed}}),process.exit(1));let i=await t.workflow.completePhase(e);a===`RED`?r.success(`RED phase completed`,{nextPhase:i.tddPhase||`GREEN`,testResults:e,subtask:o?.title}):r.success(`GREEN phase completed`,{nextPhase:i.tddPhase||`COMMIT`,testResults:e,subtask:o?.title,suggestion:`Run: autopilot commit`})}else a===`COMMIT`&&(r.error(`Use "autopilot commit" to complete COMMIT phase`),process.exit(1))}catch(e){r.error(e.message),n.verbose&&console.error(e.stack),process.exit(1)}}},dr=class extends K{constructor(){super(`finalize`),this.description(`Finalize and complete the workflow. Validates working tree is clean.`).action(async e=>{await this.execute(e)})}async execute(e){let t=this.parent?.opts(),n={...t,...e,projectRoot:``},r=new sr(e.json||t?.json||!1);try{let i=X(e.projectRoot||t?.projectRoot);n={...n,projectRoot:i};let a=await b({projectPath:i});await a.workflow.hasWorkflow()||(r.error(`No active workflow`,{suggestion:`Start a workflow with: autopilot start <taskId>`}),process.exit(1)),await a.workflow.resume();let o=a.workflow.getStatus();o.phase!==`FINALIZE`&&(r.error(`Cannot finalize: workflow is in ${o.phase} phase`,{suggestion:`Complete all subtasks first`}),process.exit(1)),r.info(`Validating working tree and finalizing workflow...`);let s=await a.workflow.finalize();r.success(`Workflow completed`,{taskId:s.taskId,phase:s.phase,branchName:s.branchName,progress:s.progress})}catch(e){r.error(e.message),n.verbose&&console.error(e.stack),process.exit(1)}}},fr=class extends K{constructor(){super(`next`),this.description(`Get the next action to perform in the TDD workflow`).action(async e=>{await this.execute(e)})}async execute(e){let t=this.parent?.opts(),n={...t,...e,projectRoot:``},r=new sr(e.json||t?.json||!1);try{let i=X(e.projectRoot||t?.projectRoot);n={...n,projectRoot:i};let a=await b({projectPath:i});await a.workflow.hasWorkflow()||(r.error(`No active workflow`,{suggestion:`Start a workflow with: autopilot start <taskId>`}),process.exit(1)),await a.workflow.resume();let o=a.workflow.getStatus(),s=a.workflow.getNextAction(),c=a.workflow.getContext(),l=o.phase,u=o.tddPhase,d=o.currentSubtask;if(l===`COMPLETE`){r.success(`Workflow complete`,{message:`All subtasks have been completed`,taskId:o.taskId});return}let f={action:s.action,description:s.description,phase:l,tddPhase:u,taskId:o.taskId,branchName:o.branchName,subtask:d?{id:d.id,title:d.title,attempts:d.attempts}:null,nextSteps:s.nextSteps,lastTestResults:c.lastTestResults};n.json?r.output(f):r.success(`Next action`,f)}catch(e){r.error(e.message),n.verbose&&console.error(e.stack),process.exit(1)}}},pr=class extends K{constructor(){super(`resume`),this.description(`Resume a previously started TDD workflow`).action(async e=>{await this.execute(e)})}async execute(e){let t=this.parent?.opts(),n={...t,...e,projectRoot:X(e.projectRoot||t?.projectRoot)},r=new sr(n.json||!1);try{let e=n.projectRoot,t=await b({projectPath:e});await t.workflow.hasWorkflow()||(r.error(`No workflow state found`,{suggestion:`Start a new workflow with: autopilot start <taskId>`}),process.exit(1)),r.info(`Loading workflow state...`);let i=await t.workflow.resume();r.success(`Workflow resumed`,{taskId:i.taskId,phase:i.phase,tddPhase:i.tddPhase,branchName:i.branchName,progress:i.progress,currentSubtask:i.currentSubtask?{id:i.currentSubtask.id,title:i.currentSubtask.title,attempts:i.currentSubtask.attempts}:null})}catch(e){r.error(e.message),n.verbose&&console.error(e.stack),process.exit(1)}}},mr=class extends K{constructor(){super(`start`),this.description(`Initialize and start a new TDD workflow for a task`).argument(`<taskId>`,`Task ID to start workflow for`).option(`-f, --force`,`Force start even if workflow state exists`).option(`--max-attempts <number>`,`Maximum attempts per subtask`,`3`).action(async(e,t)=>{await this.execute(e,t)})}async execute(e,t){let n=this.parent?.opts(),r={...n,...t,projectRoot:X(t.projectRoot||n?.projectRoot)},i=new sr(r.json||!1);try{let t=f.safeParse(e);t.success||(i.error(`Invalid task ID format`,{taskId:e,error:t.error.issues[0]?.message}),process.exit(1));let n=t.data,a=r.projectRoot,o=await b({projectPath:a});await o.workflow.hasWorkflow()&&!r.force&&(i.error(`Workflow state already exists. Use --force to overwrite or resume with "autopilot resume"`),process.exit(1));let s=o.config.getActiveTag();i.info(`Loading task ${n}...`);let{task:c}=await o.tasks.get(n);c||(i.error(`Task not found`,{taskId:n}),process.exit(1)),(!c.subtasks||c.subtasks.length===0)&&(i.error(`Task has no subtasks. Expand task first.`,{taskId:n,suggestion:`Run: taskgraph expand --id=${n}`}),process.exit(1));let l=parseInt(r.maxAttempts||`3`,10);i.info(`Starting TDD workflow...`);let u=await o.workflow.start({taskId:n,taskTitle:c.title,subtasks:c.subtasks.map(e=>({id:e.id,title:e.title,status:e.status,maxAttempts:l})),maxAttempts:l,force:r.force,tag:s});i.success(`TDD workflow started`,{taskId:u.taskId,title:c.title,phase:u.phase,tddPhase:u.tddPhase,branchName:u.branchName,subtasks:c.subtasks.length,currentSubtask:u.currentSubtask?.title})}catch(e){i.error(e.message),r.verbose&&console.error(e.stack),process.exit(1)}}},hr=class extends K{constructor(){super(`status`),this.description(`Show current TDD workflow status and progress`).action(async e=>{await this.execute(e)})}async execute(e){let t=this.parent?.opts(),n={...t,...e,projectRoot:X(e.projectRoot||t?.projectRoot)},r=new sr(n.json||!1);try{let e=n.projectRoot,t=await b({projectPath:e});if(!await t.workflow.hasWorkflow()){n.json?r.output({active:!1,message:`No active workflow`}):(r.info(`No active workflow`),console.log(`Start a workflow with: autopilot start <taskId>`));return}await t.workflow.resume();let i=t.workflow.getStatus(),a=t.workflow.getContext(),o={taskId:i.taskId,phase:i.phase,tddPhase:i.tddPhase,branchName:i.branchName,progress:i.progress,currentSubtask:i.currentSubtask?{id:i.currentSubtask.id,title:i.currentSubtask.title,attempts:i.currentSubtask.attempts,maxAttempts:i.currentSubtask.maxAttempts}:null,subtasks:a.subtasks.map(e=>({id:e.id,title:e.title,status:e.status,attempts:e.attempts})),errors:a.errors&&a.errors.length>0?a.errors:void 0,metadata:a.metadata};n.json?r.output(o):r.success(`Workflow status`,o)}catch(e){r.error(e.message),n.verbose&&console.error(e.stack),process.exit(1)}}},gr=class e extends K{constructor(){super(`autopilot`),this.description(`AI agent orchestration for TDD workflow execution`).alias(`ap`).option(`--json`,`Output in JSON format for machine parsing`).option(`-v, --verbose`,`Enable verbose output`).option(`-p, --project-root <path>`,`Project root directory (auto-detected if not specified)`),this.registerSubcommands()}registerSubcommands(){this.addCommand(new mr),this.addCommand(new pr),this.addCommand(new fr),this.addCommand(new ur),this.addCommand(new lr),this.addCommand(new hr),this.addCommand(new dr),this.addCommand(new cr)}static register(t){let n=new e;return t.addCommand(n),n}},_r=class e extends K{tmCore;lastResult;constructor(e){super(e||`generate`),this.description(`Generate individual task files from tasks.json`).option(`-t, --tag <tag>`,`Tag context for task operations`).option(`-o, --output <dir>`,`Output directory for generated files (defaults to .taskgraph/tasks)`).option(`-p, --project <path>`,`Project root directory (auto-detected if not provided)`).option(`-f, --format <format>`,`Output format (text, json)`,`text`).action(async e=>{await this.executeCommand(e)})}async executeCommand(e){let t=!1;try{this.validateOptions(e);let t=X(e.project);await this.initializeCore(t);let n=await this.generateFiles(t,e);this.lastResult=n,this.displayResults(n,e)}catch(e){t=!0,Y(e,{skipExit:!0})}finally{await this.cleanup()}t&&process.exit(1)}validateOptions(e){if(e.format&&![`text`,`json`].includes(e.format))throw Error(`Invalid format: ${e.format}. Valid formats are: text, json`)}async initializeCore(e){if(!this.tmCore){let t=Ae.resolve(e);this.tmCore=await b({projectPath:t})}}async generateFiles(e,t){if(!this.tmCore)throw Error(`TmCore not initialized`);let n=t.output?Ae.resolve(e,t.output):void 0;return this.tmCore.tasks.generateTaskFiles({tag:t.tag,outputDir:n})}displayResults(e,t){switch(t.format||`text`){case`json`:this.displayJson(e);break;default:this.displayText(e,t)}}displayJson(e){console.log(JSON.stringify(e,null,2))}displayText(e,t){if(this.tmCore&&Tn({tag:t.tag||this.tmCore.config.getActiveTag()}),!e.success){console.log(G(V.red(`Error: ${e.error||`Unknown error`}`),{padding:1,borderStyle:`round`,borderColor:`red`,title:`Generation failed`,titleAlignment:`center`}));return}if(e.count===0){console.log(G(V.yellow(`No tasks found to generate files for.`),{padding:1,borderStyle:`round`,borderColor:`yellow`,title:`No tasks`,titleAlignment:`center`}));return}let n=`${V.green(`✓`)} Generated ${V.cyan(e.count)} task file(s)`;n+=`\n\n${V.dim(`Output directory:`)} ${e.directory}`,e.orphanedFilesRemoved>0&&(n+=`\n${V.dim(`Orphaned files removed:`)} ${e.orphanedFilesRemoved}`),console.log(G(n,{padding:1,borderStyle:`round`,borderColor:`green`,title:`Task files generated`,titleAlignment:`center`}))}getLastResult(){return this.lastResult}async cleanup(){this.tmCore&&=void 0}static register(t,n){let r=new e(n);return t.addCommand(r),r}};const vr={create:V.green,update:V.yellow,skip:B.muted,close:V.red};function yr(e){let t={create:0,update:0,skip:0,close:0};for(let n of e.steps)t[n.action]++;return t}function br(e){let t=yr(e);return t.create+t.update+t.close>0}function xr(e){let t=vr[e.action](e.action.padEnd(6)),n=e.issueNumber?` -> #${e.issueNumber}`:``,r=e.reason?B.muted(` (${e.reason})`):``;return` ${t} [${e.tag}] ${e.taskId} ${e.title}${n}${r}`}function Sr(e){let t=yr(e),n=[V.bold(`Plan for ${e.repo}`),` ${t.create} to create, ${t.update} to update, ${t.skip} unchanged, ${t.close} to close`];for(let t of e.steps.filter(e=>e.action!==`skip`))n.push(xr(t));if(e.orphans.length>0){n.push(``,V.yellow(`${e.orphans.length} open issue(s) have no local task (pass --close-orphans to close them):`));for(let t of e.orphans)n.push(` #${t.issueNumber} ${t.title}`)}return n.join(`
|
|
131
|
+
`)}function Cr(e){let t=e.dryRun?`would be `:``;return[V.bold(e.dryRun?`Dry run, nothing written`:`Push complete`),` ${t}created ${e.created}, ${t}updated ${e.updated}, unchanged ${e.skipped}, ${t}closed ${e.closed}`].join(`
|
|
132
|
+
`)}const wr={apply:V.green,sync:B.muted,conflict:V.red,skip:B.muted};function Tr(e){let t={apply:0,sync:0,conflict:0,skip:0};for(let n of e.steps)t[n.action]++;return t}function Er(e){let t=Tr(e);return t.apply+t.sync>0}function Dr(e){return Tr(e).apply>0}function Or(e){let t=wr[e.action](e.action.padEnd(8)),n=e.action===`conflict`?`local ${e.from}, GitHub ${e.to}`:`${e.from} -> ${e.to}`,r=e.issueNumber?` (#${e.issueNumber})`:``;return` ${t} [${e.tag}] ${e.taskId} ${e.title}${r} ${B.muted(n)}`}function kr(e){let t=Tr(e),n=[V.bold(`Pull plan for ${e.repo}`),` ${t.apply} to update, ${t.sync} already in sync, ${t.conflict} conflict(s), ${t.skip} unchanged or skipped`];for(let t of e.steps.filter(e=>e.action!==`skip`))n.push(Or(t));return t.conflict>0&&n.push(``,V.yellow(`${t.conflict} task(s) changed on both sides and keep their local status. Run \`taskgraph github push\` to overwrite GitHub with it.`)),n.join(`
|
|
133
|
+
`)}function Ar(e){let t=e.dryRun?`would be `:``;return[V.bold(e.dryRun?`Dry run, nothing written`:`Pull complete`),` ${t}updated ${e.applied}, ${t}marked in sync ${e.synced}, conflicts ${e.conflicts}, skipped ${e.skipped}`].join(`
|
|
134
|
+
`)}function jr(e){let t=e.ghAvailable?V.green(`available and signed in`):V.red("not available (install gh and run `gh auth login`)");return[V.bold(`GitHub`),` gh CLI: ${t}`,` repo: ${e.repo??B.muted(`not detected (use --repo owner/name)`)}`,` linked: ${e.linkedTasks} task(s)`,` unlinked: ${e.unlinkedTasks} task(s)`].join(`
|
|
135
|
+
`)}function Mr(e){return[`Unlinked task ${e.taskId} [${e.tag}] from issue #${e.issueNumber} (${e.url}).`,B.muted(`The issue was not changed. If it still carries its taskgraph marker, the next push will link it again.`)].join(`
|
|
136
|
+
`)}var Nr=class extends K{tmCore;constructor(e){super(e||`github`),this.description(`Push tasks to GitHub Issues and pull issue status back`),this.addStatusCommand(),this.addPushCommand(),this.addPullCommand(),this.addUnlinkCommand()}addStatusCommand(){this.command(`status`).description(`Show gh availability, target repo and linked task counts`).option(`--repo <owner/name>`,`Repository to check`).option(`-p, --project <path>`,`Project root directory`).option(`--json`,`Output as JSON`).action(e=>this.guard(e,()=>this.runStatus(e)))}addPushCommand(){this.command(`push`).description(`Create or update GitHub issues for tasks`).option(`--tag <name>`,`Tag to push (default: the active tag)`).option(`--all-tags`,`Push every tag`).option(`--id <ids>`,`Only push these task ids, comma separated`).option(`--dry-run`,`Show the plan without writing anything`).option(`-y, --yes`,`Write without asking for confirmation`).option(`--repo <owner/name>`,`Repository (default: detected via gh)`).option(`--include-details`,`Include task details in issue bodies`).option(`--close-orphans`,`Close open issues whose task is gone`).option(`-p, --project <path>`,`Project root directory`).option(`--json`,`Output as JSON (requires --yes or --dry-run)`).addHelpText(`after`,`
|
|
134
137
|
Examples:
|
|
135
138
|
$ taskgraph github push --dry-run # Preview the active tag
|
|
136
139
|
$ taskgraph github push --all-tags -y # Push every tag without asking
|
|
137
140
|
$ taskgraph github push --id 1,2 # Push only tasks 1 and 2
|
|
138
|
-
`).action(e=>this.guard(e,()=>this.runPush(e)))}
|
|
141
|
+
`).action(e=>this.guard(e,()=>this.runPush(e)))}addPullCommand(){this.command(`pull`).description(`Update task statuses from their GitHub issues (status only, never writes to GitHub)`).option(`--tag <name>`,`Tag to pull (default: the active tag)`).option(`--all-tags`,`Pull every tag`).option(`--id <ids>`,`Only pull these task ids, comma separated`).option(`--dry-run`,`Show the plan without changing any task`).option(`-y, --yes`,`Update tasks without asking for confirmation`).option(`--repo <owner/name>`,`Repository (default: detected via gh)`).option(`-p, --project <path>`,`Project root directory`).option(`--json`,`Output as JSON (requires --yes or --dry-run)`).addHelpText(`after`,`
|
|
142
|
+
A task that changed on GitHub and not locally takes the issue's status.
|
|
143
|
+
A task that changed on both sides keeps its local status and is reported.
|
|
139
144
|
|
|
140
|
-
|
|
145
|
+
Examples:
|
|
146
|
+
$ taskgraph github pull --dry-run # Preview the active tag
|
|
147
|
+
$ taskgraph github pull -y # Update tasks without asking
|
|
148
|
+
`).action(e=>this.guard(e,()=>this.runPull(e)))}addUnlinkCommand(){this.command(`unlink`).description(`Forget the GitHub issue a task is linked to`).argument(`<id>`,`Task id`).option(`--tag <name>`,`Tag the task lives in`).option(`-p, --project <path>`,`Project root directory`).option(`--json`,`Output as JSON`).action((e,t)=>this.guard(t,()=>this.runUnlink(e,t)))}async guard(e,t){let n=!1;try{await this.initializeCore(e),await t()}catch(e){n=!0,Y(e,{skipExit:!0})}finally{await this.tmCore?.close()}n&&process.exit(1)}async initializeCore(e){if(!this.tmCore){let t=Ae.resolve(X(e.project));this.tmCore=await b({projectPath:t})}}core(){if(!this.tmCore)throw Error(`TmCore not initialized`);return this.tmCore}async runStatus(e){let t=await this.core().github.status({repo:e.repo});console.log(e.json?JSON.stringify(t,null,2):jr(t))}async runPush(e){let t=this.core(),n={repo:e.repo,tag:e.tag,allTags:e.allTags,taskIds:e.id,includeDetails:e.includeDetails,closeOrphans:e.closeOrphans};if(e.dryRun){let r=await t.github.push({...n,dryRun:!0});this.print(e,r,[Sr(r.plan),Cr(r)]);return}let r=await t.github.planPush(n);if(!br(r)){let i=await t.github.push({...n,dryRun:!0});this.print(e,{...i,dryRun:!1},[Sr(r),`GitHub is already up to date.`]);return}if(!e.yes){if(e.json||!this.isInteractive())throw Error(`Refusing to write to GitHub without confirmation. Pass --yes to proceed or --dry-run to preview.`);if(console.log(Sr(r)),!await this.confirm(`Write these changes to ${r.repo}?`)){console.log(`Cancelled. Nothing was written.`);return}}let i=await t.github.push({...n,dryRun:!1});this.print(e,i,[...e.yes?[Sr(i.plan)]:[],Cr(i)])}async runPull(e){let t=this.core(),n={repo:e.repo,tag:e.tag,allTags:e.allTags,taskIds:e.id};if(e.dryRun){let r=await t.github.pull({...n,dryRun:!0});this.print(e,r,[kr(r.plan),Ar(r)]);return}let r=await t.github.planPull(n);if(!Er(r)){let i=await t.github.pull({...n,dryRun:!0});this.print(e,{...i,dryRun:!1},[kr(r),`Task statuses are already up to date.`]);return}if(Dr(r)&&!e.yes){if(e.json||!this.isInteractive())throw Error(`Refusing to change tasks without confirmation. Pass --yes to proceed or --dry-run to preview.`);if(console.log(kr(r)),!await this.confirm(`Update these task statuses?`)){console.log(`Cancelled. Nothing was changed.`);return}}let i=await t.github.pull({...n,dryRun:!1});this.print(e,i,[...e.yes?[kr(i.plan)]:[],Ar(i)])}async runUnlink(e,t){let n=await this.core().github.unlink(e,{tag:t.tag});console.log(t.json?JSON.stringify(n,null,2):Mr(n))}print(e,t,n){console.log(e.json?JSON.stringify(t,null,2):n.join(`
|
|
149
|
+
|
|
150
|
+
`))}isInteractive(){return!!(process.stdin.isTTY&&process.stdout.isTTY)}async confirm(e){let{proceed:t}=await Ke.prompt([{type:`confirm`,name:`proceed`,message:e,default:!1}]);return t}},Pr=class{static commands=[{name:`list`,description:`List all tasks with filtering and status overview`,commandClass:Dn,category:`task`},{name:`show`,description:`Display detailed information about a specific task`,commandClass:On,category:`task`},{name:`next`,description:`Find the next available task to work on`,commandClass:kn,category:`task`},{name:`graph`,description:`Show tasks as a dependency tree`,commandClass:An,category:`task`},{name:`start`,description:`Start working on a task with claude-code`,commandClass:jn,category:`task`},{name:`set-status`,description:`Update the status of one or more tasks`,commandClass:Nn,category:`task`},{name:`autopilot`,description:`AI agent orchestration for TDD workflow (start, resume, next, complete, commit, status, abort)`,commandClass:gr,category:`development`},{name:`loop`,description:`Run Claude Code in a loop, one task per iteration`,commandClass:or,category:`development`},{name:`tags`,description:`Manage tags for task organization`,commandClass:ar,category:`task`},{name:`generate`,description:`Generate individual task files from tasks.json`,commandClass:_r,category:`utility`},{name:`github`,description:`Push tasks to GitHub Issues (status, push, unlink)`,commandClass:Nr,category:`utility`}];static registerAll(e){for(let t of this.commands)this.registerCommand(e,t)}static registerByCategory(e,t){let n=this.commands.filter(e=>e.category===t);for(let t of n)this.registerCommand(e,t)}static registerByName(e,t){let n=this.commands.find(e=>e.name===t);if(n)this.registerCommand(e,n);else throw Error(`Command '${t}' not found in registry`)}static registerCommand(e,t){let n=t.commandClass;if(n.registerOn)n.registerOn(e);else if(n.register)n.register(e);else{let t=new n;e.addCommand(t)}}static getCommandNames(){return this.commands.map(e=>e.name)}static getCommandsByCategory(e){return this.commands.filter(t=>t.category===e)}static addCommand(e){if(this.commands.some(t=>t.name===e.name))throw Error(`Command '${e.name}' already exists in registry`);this.commands.push(e)}static removeCommand(e){let t=this.commands.findIndex(t=>t.name===e);return t>=0&&(this.commands.splice(t,1),!0)}static getCommand(e){return this.commands.find(t=>t.name===e)}static hasCommand(e){return this.commands.some(t=>t.name===e)}static getFormattedCommandList(){let e={task:`Task Management`,utility:`Utilities`,development:`Development`},t=``;for(let[n,r]of Object.entries(e)){let e=this.getCommandsByCategory(n);if(e.length>0){t+=`\n${r}:\n`;for(let n of e)t+=` ${n.name.padEnd(20)} ${n.description}\n`}}return t}};function Fr(e){Pr.registerAll(e)}const Ir=[`main`,`research`,`fallback`];function Lr(e){if(!e)throw Error(`Project root is required but not found.`);let t=te(null,{projectRoot:e}),n=re(e);if(I(`debug`,`Checking for config file using findConfigPath, found: ${t}`),I(`debug`,`Checking config file using isConfigFilePresent(), exists: ${n}`),!n)throw Error(`The configuration file is missing. Run "taskgraph init" to create it.`)}function Rr(e){return(t,...n)=>{e&&typeof e[t]==`function`&&e[t](...n)}}async function zr(e={}){let{mcpLog:t,projectRoot:n}=e,r=Rr(t);Lr(n);try{let e=ye(n),t=(t,n)=>{let r=e.find(e=>e.id===n&&e.provider===t);return{provider:t,modelId:n,sweScore:r?.swe_score||null,cost:r?.cost_per_1m_tokens||null}},r=de(n);return{success:!0,data:{activeModels:{main:t(ve(n),xe(n)),research:t(Oe(n),Ee(n)),fallback:r?t(r,Te(n)):null},message:`Successfully retrieved current model configuration`}}}catch(e){return r(`error`,`Error getting model configuration: ${e.message}`),{success:!1,error:{code:`CONFIG_ERROR`,message:e.message}}}}async function Br(e={}){let{mcpLog:t,projectRoot:n}=e,r=Rr(t);Lr(n);try{let e=ye(n).map(e=>({provider:e.provider||`N/A`,modelId:e.id,sweScore:e.swe_score||null,cost:e.cost_per_1m_tokens||null,allowedRoles:e.allowed_roles||[]}));return{success:!0,data:{models:e,message:e.length?`Successfully retrieved ${e.length} available models`:`No available models found`}}}catch(e){return r(`error`,`Error getting available models: ${e.message}`),{success:!1,error:{code:`MODELS_LIST_ERROR`,message:e.message}}}}async function Vr(e,t,n={}){let{mcpLog:r,projectRoot:i}=n,a=Rr(r);if(Lr(i),!Ir.includes(e))return{success:!1,error:{code:`INVALID_ROLE`,message:`Invalid role: ${e}. Must be one of: ${Ir.join(`, `)}.`}};if(typeof t!=`string`||t.trim()===``)return{success:!1,error:{code:`INVALID_MODEL_ID`,message:`Invalid model ID: ${t}. Must be a non-empty string.`}};try{let n=d.CLAUDE_CODE,r=ye(i).filter(e=>e.provider===n),o=r.find(e=>e.id===t);if(!o)return{success:!1,error:{code:`MODEL_NOT_FOUND`,message:`Model ID "${t}" is not supported. TaskGraph uses Claude Code; valid models: ${r.map(e=>e.id).join(`, `)}.`}};let s=ce(i);if(s.models[e]={...s.models[e],provider:n,modelId:t},delete s.models[e].baseURL,o.max_tokens&&(s.models[e].maxTokens=o.max_tokens),!w(s,i))return{success:!1,error:{code:`CONFIG_WRITE_ERROR`,message:`Error writing updated configuration to configuration file`}};let c=`Successfully set ${e} model to ${t} (Provider: ${n})`;return a(`info`,c),{success:!0,data:{role:e,provider:n,modelId:t,message:c}}}catch(t){return a(`error`,`Error setting ${e} model: ${t.message}`),{success:!1,error:{code:`SET_MODEL_ERROR`,message:t.message}}}}async function Hr(e){return zr(e)}async function Ur(e,t,n){return Vr(e,t,n)}function Wr(){return ye()}function Gr(e,t,n=!1){let r=t[e],i=Wr().filter(e=>!!e.provider).reduce((e,t)=>(e[t.provider]||(e[t.provider]=[]),e[t.provider].push(t),e),{}),a=[],o={name:`⏹ Cancel Model Setup`,value:`__CANCEL__`,short:`Cancel`},s=r?.modelId&&r?.provider?{name:`✓ No change to current ${e} model (${r.provider}/${r.modelId})`,value:`__NO_CHANGE__`,short:`No change`}:null;s&&a.push(s),a.push(o);let c=Object.entries(i).flatMap(([t,n])=>n.filter(t=>t.allowed_roles&&t.allowed_roles.includes(e)).map(e=>{let n=e.name||e.id;return{name:`${t} / ${n} ${e.cost_per_1m_tokens?B.muted(`($${e.cost_per_1m_tokens.input.toFixed(2)} input | $${e.cost_per_1m_tokens.output.toFixed(2)} output)`):``}`,value:{id:e.id,provider:t},short:`${t}/${n}`}})).filter(e=>e!==null),l=-1;r?.modelId&&r?.provider&&(l=c.findIndex(e=>typeof e.value==`object`&&e.value!==null&&`id`in e.value&&e.value.id===r.modelId&&e.value.provider===r.provider));let u=a.length,d,f;if(n){d=[...a,new Je(`
|
|
141
151
|
── Claude Code Models ──`),{name:`○ None (disable)`,value:null,short:`None`},...c];let e=u+1;f=l===-1?e:l+u+2}else d=[...a,new Je(`
|
|
142
|
-
── Claude Code Models ──`),...c],f=l===-1?+!!s:l+u+1;return(f<0||f>=d.length)&&(f=0,console.warn(`Warning: Could not determine default model for role '${e}'. Defaulting to 'Cancel'.`)),{choices:d,default:f}}function
|
|
152
|
+
── Claude Code Models ──`),...c],f=l===-1?+!!s:l+u+1;return(f<0||f>=d.length)&&(f=0,console.warn(`Warning: Could not determine default model for role '${e}'. Defaulting to 'Cancel'.`)),{choices:d,default:f}}function Kr(e,t){return(t=``)=>{let n=e.filter(e=>{if(e instanceof Je)return!0;let n=e;return`${n.name||``} ${typeof n.value==`object`&&n.value!==null&&`id`in n.value?n.value.id:``}`.toLowerCase().includes(t.toLowerCase())});return Promise.resolve(n.map(e=>{if(e instanceof Je)return e;let t=e;return{name:t.name,value:t.value,short:t.short}}))}}function qr(){console.log(V.cyan(`
|
|
143
153
|
Interactive model setup`)),console.log(B.muted(`━`.repeat(50))),console.log(V.yellow(`Navigation tips:`)),console.log(B.muted(` • Type to search and filter options`)),console.log(B.muted(` • Use ↑↓ arrow keys to navigate results`)),console.log(B.muted(` • Press Enter to select
|
|
144
|
-
`))}async function
|
|
154
|
+
`))}async function Jr(e,t){return await qe({message:`Select the ${{main:`main model for generation/updates`,research:`research model`,fallback:`fallback model (optional)`}[e]}:`,source:Kr(t.choices,t.default),pageSize:15})}async function Yr(e,t,n,r){let i=n?.modelId??null,a=n?.provider??null;if(t===`__CANCEL__`)return console.log(V.yellow(`\nSetup canceled during ${e} model selection.`)),{success:!1,modified:!1};if(t===`__NO_CHANGE__`)return console.log(B.muted(`No change selected for ${e} model.`)),{success:!0,modified:!1};let o=null,s=null;if(t&&typeof t==`object`&&`id`in t)o=t.id,s=t.provider;else if(t)return console.error(V.red(`Internal Error: Unexpected selection value for ${e}: ${JSON.stringify(t)}`)),{success:!1,modified:!1};if(o===i&&(s??null)===a)return{success:!0,modified:!1};if(o){let t=await Ur(e,o,{projectRoot:r,providerHint:s||void 0});return t.success?(console.log(B.brand(`Set ${e} model: ${t.data?.provider} / ${t.data?.modelId}`)),{success:!0,modified:!0}):(console.error(V.red(`Error setting ${e} model: ${t.error?.message||`Unknown`}`)),{success:!1,modified:!1})}return{success:!0,modified:!1}}async function Xr(e){e||(console.error(V.red(`Error: Could not determine project root for interactive setup.`)),process.exit(1));let t=await Hr({projectRoot:e}),n=t.success&&t.data?{main:t.data.activeModels.main?{modelId:t.data.activeModels.main.modelId,provider:t.data.activeModels.main.provider}:null,research:t.data.activeModels.research?{modelId:t.data.activeModels.research.modelId,provider:t.data.activeModels.research.provider}:null,fallback:t.data.activeModels.fallback?{modelId:t.data.activeModels.fallback.modelId,provider:t.data.activeModels.fallback.provider}:null}:{main:null,research:null,fallback:null};!t.success&&t.error?.code!==`CONFIG_MISSING`&&console.warn(V.yellow(`Warning: Could not load current model configuration: ${t.error?.message||`Unknown error`}. Proceeding with defaults.`));let r=Gr(`main`,n),i=Gr(`research`,n),a=Gr(`fallback`,n);qr();let o=await Jr(`main`,r);if(o===`__CANCEL__`)return!1;let s=await Jr(`research`,i);if(s===`__CANCEL__`)return!1;let c=await Jr(`fallback`,a);if(c===`__CANCEL__`)return!1;let l=!0,u=!1,d=await Yr(`main`,o,n.main,e);d.success||(l=!1),d.modified&&(u=!0);let f=await Yr(`research`,s,n.research,e);f.success||(l=!1),f.modified&&(u=!0);let p=await Yr(`fallback`,c,n.fallback,e);return p.success||(l=!1),p.modified&&(u=!0),l&&u?console.log(V.green.bold(`
|
|
145
155
|
Model setup complete!`)):l&&!u?console.log(V.yellow(`
|
|
146
156
|
No changes made to model configuration.`)):console.error(V.red(`
|
|
147
|
-
Errors occurred during model selection. Please review and try again.`)),l}const
|
|
157
|
+
Errors occurred during model selection. Please review and try again.`)),l}const Zr=[`pending`,`done`,`in-progress`,`review`,`deferred`,`cancelled`];function Qr(e){return Zr.includes(e)}function $r(){return x||`unknown`}async function ei(e,t,n=null,r=null,i=!1,a={}){let{projectRoot:o,tag:s}=a;try{I(`info`,`Adding subtask to parent task ${t}...`);let i=P(e,o,s);if(!i||!i.tasks)throw Error(`Invalid or missing tasks file at ${e}`);let a=parseInt(t,10),c=i.tasks.find(e=>e.id===a);if(!c)throw Error(`Parent task with ID ${a} not found`);c.subtasks||=[];let l;if(n!==null){let e=parseInt(n,10),t=i.tasks.findIndex(t=>t.id===e);if(t===-1)throw Error(`Task with ID ${e} not found`);let r=i.tasks[t];if(r.parentTaskId)throw Error(`Task ${e} is already a subtask of task ${r.parentTaskId}`);if(e===a)throw Error(`Cannot make a task a subtask of itself`);if(Hi(i.tasks,c,e))throw Error(`Cannot create circular dependency: task ${a} is already a subtask or dependent of task ${e}`);let o=(c.subtasks.length>0?Math.max(...c.subtasks.map(e=>e.id)):0)+1;l={...r,id:o,parentTaskId:a},c.subtasks.push(l),i.tasks.splice(t,1),I(`info`,`Converted task ${e} to subtask ${a}.${o}`)}else if(r){let e=(c.subtasks.length>0?Math.max(...c.subtasks.map(e=>e.id)):0)+1;l={id:e,title:r.title,description:r.description||``,details:r.details||``,status:r.status||`pending`,dependencies:r.dependencies||[],parentTaskId:a},c.subtasks.push(l),I(`info`,`Created new subtask ${a}.${e}`)}else throw Error(`Either existingTaskId or newSubtaskData must be provided`);return F(e,i,o,s),l}catch(e){throw I(`error`,`Error adding subtask: ${e.message}`),e}}const ti=[`high`,`medium`,`low`],ni=`medium`;function ri(e){return ti.includes(e?.toLowerCase())}function ii(e){if(!e)return null;let t=e.toLowerCase();return ri(t)?t:null}const ai=U.object({title:U.string().describe(`Clear, concise title for the task`),description:U.string().describe(`A one or two sentence description of the task`),details:U.string().describe(`In-depth implementation details, considerations, and guidance`),testStrategy:U.string().describe(`Detailed approach for verifying task completion`),dependencies:U.array(U.number()).nullable().describe(`Array of task IDs that this task depends on (must be completed before this task can start)`)}).strict(),oi=U.object({taskId:U.number().int().positive(),taskTitle:U.string(),complexityScore:U.number().min(1).max(10),recommendedSubtasks:U.number().int().nonnegative(),expansionPrompt:U.string(),reasoning:U.string()}).strict(),si=U.object({complexityAnalysis:U.array(oi)}).strict(),ci=U.enum([`pending`,`in-progress`,`blocked`,`done`,`cancelled`,`deferred`]),li=U.object({id:U.number().int().positive(),title:U.string().min(1).max(200),description:U.string().min(1),status:ci,dependencies:U.array(U.union([U.number().int().positive(),U.string()])),priority:U.enum([`low`,`medium`,`high`,`critical`]).nullable(),details:U.string().nullable(),testStrategy:U.string().nullable()}).strict(),ui=U.object({id:U.number().int().positive(),title:U.string().min(5).max(200),description:U.string().min(10),dependencies:U.array(U.number().int().positive()),details:U.string().min(20),status:U.enum([`pending`,`done`,`completed`]),testStrategy:U.string().nullable()}).strict(),di=U.object({subtasks:U.array(ui)}).strict(),fi=U.object({id:U.number().int().positive(),title:U.string().min(1),description:U.string().min(1),details:U.string().nullable(),testStrategy:U.string().nullable(),priority:U.enum([`high`,`medium`,`low`]).nullable(),dependencies:U.array(U.number().int().positive()).nullable(),status:U.string().nullable()}).strict(),pi=U.object({tasks:U.array(fi)}).strict(),mi=U.object({subtask:ui}).strict(),hi=li.extend({subtasks:U.array(ui).nullable()}).strict(),gi={"update-tasks":U.object({tasks:U.array(hi)}).strict(),"expand-task":di,"analyze-complexity":si,"update-subtask-by-id":mi,"update-task-by-id":U.object({task:hi}),"add-task":ai,"parse-prd":pi};var _i={id:`add-task`,version:`1.0.0`,description:`Generate a new task based on description`,metadata:{author:`system`,created:`2024-01-01T00:00:00Z`,updated:`2024-01-01T00:00:00Z`,tags:[`task-creation`,`generation`]},parameters:{prompt:{type:`string`,required:!0,description:`User's task description`},newTaskId:{type:`number`,required:!0,description:`ID for the new task`},existingTasks:{type:`array`,description:`List of existing tasks for context`},gatheredContext:{type:`string`,description:`Context gathered from codebase analysis`},contextFromArgs:{type:`string`,description:`Additional context from manual args`},priority:{type:`string`,default:`medium`,enum:[`high`,`medium`,`low`],description:`Task priority`},dependencies:{type:`array`,description:`Task dependency IDs`},useResearch:{type:`boolean`,default:!1,description:`Use research mode`},hasCodebaseAnalysis:{type:`boolean`,required:!1,default:!1,description:`Whether codebase analysis is available`},projectRoot:{type:`string`,required:!1,default:``,description:`Project root path for context`}},prompts:{default:{system:`You are a helpful assistant that creates well-structured tasks for a software development project. Generate a single new task based on the user's description, adhering strictly to the provided JSON schema.
|
|
148
158
|
|
|
149
159
|
IMPORTANT: Your response MUST be a JSON object with the following structure (no wrapper property, just these fields directly):
|
|
150
160
|
{
|
|
@@ -204,7 +214,7 @@ Project Root: {{projectRoot}}
|
|
|
204
214
|
}
|
|
205
215
|
|
|
206
216
|
Make sure the details and test strategy are comprehensive and specific{{#if useResearch}}, incorporating current best practices from your research{{/if}}. DO NOT include the task ID in the title.
|
|
207
|
-
{{#if contextFromArgs}}{{contextFromArgs}}{{/if}}`}}},
|
|
217
|
+
{{#if contextFromArgs}}{{contextFromArgs}}{{/if}}`}}},vi={id:`analyze-complexity`,version:`1.0.0`,description:`Analyze task complexity and generate expansion recommendations`,metadata:{author:`system`,created:`2024-01-01T00:00:00Z`,updated:`2024-01-01T00:00:00Z`,tags:[`analysis`,`complexity`,`expansion`,`recommendations`]},parameters:{tasks:{type:`array`,required:!0,description:`Array of tasks to analyze`},gatheredContext:{type:`string`,default:``,description:`Additional project context`},threshold:{type:`number`,default:5,min:1,max:10,description:`Complexity threshold for expansion recommendation`},useResearch:{type:`boolean`,default:!1,description:`Use research mode for deeper analysis`},hasCodebaseAnalysis:{type:`boolean`,default:!1,description:`Whether codebase analysis is available`},projectRoot:{type:`string`,default:``,description:`Project root path for context`}},prompts:{default:{system:`You are an expert software architect and project manager analyzing task complexity. Your analysis should consider implementation effort, technical challenges, dependencies, and testing requirements.
|
|
208
218
|
|
|
209
219
|
IMPORTANT: For each task, provide an analysis object with ALL of the following fields:
|
|
210
220
|
- taskId: The ID of the task being analyzed (positive integer)
|
|
@@ -242,7 +252,7 @@ Tasks:
|
|
|
242
252
|
|
|
243
253
|
{{gatheredContext}}
|
|
244
254
|
{{/if}}
|
|
245
|
-
`}}},
|
|
255
|
+
`}}},yi={id:`expand-task`,version:`1.0.0`,description:`Break down a task into detailed subtasks`,metadata:{author:`system`,created:`2024-01-01T00:00:00Z`,updated:`2024-01-01T00:00:00Z`,tags:[`expansion`,`subtasks`,`breakdown`]},parameters:{subtaskCount:{type:`number`,required:!0,description:`Number of subtasks to generate`},task:{type:`object`,required:!0,description:`The task to expand`},nextSubtaskId:{type:`number`,required:!0,description:`Starting ID for new subtasks`},useResearch:{type:`boolean`,default:!1,description:`Use research mode`},expansionPrompt:{type:`string`,required:!1,description:`Expansion prompt from complexity report`},additionalContext:{type:`string`,required:!1,default:``,description:`Additional context for task expansion`},complexityReasoningContext:{type:`string`,required:!1,default:``,description:`Complexity analysis reasoning context`},gatheredContext:{type:`string`,required:!1,default:``,description:`Gathered project context`},hasCodebaseAnalysis:{type:`boolean`,required:!1,default:!1,description:`Whether codebase analysis is available`},projectRoot:{type:`string`,required:!1,default:``,description:`Project root path for context`}},prompts:{"complexity-report":{condition:`expansionPrompt`,system:`You are an AI assistant helping with task breakdown. Generate {{#if (gt subtaskCount 0)}}exactly {{subtaskCount}}{{else}}an appropriate number of{{/if}} subtasks based on the provided prompt and context.
|
|
246
256
|
|
|
247
257
|
IMPORTANT: Your response MUST be a JSON object with a "subtasks" property containing an array of subtask objects. Each subtask must include ALL of the following fields:
|
|
248
258
|
- id: MUST be sequential integers starting EXACTLY from {{nextSubtaskId}}. First subtask id={{nextSubtaskId}}, second id={{nextSubtaskId}}+1, etc. DO NOT use any other numbering pattern!
|
|
@@ -354,7 +364,7 @@ Complexity Analysis Reasoning: {{complexityReasoningContext}}{{/if}}{{#if gather
|
|
|
354
364
|
|
|
355
365
|
{{gatheredContext}}{{/if}}
|
|
356
366
|
|
|
357
|
-
CRITICAL: You MUST use sequential IDs starting from {{nextSubtaskId}}. The first subtask MUST have id={{nextSubtaskId}}, the second MUST have id={{nextSubtaskId}}+1, and so on. Do NOT use parent task ID in subtask numbering!`}}},
|
|
367
|
+
CRITICAL: You MUST use sequential IDs starting from {{nextSubtaskId}}. The first subtask MUST have id={{nextSubtaskId}}, the second MUST have id={{nextSubtaskId}}+1, and so on. Do NOT use parent task ID in subtask numbering!`}}},bi={id:`parse-prd`,version:`1.0.0`,description:`Parse a Product Requirements Document into structured tasks`,metadata:{author:`system`,created:`2024-01-01T00:00:00Z`,updated:`2024-01-01T00:00:00Z`,tags:[`prd`,`parsing`,`initialization`]},parameters:{numTasks:{type:`number`,required:!0,description:`Target number of tasks to generate`},nextId:{type:`number`,required:!0,description:`Starting ID for tasks`},research:{type:`boolean`,default:!1,description:`Enable research mode for latest best practices`},prdContent:{type:`string`,required:!0,description:`Content of the PRD file`},prdPath:{type:`string`,required:!0,description:`Path to the PRD file`},defaultTaskPriority:{type:`string`,required:!1,default:`medium`,enum:[`high`,`medium`,`low`],description:`Default priority for generated tasks`},hasCodebaseAnalysis:{type:`boolean`,required:!1,default:!1,description:`Whether codebase analysis is available`},projectRoot:{type:`string`,required:!1,default:``,description:`Project root path for context`}},prompts:{default:{system:`You are an AI assistant specialized in analyzing Product Requirements Documents (PRDs) and generating a structured, logically ordered, dependency-aware and sequenced list of development tasks in JSON format.{{#if research}}
|
|
358
368
|
Before breaking down the PRD into tasks, you will:
|
|
359
369
|
1. Research and analyze the latest technologies, libraries, frameworks, and best practices that would be appropriate for this project
|
|
360
370
|
2. Identify any potential technical challenges, security concerns, or scalability issues not explicitly mentioned in the PRD without discarding any explicit requirements or going overboard with complexity -- always aim to provide the most direct path to implementation, avoiding over-engineering or roundabout approaches
|
|
@@ -418,7 +428,7 @@ Remember to thoroughly research current best practices and technologies before t
|
|
|
418
428
|
|
|
419
429
|
{{prdContent}}
|
|
420
430
|
|
|
421
|
-
IMPORTANT: Your response must be a JSON object with a "tasks" property containing an array of task objects. You may optionally include a "metadata" object. Do not include any other properties.`}}},
|
|
431
|
+
IMPORTANT: Your response must be a JSON object with a "tasks" property containing an array of task objects. You may optionally include a "metadata" object. Do not include any other properties.`}}},xi={id:`research`,version:`1.0.0`,description:`Perform AI-powered research with project context`,metadata:{author:`system`,created:`2024-01-01T00:00:00Z`,updated:`2024-01-01T00:00:00Z`,tags:[`research`,`context-aware`,`information-gathering`]},parameters:{query:{type:`string`,required:!0,description:`Research query`},gatheredContext:{type:`string`,default:``,description:`Gathered project context`},detailLevel:{type:`string`,enum:[`low`,`medium`,`high`],default:`medium`,description:`Level of detail for the response`},projectInfo:{type:`object`,description:`Project information`,properties:{root:{type:`string`,description:`Project root path`},taskCount:{type:`number`,description:`Number of related tasks`},fileCount:{type:`number`,description:`Number of related files`}}}},prompts:{default:{system:`You are an expert AI research assistant helping with a software development project. You have access to project context including tasks, files, and project structure.
|
|
422
432
|
|
|
423
433
|
Your role is to provide comprehensive, accurate, and actionable research responses based on the user's query and the provided project context.
|
|
424
434
|
{{#if (eq detailLevel "low")}}
|
|
@@ -468,7 +478,7 @@ Your role is to provide comprehensive, accurate, and actionable research respons
|
|
|
468
478
|
|
|
469
479
|
# Instructions
|
|
470
480
|
|
|
471
|
-
Please research and provide a {{detailLevel}}-detail response to the query above. Consider the project context provided and make your response as relevant and actionable as possible for this specific project.`}}},
|
|
481
|
+
Please research and provide a {{detailLevel}}-detail response to the query above. Consider the project context provided and make your response as relevant and actionable as possible for this specific project.`}}},Si={id:`update-subtask`,version:`1.0.0`,description:`Append information to a subtask by generating only new content`,metadata:{author:`system`,created:`2024-01-01T00:00:00Z`,updated:`2024-01-01T00:00:00Z`,tags:[`update`,`subtask`,`append`,`logging`]},parameters:{parentTask:{type:`object`,required:!0,description:`The parent task context`},prevSubtask:{type:`object`,required:!1,description:`The previous subtask if any`},nextSubtask:{type:`object`,required:!1,description:`The next subtask if any`},currentDetails:{type:`string`,required:!0,default:`(No existing details)`,description:`Current subtask details`},updatePrompt:{type:`string`,required:!0,description:`User request for what to add`},useResearch:{type:`boolean`,default:!1,description:`Use research mode`},gatheredContext:{type:`string`,default:``,description:`Additional project context`},hasCodebaseAnalysis:{type:`boolean`,required:!1,default:!1,description:`Whether codebase analysis is available`},projectRoot:{type:`string`,required:!1,default:``,description:`Project root path for context`}},prompts:{default:{system:`You are an AI assistant helping to update a subtask. You will be provided with the subtask's existing details, context about its parent and sibling tasks, and a user request string.{{#if useResearch}} You have access to current best practices and latest technical information to provide research-backed updates.{{/if}}
|
|
472
482
|
|
|
473
483
|
Your Goal: Based *only* on the user's request and all the provided context (including existing details if relevant to the request), GENERATE the new text content that should be added to the subtask's details.
|
|
474
484
|
Focus *only* on generating the substance of the update.
|
|
@@ -512,7 +522,7 @@ User Request: "{{updatePrompt}}"
|
|
|
512
522
|
# Additional Project Context
|
|
513
523
|
|
|
514
524
|
{{gatheredContext}}
|
|
515
|
-
{{/if}}`}}},
|
|
525
|
+
{{/if}}`}}},Ci={id:`update-task`,version:`1.0.0`,description:`Update a single task with new information, supporting full updates and append mode`,metadata:{author:`system`,created:`2024-01-01T00:00:00Z`,updated:`2024-01-01T00:00:00Z`,tags:[`update`,`single-task`,`modification`,`append`]},parameters:{task:{type:`object`,required:!0,description:`The task to update`},taskJson:{type:`string`,required:!0,description:`JSON string representation of the task`},updatePrompt:{type:`string`,required:!0,description:`Description of changes to apply`},appendMode:{type:`boolean`,default:!1,description:`Whether to append to details or do full update`},useResearch:{type:`boolean`,default:!1,description:`Use research mode`},currentDetails:{type:`string`,default:`(No existing details)`,description:`Current task details for context`},gatheredContext:{type:`string`,default:``,description:`Additional project context`},hasCodebaseAnalysis:{type:`boolean`,required:!1,default:!1,description:`Whether codebase analysis is available`},projectRoot:{type:`string`,required:!1,default:``,description:`Project root path for context`}},prompts:{default:{system:`You are an AI assistant helping to update a software development task based on new context.{{#if useResearch}} You have access to current best practices and latest technical information to provide research-backed updates.{{/if}}
|
|
516
526
|
You will be given a task and a prompt describing changes or new implementation details.
|
|
517
527
|
Your job is to update the task to reflect these changes, while preserving its basic structure.
|
|
518
528
|
|
|
@@ -610,7 +620,7 @@ Based on the User Request and all the Task Context (including current task detai
|
|
|
610
620
|
# Additional Project Context
|
|
611
621
|
|
|
612
622
|
{{gatheredContext}}
|
|
613
|
-
{{/if}}`}}},
|
|
623
|
+
{{/if}}`}}},wi={id:`update-tasks`,version:`1.0.0`,description:`Update multiple tasks based on new context or changes`,metadata:{author:`system`,created:`2024-01-01T00:00:00Z`,updated:`2024-01-01T00:00:00Z`,tags:[`update`,`bulk`,`context-change`]},parameters:{tasks:{type:`array`,required:!0,description:`Array of tasks to update`},updatePrompt:{type:`string`,required:!0,description:`Description of changes to apply`},useResearch:{type:`boolean`,default:!1,description:`Use research mode`},projectContext:{type:`string`,description:`Additional project context`},hasCodebaseAnalysis:{type:`boolean`,required:!1,default:!1,description:`Whether codebase analysis is available`},projectRoot:{type:`string`,required:!1,default:``,description:`Project root path for context`}},prompts:{default:{system:`You are an AI assistant helping to update software development tasks based on new context.
|
|
614
624
|
You will be given a set of tasks and a prompt describing changes or new implementation details.
|
|
615
625
|
Your job is to update the tasks to reflect these changes, while preserving their basic structure.
|
|
616
626
|
|
|
@@ -652,7 +662,7 @@ IMPORTANT: In the tasks above, any subtasks with "status": "done" or "status": "
|
|
|
652
662
|
|
|
653
663
|
{{projectContext}}{{/if}}
|
|
654
664
|
|
|
655
|
-
IMPORTANT: Your response must be a JSON object with a single property named "tasks" containing the updated array of tasks.`}}},mi={$schema:`http://json-schema.org/draft-07/schema#`,$id:`https://github.com/stephennmiller/taskgraph-ai/blob/main/src/prompts/schemas/prompt-template.schema.json`,version:`1.0.0`,title:`TaskGraph Prompt Template`,description:`Schema for TaskGraph prompt template files`,type:`object`,required:[`id`,`version`,`description`,`prompts`],properties:{id:{type:`string`,pattern:`^[a-z0-9-]+$`,description:`Unique identifier for the prompt template`},version:{type:`string`,pattern:`^\\d+\\.\\d+\\.\\d+$`,description:`Semantic version of the prompt template`},description:{type:`string`,minLength:1,description:`Brief description of what this prompt does`},metadata:{$ref:`#/definitions/metadata`},parameters:{type:`object`,additionalProperties:{$ref:`#/definitions/parameter`}},prompts:{type:`object`,properties:{default:{$ref:`#/definitions/promptVariant`}},additionalProperties:{$ref:`#/definitions/conditionalPromptVariant`}}},definitions:{parameter:{type:`object`,required:[`type`,`description`],properties:{type:{type:`string`,enum:[`string`,`number`,`boolean`,`array`,`object`]},description:{type:`string`,minLength:1},required:{type:`boolean`,default:!1},default:{description:`Default value for optional parameters`},enum:{type:`array`,description:`Valid values for string parameters`},pattern:{type:`string`,description:`Regular expression pattern for string validation`},minimum:{type:`number`,description:`Minimum value for number parameters`},maximum:{type:`number`,description:`Maximum value for number parameters`}}},promptVariant:{type:`object`,required:[`system`,`user`],properties:{system:{type:`string`,minLength:1},user:{type:`string`,minLength:1}}},conditionalPromptVariant:{allOf:[{$ref:`#/definitions/promptVariant`},{type:`object`,properties:{condition:{type:`string`,description:`JavaScript expression for variant selection`}}}]},metadata:{type:`object`,properties:{author:{type:`string`},created:{type:`string`,format:`date-time`},updated:{type:`string`,format:`date-time`},tags:{type:`array`,items:{type:`string`}},category:{type:`string`,enum:[`task`,`analysis`,`research`,`parsing`,`update`,`expansion`]}}}}},hi=class{constructor(){this.prompts=/* @__PURE__ */ new Map([[`analyze-complexity`,si],[`expand-task`,ci],[`add-task`,oi],[`research`,ui],[`parse-prd`,li],[`update-task`,fi],[`update-tasks`,pi],[`update-subtask`,di]]),this.cache=/* @__PURE__ */ new Map,this.setupValidation()}setupValidation(){this.ajv=new Ze({allErrors:!0,strict:!1}),Qe(this.ajv);try{this.validatePrompt=this.ajv.compile(mi),I(`debug`,`✓ JSON schema validation enabled`)}catch(e){I(`warn`,`⚠ Schema validation disabled: ${e.message}`),this.validatePrompt=()=>!0}}loadPrompt(e,t={},n=null){try{let r=`${e}-${JSON.stringify(t)}-${n}`;if(this.cache.has(r))return this.cache.get(r);let i=this.loadTemplate(e);this.validatePrompt&&this.validatePrompt!==!0&&this.validateParameters(i,t);let a=n?{...i.prompts[n],name:n}:this.selectVariant(i,t),o={systemPrompt:this.renderTemplate(a.system,t),userPrompt:this.renderTemplate(a.user,t),metadata:{templateId:i.id,version:i.version,variant:a.name||`default`,parameters:t}};return this.cache.set(r,o),o}catch(t){throw I(`error`,`Failed to load prompt ${e}: ${t.message}`),t}}loadTemplate(e){let t=this.prompts.get(e);if(!t)throw Error(`Prompt template '${e}' not found`);if(this.validatePrompt&&this.validatePrompt!==!0){if(!this.validatePrompt(t)){let e=this.validatePrompt.errors.map(e=>`${e.instancePath||`root`}: ${e.message}`).join(`, `);throw Error(`Schema validation failed: ${e}`)}}else if(!t.id||!t.prompts||!t.prompts.default)throw Error(`Invalid template structure: missing required fields (id, prompts.default)`);return t}validateParameters(e,t){if(!e.parameters)return;let n=[];for(let[r,i]of Object.entries(e.parameters)){let e=t[r];i.required&&e===void 0?n.push(`Required parameter '${r}' missing`):e!==void 0&&(this.validateParameterType(e,i.type)||n.push(`Parameter '${r}' expected ${i.type}, got ${typeof e}`),i.enum&&!i.enum.includes(e)&&n.push(`Parameter '${r}' must be one of: ${i.enum.join(`, `)}`),i.pattern&&typeof e==`string`&&(new RegExp(i.pattern).test(e)||n.push(`Parameter '${r}' does not match required pattern: ${i.pattern}`)),typeof e==`number`&&(i.minimum!==void 0&&e<i.minimum&&n.push(`Parameter '${r}' must be >= ${i.minimum}`),i.maximum!==void 0&&e>i.maximum&&n.push(`Parameter '${r}' must be <= ${i.maximum}`)))}if(n.length>0)throw Error(`Parameter validation failed: ${n.join(`; `)}`)}validateParameterType(e,t){switch(t){case`string`:return typeof e==`string`;case`number`:return typeof e==`number`;case`boolean`:return typeof e==`boolean`;case`array`:return Array.isArray(e);case`object`:return typeof e==`object`&&!!e&&!Array.isArray(e);default:return!0}}selectVariant(e,t){for(let[n,r]of Object.entries(e.prompts))if(n!=="default"&&r.condition&&this.evaluateCondition(r.condition,t))return{...r,name:n};return{...e.prompts.default,name:`default`}}evaluateCondition(e,t){try{let n={...t};return Function(...Object.keys(n),`return ${e}`)(...Object.values(n))}catch{return I(`warn`,`Failed to evaluate condition: ${e}`),!1}}renderTemplate(e,t){let n=e;return n=n.replace(/\(eq\s+(\w+(?:\.\w+)*)\s+"([^"]+)"\)/g,(e,n,r)=>this.getNestedValue(t,n)===r?`true`:`false`),n=n.replace(/\(not\s+(\w+(?:\.\w+)*)\)/g,(e,n)=>this.getNestedValue(t,n)?`false`:`true`),n=n.replace(/\(gt\s+(\w+(?:\.\w+)*)\s+(\d+(?:\.\d+)?)\)/g,(e,n,r)=>{let i=this.getNestedValue(t,n);return typeof i==`number`&&i>parseFloat(r)?`true`:`false`}),n=n.replace(/\(gte\s+(\w+(?:\.\w+)*)\s+(\d+(?:\.\d+)?)\)/g,(e,n,r)=>{let i=this.getNestedValue(t,n);return typeof i==`number`&&i>=parseFloat(r)?`true`:`false`}),n=n.replace(/\{\{#if\s+([^}]+)\}\}([\s\S]*?)(?:\{\{else\}\}([\s\S]*?))?\{\{\/if\}\}/g,(e,n,r,i=``)=>{let a;return a=n===`true`||n!==`false`&&this.getNestedValue(t,n),a?r:i}),n=n.replace(/\{\{#each\s+(\w+(?:\.\w+)*)\}\}([\s\S]*?)\{\{\/each\}\}/g,(e,n,r)=>{let i=this.getNestedValue(t,n);return Array.isArray(i)?i.map((e,n)=>{let a={...t,...e,"@index":n,"@first":n===0,"@last":n===i.length-1};return this.renderTemplate(r,a)}).join(``):``}),n=n.replace(/\{\{\{json\s+(\w+(?:\.\w+)*)\}\}\}/g,(e,n)=>{let r=this.getNestedValue(t,n);return r===void 0?``:JSON.stringify(r,null,2)}),n=n.replace(/\{\{(\w+(?:\.\w+)*)\}\}/g,(e,n)=>{let r=this.getNestedValue(t,n);return r===void 0?``:r}),n}getNestedValue(e,t){return t.split(`.`).reduce((e,t)=>e&&e[t]!==void 0?e[t]:void 0,e)}validateAllPrompts(){let e={total:0,errors:[],valid:[]};for(let[t,n]of this.prompts.entries()){e.total++;try{if(this.validatePrompt&&this.validatePrompt!==!0&&!this.validatePrompt(n)){let e=this.validatePrompt.errors.map(e=>`${e.instancePath||`root`}: ${e.message}`).join(`, `);throw Error(`Schema validation failed: ${e}`)}e.valid.push(t)}catch(n){e.errors.push(`${t}: ${n.message}`)}}return e}listPrompts(){let e=[];for(let[t,n]of this.prompts.entries())try{e.push({id:n.id,description:n.description,version:n.version,parameters:n.parameters,tags:n.metadata?.tags||[]})}catch(e){I(`warn`,`Failed to process template ${t}: ${e.message}`)}return e}validateTemplate(e){try{let t;if(typeof e==`string`){if(t=this.prompts.get(e),!t)return{valid:!1,error:`Template '${e}' not found`}}else t=e;for(let e of[`id`,`version`,`description`,`prompts`])if(!t[e])return{valid:!1,error:`Missing required field: ${e}`};if(!t.prompts.default)return{valid:!1,error:`Missing default prompt variant`};for(let[e,n]of Object.entries(t.prompts))if(!n.system||!n.user)return{valid:!1,error:`Variant '${e}' missing system or user prompt`};return this.validatePrompt&&this.validatePrompt!==!0&&!this.validatePrompt(t)?{valid:!1,error:`Schema validation failed: ${this.validatePrompt.errors.map(e=>`${e.instancePath||`root`}: ${e.message}`).join(`, `)}`}:{valid:!0}}catch(e){return{valid:!1,error:e.message}}}};let gi=null;function _i(){return gi||=new hi,gi}const{encode:vi}=$e;var yi=class{constructor(e,t){this.projectRoot=e,this.tasksPath=H.join(e,`.taskgraph`,`tasks`,`tasks.json`),this.tag=t,this.allTasks=this._loadAllTasks()}_loadAllTasks(){try{return P(this.tasksPath,this.projectRoot,this.tag)?.tasks||[]}catch(e){return console.warn(`Warning: Could not load tasks for ContextGatherer: ${e.message}`),[]}}countTokens(e){if(!e||typeof e!=`string`)return 0;try{return vi(e).length}catch{return Math.ceil(e.length/4)}}async gather(e={}){let{tasks:t=[],files:n=[],customContext:r=``,includeProjectTree:i=!1,format:a=`research`,includeTokenCounts:o=!1,semanticQuery:s,maxSemanticResults:c=10,dependencyTasks:l=[]}=e,u=[],d=new Set(t.map(String)),f=null,p=null;if(o&&(p={total:0,customContext:null,tasks:[],files:[],projectTree:null}),s&&this.allTasks.length>0){let e=this._performSemanticSearch(s,c);f=e.analysisData,e.tasks.forEach(e=>{d.add(String(e.id))})}if(l.length>0&&this._buildDependencyGraphs(l).allRelatedTaskIds.forEach(e=>d.add(String(e))),r&&r.trim()){let e=this._formatCustomContext(r,a);u.push(e),o&&(p.customContext={tokens:this.countTokens(e),characters:e.length},p.total+=p.customContext.tokens)}if(d.size>0){let e=await this._gatherTaskContext(Array.from(d),a,o);if(e.context&&(u.push(e.context),o&&e.breakdown)){p.tasks=e.breakdown;let t=e.breakdown.reduce((e,t)=>e+t.tokens,0);p.total+=t}}if(n.length>0){let e=await this._gatherFileContext(n,a,o);if(e.context&&(u.push(e.context),o&&e.breakdown)){p.files=e.breakdown;let t=e.breakdown.reduce((e,t)=>e+t.tokens,0);p.total+=t}}if(i){let e=await this._gatherProjectTreeContext(a,o);e.context&&(u.push(e.context),o&&e.breakdown&&(p.projectTree=e.breakdown,p.total+=e.breakdown.tokens))}let m={context:this._joinContextSections(u,a),analysisData:f,contextSections:u.length,finalTaskIds:Array.from(d)};return o&&(m.tokenBreakdown=p),m}_performSemanticSearch(e,t){let n=this.allTasks.map(e=>{let t=e.dependencies?.length>0?e.dependencies.map(e=>this.allTasks.find(t=>t.id===e)?.title).filter(Boolean).join(` `):``;return{...e,dependencyTitles:t}}),r=new Ye(n,{includeScore:!0,threshold:.4,keys:[{name:`title`,weight:1.5},{name:`description`,weight:2},{name:`details`,weight:3},{name:`dependencyTitles`,weight:.5}],shouldSort:!0,useExtendedSearch:!0,limit:50}),i=e.toLowerCase().replace(/[^\w\s-]/g,` `).split(/\s+/).filter(e=>e.length>3),a=r.search(e),o=[];for(let e of i)if(e.length>5){let t=r.search(e);t.length>0&&o.push(...t)}let s=[...a];for(let e of o)s.some(t=>t.item.id===e.item.id)||s.push(e);let c=s.filter(e=>e.score<.25).map(e=>e.item),l=s.filter(e=>e.score>=.25&&e.score<.4).map(e=>e.item),u=[...this.allTasks].sort((e,t)=>t.id-e.id).slice(0,5),d=[...c];for(let e of l)d.some(t=>t.id===e.id)||d.push(e);for(let e of u)d.some(t=>t.id===e.id)||d.push(e);return{tasks:d.slice(0,t),analysisData:{highRelevance:c,mediumRelevance:l,recentTasks:u,allRelevantTasks:d}}}_buildDependencyContext(e){let{allRelatedTaskIds:t,graphs:n,depthMap:r}=this._buildDependencyGraphs(e);if(t.size===0)return``;let i=Array.from(t).map(e=>this.allTasks.find(t=>t.id===e)).filter(Boolean).sort((e,t)=>(r.get(e.id)||0)-(r.get(t.id)||0)),a=i.slice(0,8),o=`\nThis task relates to a dependency structure with ${i.length} related tasks in the chain.`,s=this.allTasks.filter(t=>e.includes(t.id));s.length>0&&(o+=`\n\nDirect dependencies:\n${s.map(e=>`- Task ${e.id}: ${e.title} - ${e.description}`).join(`
|
|
665
|
+
IMPORTANT: Your response must be a JSON object with a single property named "tasks" containing the updated array of tasks.`}}},Ti={$schema:`http://json-schema.org/draft-07/schema#`,$id:`https://github.com/stephennmiller/taskgraph-ai/blob/main/src/prompts/schemas/prompt-template.schema.json`,version:`1.0.0`,title:`TaskGraph Prompt Template`,description:`Schema for TaskGraph prompt template files`,type:`object`,required:[`id`,`version`,`description`,`prompts`],properties:{id:{type:`string`,pattern:`^[a-z0-9-]+$`,description:`Unique identifier for the prompt template`},version:{type:`string`,pattern:`^\\d+\\.\\d+\\.\\d+$`,description:`Semantic version of the prompt template`},description:{type:`string`,minLength:1,description:`Brief description of what this prompt does`},metadata:{$ref:`#/definitions/metadata`},parameters:{type:`object`,additionalProperties:{$ref:`#/definitions/parameter`}},prompts:{type:`object`,properties:{default:{$ref:`#/definitions/promptVariant`}},additionalProperties:{$ref:`#/definitions/conditionalPromptVariant`}}},definitions:{parameter:{type:`object`,required:[`type`,`description`],properties:{type:{type:`string`,enum:[`string`,`number`,`boolean`,`array`,`object`]},description:{type:`string`,minLength:1},required:{type:`boolean`,default:!1},default:{description:`Default value for optional parameters`},enum:{type:`array`,description:`Valid values for string parameters`},pattern:{type:`string`,description:`Regular expression pattern for string validation`},minimum:{type:`number`,description:`Minimum value for number parameters`},maximum:{type:`number`,description:`Maximum value for number parameters`}}},promptVariant:{type:`object`,required:[`system`,`user`],properties:{system:{type:`string`,minLength:1},user:{type:`string`,minLength:1}}},conditionalPromptVariant:{allOf:[{$ref:`#/definitions/promptVariant`},{type:`object`,properties:{condition:{type:`string`,description:`JavaScript expression for variant selection`}}}]},metadata:{type:`object`,properties:{author:{type:`string`},created:{type:`string`,format:`date-time`},updated:{type:`string`,format:`date-time`},tags:{type:`array`,items:{type:`string`}},category:{type:`string`,enum:[`task`,`analysis`,`research`,`parsing`,`update`,`expansion`]}}}}},Ei=class{constructor(){this.prompts=/* @__PURE__ */ new Map([[`analyze-complexity`,vi],[`expand-task`,yi],[`add-task`,_i],[`research`,xi],[`parse-prd`,bi],[`update-task`,Ci],[`update-tasks`,wi],[`update-subtask`,Si]]),this.cache=/* @__PURE__ */ new Map,this.setupValidation()}setupValidation(){this.ajv=new Ze({allErrors:!0,strict:!1}),Qe(this.ajv);try{this.validatePrompt=this.ajv.compile(Ti),I(`debug`,`✓ JSON schema validation enabled`)}catch(e){I(`warn`,`⚠ Schema validation disabled: ${e.message}`),this.validatePrompt=()=>!0}}loadPrompt(e,t={},n=null){try{let r=`${e}-${JSON.stringify(t)}-${n}`;if(this.cache.has(r))return this.cache.get(r);let i=this.loadTemplate(e);this.validatePrompt&&this.validatePrompt!==!0&&this.validateParameters(i,t);let a=n?{...i.prompts[n],name:n}:this.selectVariant(i,t),o={systemPrompt:this.renderTemplate(a.system,t),userPrompt:this.renderTemplate(a.user,t),metadata:{templateId:i.id,version:i.version,variant:a.name||`default`,parameters:t}};return this.cache.set(r,o),o}catch(t){throw I(`error`,`Failed to load prompt ${e}: ${t.message}`),t}}loadTemplate(e){let t=this.prompts.get(e);if(!t)throw Error(`Prompt template '${e}' not found`);if(this.validatePrompt&&this.validatePrompt!==!0){if(!this.validatePrompt(t)){let e=this.validatePrompt.errors.map(e=>`${e.instancePath||`root`}: ${e.message}`).join(`, `);throw Error(`Schema validation failed: ${e}`)}}else if(!t.id||!t.prompts||!t.prompts.default)throw Error(`Invalid template structure: missing required fields (id, prompts.default)`);return t}validateParameters(e,t){if(!e.parameters)return;let n=[];for(let[r,i]of Object.entries(e.parameters)){let e=t[r];i.required&&e===void 0?n.push(`Required parameter '${r}' missing`):e!==void 0&&(this.validateParameterType(e,i.type)||n.push(`Parameter '${r}' expected ${i.type}, got ${typeof e}`),i.enum&&!i.enum.includes(e)&&n.push(`Parameter '${r}' must be one of: ${i.enum.join(`, `)}`),i.pattern&&typeof e==`string`&&(new RegExp(i.pattern).test(e)||n.push(`Parameter '${r}' does not match required pattern: ${i.pattern}`)),typeof e==`number`&&(i.minimum!==void 0&&e<i.minimum&&n.push(`Parameter '${r}' must be >= ${i.minimum}`),i.maximum!==void 0&&e>i.maximum&&n.push(`Parameter '${r}' must be <= ${i.maximum}`)))}if(n.length>0)throw Error(`Parameter validation failed: ${n.join(`; `)}`)}validateParameterType(e,t){switch(t){case`string`:return typeof e==`string`;case`number`:return typeof e==`number`;case`boolean`:return typeof e==`boolean`;case`array`:return Array.isArray(e);case`object`:return typeof e==`object`&&!!e&&!Array.isArray(e);default:return!0}}selectVariant(e,t){for(let[n,r]of Object.entries(e.prompts))if(n!=="default"&&r.condition&&this.evaluateCondition(r.condition,t))return{...r,name:n};return{...e.prompts.default,name:`default`}}evaluateCondition(e,t){try{let n={...t};return Function(...Object.keys(n),`return ${e}`)(...Object.values(n))}catch{return I(`warn`,`Failed to evaluate condition: ${e}`),!1}}renderTemplate(e,t){let n=e;return n=n.replace(/\(eq\s+(\w+(?:\.\w+)*)\s+"([^"]+)"\)/g,(e,n,r)=>this.getNestedValue(t,n)===r?`true`:`false`),n=n.replace(/\(not\s+(\w+(?:\.\w+)*)\)/g,(e,n)=>this.getNestedValue(t,n)?`false`:`true`),n=n.replace(/\(gt\s+(\w+(?:\.\w+)*)\s+(\d+(?:\.\d+)?)\)/g,(e,n,r)=>{let i=this.getNestedValue(t,n);return typeof i==`number`&&i>parseFloat(r)?`true`:`false`}),n=n.replace(/\(gte\s+(\w+(?:\.\w+)*)\s+(\d+(?:\.\d+)?)\)/g,(e,n,r)=>{let i=this.getNestedValue(t,n);return typeof i==`number`&&i>=parseFloat(r)?`true`:`false`}),n=n.replace(/\{\{#if\s+([^}]+)\}\}([\s\S]*?)(?:\{\{else\}\}([\s\S]*?))?\{\{\/if\}\}/g,(e,n,r,i=``)=>{let a;return a=n===`true`||n!==`false`&&this.getNestedValue(t,n),a?r:i}),n=n.replace(/\{\{#each\s+(\w+(?:\.\w+)*)\}\}([\s\S]*?)\{\{\/each\}\}/g,(e,n,r)=>{let i=this.getNestedValue(t,n);return Array.isArray(i)?i.map((e,n)=>{let a={...t,...e,"@index":n,"@first":n===0,"@last":n===i.length-1};return this.renderTemplate(r,a)}).join(``):``}),n=n.replace(/\{\{\{json\s+(\w+(?:\.\w+)*)\}\}\}/g,(e,n)=>{let r=this.getNestedValue(t,n);return r===void 0?``:JSON.stringify(r,null,2)}),n=n.replace(/\{\{(\w+(?:\.\w+)*)\}\}/g,(e,n)=>{let r=this.getNestedValue(t,n);return r===void 0?``:r}),n}getNestedValue(e,t){return t.split(`.`).reduce((e,t)=>e&&e[t]!==void 0?e[t]:void 0,e)}validateAllPrompts(){let e={total:0,errors:[],valid:[]};for(let[t,n]of this.prompts.entries()){e.total++;try{if(this.validatePrompt&&this.validatePrompt!==!0&&!this.validatePrompt(n)){let e=this.validatePrompt.errors.map(e=>`${e.instancePath||`root`}: ${e.message}`).join(`, `);throw Error(`Schema validation failed: ${e}`)}e.valid.push(t)}catch(n){e.errors.push(`${t}: ${n.message}`)}}return e}listPrompts(){let e=[];for(let[t,n]of this.prompts.entries())try{e.push({id:n.id,description:n.description,version:n.version,parameters:n.parameters,tags:n.metadata?.tags||[]})}catch(e){I(`warn`,`Failed to process template ${t}: ${e.message}`)}return e}validateTemplate(e){try{let t;if(typeof e==`string`){if(t=this.prompts.get(e),!t)return{valid:!1,error:`Template '${e}' not found`}}else t=e;for(let e of[`id`,`version`,`description`,`prompts`])if(!t[e])return{valid:!1,error:`Missing required field: ${e}`};if(!t.prompts.default)return{valid:!1,error:`Missing default prompt variant`};for(let[e,n]of Object.entries(t.prompts))if(!n.system||!n.user)return{valid:!1,error:`Variant '${e}' missing system or user prompt`};return this.validatePrompt&&this.validatePrompt!==!0&&!this.validatePrompt(t)?{valid:!1,error:`Schema validation failed: ${this.validatePrompt.errors.map(e=>`${e.instancePath||`root`}: ${e.message}`).join(`, `)}`}:{valid:!0}}catch(e){return{valid:!1,error:e.message}}}};let Di=null;function Oi(){return Di||=new Ei,Di}const{encode:ki}=$e;var Ai=class{constructor(e,t){this.projectRoot=e,this.tasksPath=H.join(e,`.taskgraph`,`tasks`,`tasks.json`),this.tag=t,this.allTasks=this._loadAllTasks()}_loadAllTasks(){try{return P(this.tasksPath,this.projectRoot,this.tag)?.tasks||[]}catch(e){return console.warn(`Warning: Could not load tasks for ContextGatherer: ${e.message}`),[]}}countTokens(e){if(!e||typeof e!=`string`)return 0;try{return ki(e).length}catch{return Math.ceil(e.length/4)}}async gather(e={}){let{tasks:t=[],files:n=[],customContext:r=``,includeProjectTree:i=!1,format:a=`research`,includeTokenCounts:o=!1,semanticQuery:s,maxSemanticResults:c=10,dependencyTasks:l=[]}=e,u=[],d=new Set(t.map(String)),f=null,p=null;if(o&&(p={total:0,customContext:null,tasks:[],files:[],projectTree:null}),s&&this.allTasks.length>0){let e=this._performSemanticSearch(s,c);f=e.analysisData,e.tasks.forEach(e=>{d.add(String(e.id))})}if(l.length>0&&this._buildDependencyGraphs(l).allRelatedTaskIds.forEach(e=>d.add(String(e))),r&&r.trim()){let e=this._formatCustomContext(r,a);u.push(e),o&&(p.customContext={tokens:this.countTokens(e),characters:e.length},p.total+=p.customContext.tokens)}if(d.size>0){let e=await this._gatherTaskContext(Array.from(d),a,o);if(e.context&&(u.push(e.context),o&&e.breakdown)){p.tasks=e.breakdown;let t=e.breakdown.reduce((e,t)=>e+t.tokens,0);p.total+=t}}if(n.length>0){let e=await this._gatherFileContext(n,a,o);if(e.context&&(u.push(e.context),o&&e.breakdown)){p.files=e.breakdown;let t=e.breakdown.reduce((e,t)=>e+t.tokens,0);p.total+=t}}if(i){let e=await this._gatherProjectTreeContext(a,o);e.context&&(u.push(e.context),o&&e.breakdown&&(p.projectTree=e.breakdown,p.total+=e.breakdown.tokens))}let m={context:this._joinContextSections(u,a),analysisData:f,contextSections:u.length,finalTaskIds:Array.from(d)};return o&&(m.tokenBreakdown=p),m}_performSemanticSearch(e,t){let n=this.allTasks.map(e=>{let t=e.dependencies?.length>0?e.dependencies.map(e=>this.allTasks.find(t=>t.id===e)?.title).filter(Boolean).join(` `):``;return{...e,dependencyTitles:t}}),r=new Ye(n,{includeScore:!0,threshold:.4,keys:[{name:`title`,weight:1.5},{name:`description`,weight:2},{name:`details`,weight:3},{name:`dependencyTitles`,weight:.5}],shouldSort:!0,useExtendedSearch:!0,limit:50}),i=e.toLowerCase().replace(/[^\w\s-]/g,` `).split(/\s+/).filter(e=>e.length>3),a=r.search(e),o=[];for(let e of i)if(e.length>5){let t=r.search(e);t.length>0&&o.push(...t)}let s=[...a];for(let e of o)s.some(t=>t.item.id===e.item.id)||s.push(e);let c=s.filter(e=>e.score<.25).map(e=>e.item),l=s.filter(e=>e.score>=.25&&e.score<.4).map(e=>e.item),u=[...this.allTasks].sort((e,t)=>t.id-e.id).slice(0,5),d=[...c];for(let e of l)d.some(t=>t.id===e.id)||d.push(e);for(let e of u)d.some(t=>t.id===e.id)||d.push(e);return{tasks:d.slice(0,t),analysisData:{highRelevance:c,mediumRelevance:l,recentTasks:u,allRelevantTasks:d}}}_buildDependencyContext(e){let{allRelatedTaskIds:t,graphs:n,depthMap:r}=this._buildDependencyGraphs(e);if(t.size===0)return``;let i=Array.from(t).map(e=>this.allTasks.find(t=>t.id===e)).filter(Boolean).sort((e,t)=>(r.get(e.id)||0)-(r.get(t.id)||0)),a=i.slice(0,8),o=`\nThis task relates to a dependency structure with ${i.length} related tasks in the chain.`,s=this.allTasks.filter(t=>e.includes(t.id));s.length>0&&(o+=`\n\nDirect dependencies:\n${s.map(e=>`- Task ${e.id}: ${e.title} - ${e.description}`).join(`
|
|
656
666
|
`)}`);let c=i.filter(t=>!e.includes(t.id));c.length>0&&(o+=`\n\nIndirect dependencies (dependencies of dependencies):\n${c.slice(0,5).map(e=>`- Task ${e.id}: ${e.title} - ${e.description}`).join(`
|
|
657
667
|
`)}`,c.length>5&&(o+=`\n- ... and ${c.length-5} more indirect dependencies`)),o+=`
|
|
658
668
|
|
|
@@ -686,7 +696,7 @@ Dependency Chain Visualization:`,o+=n.map(e=>this._formatDependencyChain(e)).joi
|
|
|
686
696
|
|
|
687
697
|
`);case`system-prompt`:return e.join(` `);default:return e.join(`
|
|
688
698
|
|
|
689
|
-
`)}}};function
|
|
699
|
+
`)}}};function ji(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 Mi(e,t,n=[],r=null,a={},o=`text`,s=null,c=!1){let{session:l,mcpLog:u,projectRoot:d,commandName:f,outputType:p,tag:m}=a,h=!!u,g=h?u:{info:(...e)=>I(`info`,...e),warn:(...e)=>I(`warn`,...e),error:(...e)=>I(`error`,...e),debug:(...e)=>I(`debug`,...e),success:(...e)=>I(`success`,...e)},_=r||ue(d)||`medium`;if(r){let e=ii(r);e?_=e:(o===`text`&&I(`warn`,`Invalid priority "${r}". Using default priority "${ni}".`),_=ni)}g.info(`Adding new task with prompt: "${t}", Priority: ${_}, Dependencies: ${n.join(`, `)||`None`}, Research: ${c}, ProjectRoot: ${d}`),m&&g.info(`Using tag context: ${m}`);let v=null,y=null,b=(e,t=`info`)=>{u?u[t](e):o===`text`&&I(t,e)};function x(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=x(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 r=P(e,d,m);r&&r._rawTaggedData&&(r=r._rawTaggedData),r||=(b(`tasks.json not found or invalid. Initializing new structure.`,`info`),{master:{tasks:[],metadata:{created:(/* @__PURE__ */ new Date()).toISOString(),description:`Default tasks context`}}}),r&&Array.isArray(r.tasks)&&!r._rawTaggedData&&(b(`Legacy format detected. Migrating to tagged format...`,`info`),r={master:{tasks:r.tasks,metadata:r.metadata||{created:(/* @__PURE__ */ new Date()).toISOString(),updated:(/* @__PURE__ */ new Date()).toISOString(),description:`Tasks for master context`}}},D(r.master,{description:`Tasks for master context`}),be(e),Ce(e),b(`Successfully migrated to tagged format.`,`success`));let a=m;if(!r[a])throw b(`Tag "${a}" does not exist. Please create it first using the 'add-tag' command.`,`error`),Error(`Tag "${a}" not found.`);r[a].tasks||(r[a].tasks=[]),r[a].metadata||(r[a].metadata={created:(/* @__PURE__ */ new Date()).toISOString(),updated:(/* @__PURE__ */ new Date()).toISOString(),description:``});let u=ji(r),g=r[a].tasks,S=(g.length>0?Math.max(...g.map(e=>e.id)):0)+1;o===`text`&&console.log(G(B.text.bold(`Creating New Task #${S}`),{padding:1,borderColor:N,borderStyle:`round`,margin:{top:1,bottom:1}}));let C=n.filter(e=>{let t=parseInt(e,10);return Number.isNaN(t)||!u.some(e=>e.id===t)});C.length>0&&(b(`The following dependencies do not exist or are invalid: ${C.join(`, `)}`,`warn`),b(`Removing invalid dependencies...`,`info`),n=n.filter(e=>!C.includes(e)));let w=n.map(e=>parseInt(e,10)),T=[],E=/* @__PURE__ */ new Set,O=/* @__PURE__ */ new Map;for(let e of w){let t=x(u,e,/* @__PURE__ */ new Set,O);t&&T.push(t)}for(let[e,t]of O.entries())E.add(e);let k;if(s){if(b(`Using manually provided task data`,`info`),k=s,b(`DEBUG: Taking MANUAL task data path.`,`debug`),!k.title||typeof k.title!=`string`||!k.description||typeof k.description!=`string`)throw Error(`Manual task data must include at least a title and description.`)}else{b(`DEBUG: Taking AI task generation path.`,`debug`),b(`Generating task data with AI with prompt:\n${t}`,`info`);let e=await new Ai(d,m).gather({semanticQuery:t,dependencyTasks:w,format:`research`}),n=e.context,r=e.analysisData;o===`text`&&r&&qs(r,t,n.length);let a=``;s?.title&&(a+=`\n- Suggested Title: "${s.title}"`),s?.description&&(a+=`\n- Suggested Description: "${s.description}"`),s?.details&&(a+=`\n- Additional Details Context: "${s.details}"`),s?.testStrategy&&(a+=`\n- Additional Test Strategy Context: "${s.testStrategy}"`);let{systemPrompt:g,userPrompt:x}=await Oi().loadPrompt(`add-task`,{prompt:t,newTaskId:S,existingTasks:u,gatheredContext:n,contextFromArgs:a,useResearch:c,priority:_,dependencies:w,hasCodebaseAnalysis:ee(c,d,l),projectRoot:d});o===`text`&&(v=Ms(`Generating new task with ${c?`Research`:`Main`} AI... \n`));try{let e=c?`research`:`main`;if(b(`DEBUG: Calling generateObjectService...`,`debug`),y=await i({role:e,session:l,projectRoot:d,schema:gi[`add-task`],objectName:`newTaskData`,systemPrompt:g,prompt:x,commandName:f||`add-task`,outputType:p||(h?`mcp`:`cli`)}),b(`DEBUG: generateObjectService returned successfully.`,`debug`),!y||!y.mainResult)throw Error(`AI service did not return the expected object structure.`);if(y.mainResult.title&&y.mainResult.description)k=y.mainResult;else if(y.mainResult.object&&y.mainResult.object.title&&y.mainResult.object.description)k=y.mainResult.object;else throw Error(`AI service did not return a valid task object.`);b(`Successfully generated task data from AI.`,`success`),v&&=(Ns(v,`Task generated successfully`),null)}catch(e){throw v&&=(Ps(v,`AI generation failed`),null),b(`DEBUG: generateObjectService caught error: ${e.message}`,`debug`),b(`Error generating task with AI: ${e.message}`,`error`),e}finally{b(`DEBUG: generateObjectService finally block reached.`,`debug`),v&&$(v)}}let A={id:S,title:k.title,description:k.description,details:k.details||``,testStrategy:k.testStrategy||``,status:`pending`,dependencies:k.dependencies?.length?k.dependencies:w,priority:_,subtasks:[]};if(k.dependencies?.length&&(k.dependencies.every(e=>{let t=parseInt(e,10);return!Number.isNaN(t)&&u.some(e=>e.id===t)})||(b(`AI suggested invalid dependencies. Filtering them out...`,`warn`),A.dependencies=k.dependencies.filter(e=>{let t=parseInt(e,10);return!Number.isNaN(t)&&u.some(e=>e.id===t)}))),r[a].tasks.push(A),D(r[a],{description:`Tasks for ${a} context`}),b(`DEBUG: Writing tasks.json...`,`debug`),F(e,r,d,a),b(`DEBUG: tasks.json written.`,`debug`),o===`text`){let e=new q({head:[V.cyan.bold(`ID`),V.cyan.bold(`Title`),V.cyan.bold(`Description`)],colWidths:[5,30,50],style:{border:le}});e.push([A.id,R(A.title,27),R(A.description,47)]),console.log(V.green(`✓ New task created successfully:`)),console.log(e.toString());let t=e=>{switch(e?.toLowerCase()){case`high`:return`red`;case`low`:return`dim`;default:return`yellow`}},n=A.dependencies.filter(e=>!w.includes(e)),r=w.filter(e=>!A.dependencies.includes(e)),i={};A.dependencies.forEach(e=>{let t=u.find(t=>t.id===e);t&&(i[e]=R(t.title,30))});let a=``;A.dependencies.length>0?(a=B.text(`Dependencies:`)+`
|
|
690
700
|
`,A.dependencies.forEach(e=>{let t=n.includes(e)?V.yellow(` (AI suggested)`):``;a+=B.text(` - ${e}: ${i[e]||`Unknown task`}${t}`)+`
|
|
691
701
|
`})):a=B.text(`Dependencies: None`)+`
|
|
692
702
|
`,r.length>0&&(a+=B.muted(`
|
|
@@ -699,59 +709,59 @@ User-specified dependencies that were not used:`)+`
|
|
|
699
709
|
`)),console.log(G(B.text.bold(`Task ${S} Created Successfully`)+`
|
|
700
710
|
|
|
701
711
|
`+B.text(`Title: ${A.title}`)+`
|
|
702
|
-
`+B.text(`Status: ${
|
|
712
|
+
`+B.text(`Status: ${Is(A.status)}`)+`
|
|
703
713
|
`+B.text(`Priority: ${V[t(A.priority)](A.priority)}`)+`
|
|
704
714
|
|
|
705
715
|
`+a+o+`
|
|
706
716
|
`+B.text.bold(`Next Steps:`)+`
|
|
707
717
|
`+V.cyan(`1. Run ${V.yellow(`taskgraph show ${S}`)} to see complete task details`)+`
|
|
708
718
|
`+V.cyan(`2. Run ${V.yellow(`taskgraph set-status --id=${S} --status=in-progress`)} to start working on it`)+`
|
|
709
|
-
`+V.cyan(`3. Run ${V.yellow(`taskgraph expand --id=${S}`)} to break it down into subtasks`),{padding:1,borderColor:`green`,borderStyle:`round`})),y&&y.telemetryData&&(p===`cli`||p===`text`)&&
|
|
719
|
+
`+V.cyan(`3. Run ${V.yellow(`taskgraph expand --id=${S}`)} to break it down into subtasks`),{padding:1,borderColor:`green`,borderStyle:`round`})),y&&y.telemetryData&&(p===`cli`||p===`text`)&&Ks(y.telemetryData,`cli`)}return b(`DEBUG: Returning new task ID: ${S} and telemetry.`,`debug`),{newTaskId:S,telemetryData:y?y.telemetryData:null,tagInfo:y?y.tagInfo:null}}catch(e){throw v&&$(v),b(`Error adding task: ${e.message}`,`error`),o===`text`&&console.error(V.red(`Error: ${e.message}`)),e}}const Ni={research:{threshold:.5,limit:20,keys:[{name:`title`,weight:2},{name:`description`,weight:1},{name:`details`,weight:.5},{name:`dependencyTitles`,weight:.5}]},addTask:{threshold:.4,limit:15,keys:[{name:`title`,weight:2},{name:`description`,weight:1.5},{name:`details`,weight:.8},{name:`dependencyTitles`,weight:.5}]},default:{threshold:.4,limit:15,keys:[{name:`title`,weight:2},{name:`description`,weight:1.5},{name:`details`,weight:1},{name:`dependencyTitles`,weight:.5}]}},Pi=[{pattern:/(command|cli|flag)/i,label:`CLI commands`},{pattern:/(task|subtask|add)/i,label:`Task management`},{pattern:/(dependency|depend)/i,label:`Dependency handling`},{pattern:/(AI|model|prompt|research)/i,label:`AI integration`},{pattern:/(UI|display|show|interface)/i,label:`User interface`},{pattern:/(schedule|time|cron)/i,label:`Scheduling`},{pattern:/(config|setting|option)/i,label:`Configuration`},{pattern:/(test|testing|spec)/i,label:`Testing`},{pattern:/(auth|login|user)/i,label:`Authentication`},{pattern:/(database|db|data)/i,label:`Data management`},{pattern:/(api|endpoint|route)/i,label:`API development`},{pattern:/(deploy|build|release)/i,label:`Deployment`},{pattern:/(security|auth|login|user)/i,label:`Security`},{pattern:/.*/,label:`Other`}],Fi={high:.25,medium:.4,low:.6};var Ii=class{constructor(e,t=`default`){this.tasks=e,this.config=Ni[t]||Ni.default,this.searchableTasks=this._prepareSearchableTasks(e),this.fuse=new Ye(this.searchableTasks,{includeScore:!0,threshold:this.config.threshold,keys:this.config.keys,shouldSort:!0,useExtendedSearch:!0,limit:this.config.limit})}_prepareSearchableTasks(e){return e.map(t=>{let n=t.dependencies?.length>0?t.dependencies.map(t=>{let n=e.find(e=>e.id===t);return n?n.title:``}).filter(e=>e).join(` `):``;return{...t,dependencyTitles:n}})}_extractPromptWords(e){return e.toLowerCase().replace(/[^\w\s-]/g,` `).split(/\s+/).filter(e=>e.length>3)}findRelevantTasks(e,t={}){let{maxResults:n=8,includeRecent:r=!0,includeCategoryMatches:i=!0}=t,a=this._extractPromptWords(e),o=this.fuse.search(e),s=[];for(let e of a)if(e.length>5){let t=this.fuse.search(e);t.length>0&&s.push(...t)}let c=[...o];for(let e of s)c.some(t=>t.item.id===e.item.id)||c.push(e);let l=c.filter(e=>e.score<Fi.high).map(e=>({...e.item,score:e.score})),u=c.filter(e=>e.score>=Fi.high&&e.score<Fi.medium).map(e=>({...e.item,score:e.score})),d=c.filter(e=>e.score>=Fi.medium&&e.score<Fi.low).map(e=>({...e.item,score:e.score})),f=r?[...this.tasks].sort((e,t)=>t.id-e.id).slice(0,5):[],p=[],m=null;i&&(m=Pi.find(t=>t.pattern.test(e)),p=m?this.tasks.filter(e=>m.pattern.test(e.title)||m.pattern.test(e.description)||e.details&&m.pattern.test(e.details)).slice(0,3):[]);let h=[...l];for(let e of u)h.some(t=>t.id===e.id)||h.push(e);for(let e of d)h.some(t=>t.id===e.id)||h.push(e);for(let e of p)h.some(t=>t.id===e.id)||h.push(e);for(let e of f)h.some(t=>t.id===e.id)||h.push(e);let g=h.slice(0,n);return{results:g,breakdown:{highRelevance:l,mediumRelevance:u,lowRelevance:d,categoryTasks:p,recentTasks:f,promptCategory:m,promptWords:a},metadata:{totalSearched:this.tasks.length,fuzzyMatches:o.length,wordMatches:s.length,finalCount:g.length}}}getTaskIds(e){return e.results.map(e=>e.id.toString())}getTaskIdsWithSubtasks(e,t=!1){let n=[];for(let r of e.results)if(n.push(r.id.toString()),t&&r.subtasks&&r.subtasks.length>0)for(let e of r.subtasks)n.push(`${r.id}.${e.id}`);return n}formatSearchSummary(e,t={}){let{includeScores:n=!1,includeBreakdown:r=!1}=t,{results:i,breakdown:a,metadata:o}=e,s=`Found ${i.length} relevant tasks from ${o.totalSearched} total tasks`;if(r&&a){let e=[];a.highRelevance.length>0&&e.push(`${a.highRelevance.length} high relevance`),a.mediumRelevance.length>0&&e.push(`${a.mediumRelevance.length} medium relevance`),a.lowRelevance.length>0&&e.push(`${a.lowRelevance.length} low relevance`),a.categoryTasks.length>0&&e.push(`${a.categoryTasks.length} category matches`),e.length>0&&(s+=` (${e.join(`, `)})`),a.promptCategory&&(s+=`\nCategory detected: ${a.promptCategory.label}`)}return s}};async function Li(e,t={}){let{session:n,mcpLog:r}=t,a=e.file||`.taskgraph/tasks/tasks.json`,o=parseFloat(e.threshold||`5`),s=e.research||!1,c=e.projectRoot,l=e.tag,u=e.id?e.id.split(`,`).map(e=>parseInt(e.trim(),10)).filter(e=>!Number.isNaN(e)):null,d=e.from===void 0?null:parseInt(e.from,10),f=e.to===void 0?null:parseInt(e.to,10),p=r?`json`:`text`,m=(e,t=`info`)=>{r?r[t](e):!z()&&p===`text`&&I(t,e)},h=ne(e.output,{projectRoot:c,tag:l},m);p===`text`&&console.log(B.brand(`Analyzing task complexity and generating expansion recommendations...`));try{m(`Reading tasks from ${a}...`,`info`);let t,g=0,_=null;if(e._filteredTasksData){if(t=e._filteredTasksData,g=e._originalTaskCount||t.tasks.length,!e._originalTaskCount)try{_=P(a,c,l),_&&_.tasks&&(g=_.tasks.length)}catch(e){I(`warn`,`Could not read original tasks file: ${e.message}`)}}else{if(_=P(a,c,l),!_||!_.tasks||!Array.isArray(_.tasks)||_.tasks.length===0)throw Error(`No tasks found in the tasks file`);g=_.tasks.length;let e=[`pending`,`blocked`,`in-progress`],n=_.tasks.filter(t=>e.includes(t.status?.toLowerCase()||`pending`));if(u&&u.length>0){if(m(`Filtering tasks by specific IDs: ${u.join(`, `)}`,`info`),n=n.filter(e=>u.includes(e.id)),p===`text`){if(n.length===0&&u.length>0)console.log(V.yellow(`Warning: No active tasks found with IDs: ${u.join(`, `)}`));else if(n.length<u.length){let e=n.map(e=>e.id),t=u.filter(t=>!e.includes(t));console.log(V.yellow(`Warning: Some requested task IDs were not found or are not active: ${t.join(`, `)}`))}}}else if(d!==null||f!==null){let e=d===null?1:d,t=f===null?Math.max(..._.tasks.map(e=>e.id)):f;m(`Filtering tasks by ID range: ${e} to ${t}`,`info`),n=n.filter(n=>n.id>=e&&n.id<=t),p===`text`&&n.length===0&&console.log(V.yellow(`Warning: No active tasks found in range: ${e}-${t}`))}t={..._,tasks:n,_originalTaskCount:g}}let v=``;if(_&&_.tasks.length>0)try{let e=new Ai(c,l),n=new Ii(ae(_.tasks),`analyze-complexity`),r=t.tasks.map(e=>`${e.title} ${e.description}`).join(` `),i=n.findRelevantTasks(r,{maxResults:10}),a=n.getTaskIds(i);a.length>0&&(v=(await e.gather({tasks:a,format:`research`})).context||``)}catch(e){m(`Could not gather additional context: ${e.message}`,`warn`)}let y=g-t.tasks.length;if(m(`Found ${g} total tasks in the task file.`,`info`),u||d!==null||f!==null){let e=u?`Analyzing ${t.tasks.length} tasks with specific IDs: ${u.join(`, `)}`:`Analyzing ${t.tasks.length} tasks in range: ${d||1} to ${f||`end`}`;m(e,`info`),p===`text`&&console.log(B.brand(e))}else if(y>0){let e=`Skipping ${y} tasks marked as done/cancelled/deferred. Analyzing ${t.tasks.length} active tasks.`;m(e,`info`),p===`text`&&console.log(V.yellow(e))}let b=null,x=/* @__PURE__ */ new Map;try{W.existsSync(h)&&(b=JSON.parse(W.readFileSync(h,`utf8`)),m(`Found existing complexity report at ${h}`,`info`),b&&b.complexityAnalysis&&Array.isArray(b.complexityAnalysis)&&(b.complexityAnalysis.forEach(e=>{x.set(e.taskId,e)}),m(`Existing report contains ${b.complexityAnalysis.length} task analyses`,`info`)))}catch(e){m(`Warning: Could not read existing report: ${e.message}`,`warn`),b=null,x.clear()}if(t.tasks.length===0){if(b&&(u||d!==null||f!==null))return m(`No matching tasks found for analysis. Keeping existing report.`,`info`),p===`text`&&console.log(V.yellow(`No matching tasks found for analysis. Keeping existing report.`)),{report:b,telemetryData:null};let e={meta:{generatedAt:(/* @__PURE__ */ new Date()).toISOString(),tasksAnalyzed:0,thresholdScore:o,projectName:me(n),usedResearch:s},complexityAnalysis:b?.complexityAnalysis||[]};return m(`Writing complexity report to ${h}...`,`info`),W.writeFileSync(h,JSON.stringify(e,null,` `),`utf8`),m(`Task complexity analysis complete. Report written to ${h}`,`success`),p===`text`&&(console.log(V.green(`Task complexity analysis complete. Report written to ${h}`)),console.log(`
|
|
710
720
|
Complexity Analysis Summary:`),console.log(`----------------------------`),console.log(`Tasks in input file: ${g}`),console.log(`Tasks successfully analyzed: 0`),console.log(`High complexity tasks: 0`),console.log(`Medium complexity tasks: 0`),console.log(`Low complexity tasks: 0`),console.log(`Sum verification: 0 (should equal 0)`),console.log(`Research-backed analysis: ${s?`Yes`:`No`}`),console.log(`\nSee ${h} for the full report and expansion commands.`),console.log(G(B.text.bold(`Suggested Next Steps:`)+`
|
|
711
721
|
|
|
712
|
-
${V.cyan(`1.`)} Run ${V.yellow(`taskgraph complexity-report`)} to review detailed findings\n${V.cyan(`2.`)} Run ${V.yellow(`taskgraph expand --id=<id>`)} to break down complex tasks\n${V.cyan(`3.`)} Run ${V.yellow(`taskgraph expand --all`)} to expand all pending tasks based on complexity`,{padding:1,borderColor:`cyan`,borderStyle:`round`,margin:{top:1}}))),{report:e,telemetryData:null}}let S=
|
|
722
|
+
${V.cyan(`1.`)} Run ${V.yellow(`taskgraph complexity-report`)} to review detailed findings\n${V.cyan(`2.`)} Run ${V.yellow(`taskgraph expand --id=<id>`)} to break down complex tasks\n${V.cyan(`3.`)} Run ${V.yellow(`taskgraph expand --all`)} to expand all pending tasks based on complexity`,{padding:1,borderColor:`cyan`,borderStyle:`round`,margin:{top:1}}))),{report:e,telemetryData:null}}let S=Oi(),C={tasks:t.tasks,gatheredContext:v||``,useResearch:s,hasCodebaseAnalysis:ee(s,c,n),projectRoot:c||``},{systemPrompt:w,userPrompt:T}=await S.loadPrompt(`analyze-complexity`,C,`default`),E=null;p===`text`&&(E=Ms(`${s?`Researching`:`Analyzing`} the complexity of your tasks with AI...\n`));let D=null,O=null;try{D=await i({prompt:T,systemPrompt:w,role:s?`research`:`main`,session:n,projectRoot:c,schema:gi[`analyze-complexity`],objectName:`complexityAnalysis`,commandName:`analyze-complexity`,outputType:r?`mcp`:`cli`}),E&&=($(E),null),p===`text`&&(Pe.clearLine(process.stdout,0),Pe.cursorTo(process.stdout,0),console.log(V.green(`AI service call complete.`))),O=D.mainResult?.complexityAnalysis,m(`Received ${O.length} complexity analyses from AI.`,`info`);let e=t.tasks.map(e=>e.id),a=O.map(e=>e.taskId),l=e.filter(e=>!a.includes(e));if(l.length>0){m(`Missing analysis for ${l.length} tasks: ${l.join(`, `)}`,`warn`),p===`text`&&console.log(V.yellow(`Missing analysis for ${l.length} tasks: ${l.join(`, `)}`));for(let e of l){let n=t.tasks.find(t=>t.id===e);n&&(m(`Adding default analysis for task ${e}`,`info`),O.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 u=[];if(b&&Array.isArray(b.complexityAnalysis)){let e=new Set(O.map(e=>e.taskId)),n=new Set(t.tasks.map(e=>e.id)),r=b.complexityAnalysis.filter(t=>!e.has(t.taskId)&&n.has(t.taskId));u=[...r,...O],m(`Merged ${O.length} new analyses with ${r.length} existing entries from current tag`,`info`)}else u=O;let d={meta:{generatedAt:(/* @__PURE__ */ new Date()).toISOString(),tasksAnalyzed:t.tasks.length,totalTasks:g,analysisCount:u.length,thresholdScore:o,projectName:me(n),usedResearch:s},complexityAnalysis:u};if(m(`Writing complexity report to ${h}...`,`info`),W.writeFileSync(h,JSON.stringify(d,null,` `),`utf8`),m(`Task complexity analysis complete. Report written to ${h}`,`success`),p===`text`){console.log(V.green(`Task complexity analysis complete. Report written to ${h}`));let e=O.filter(e=>e.complexityScore>=8).length,t=O.filter(e=>e.complexityScore>=5&&e.complexityScore<8).length,r=O.filter(e=>e.complexityScore<5).length,i=O.length;console.log(`
|
|
713
723
|
Current Analysis Summary:`),console.log(`----------------------------`),console.log(`Tasks analyzed in this run: ${i}`),console.log(`High complexity tasks: ${e}`),console.log(`Medium complexity tasks: ${t}`),console.log(`Low complexity tasks: ${r}`),b&&(console.log(`
|
|
714
724
|
Updated Report Summary:`),console.log(`----------------------------`),console.log(`Total analyses in report: ${u.length}`),console.log(`Analyses from previous runs: ${u.length-i}`),console.log(`New/updated analyses: ${i}`)),console.log(`Research-backed analysis: ${s?`Yes`:`No`}`),console.log(`\nSee ${h} for the full report and expansion commands.`),console.log(G(B.text.bold(`Suggested Next Steps:`)+`
|
|
715
725
|
|
|
716
|
-
${V.cyan(`1.`)} Run ${V.yellow(`taskgraph complexity-report`)} to review detailed findings\n${V.cyan(`2.`)} Run ${V.yellow(`taskgraph expand --id=<id>`)} to break down complex tasks\n${V.cyan(`3.`)} Run ${V.yellow(`taskgraph expand --all`)} to expand all pending tasks based on complexity`,{padding:1,borderColor:`cyan`,borderStyle:`round`,margin:{top:1}})),L(n)&&console.debug(B.muted(`Final analysis object: ${JSON.stringify(d,null,2)}`)),D.telemetryData&&
|
|
717
|
-
Please ensure your API keys are correctly configured in .env or ~/.taskgraph/.env`)),console.log(V.yellow(`Run 'taskgraph models --setup' if needed.`)))),e}}catch(e){if(m(`Error analyzing task complexity: ${e.message}`,`error`),p===`text`)console.error(V.red(`Error analyzing task complexity: ${e.message}`)),L(n)&&console.error(e),process.exit(1);else throw e}}function
|
|
726
|
+
${V.cyan(`1.`)} Run ${V.yellow(`taskgraph complexity-report`)} to review detailed findings\n${V.cyan(`2.`)} Run ${V.yellow(`taskgraph expand --id=<id>`)} to break down complex tasks\n${V.cyan(`3.`)} Run ${V.yellow(`taskgraph expand --all`)} to expand all pending tasks based on complexity`,{padding:1,borderColor:`cyan`,borderStyle:`round`,margin:{top:1}})),L(n)&&console.debug(B.muted(`Final analysis object: ${JSON.stringify(d,null,2)}`)),D.telemetryData&&Ks(D.telemetryData,`cli`)}return{report:d,telemetryData:D?.telemetryData,tagInfo:D?.tagInfo}}catch(e){throw E&&$(E),m(`Error during AI service call: ${e.message}`,`error`),p===`text`&&(console.error(V.red(`Error during AI service call: ${e.message}`)),e.message.includes(`API key`)&&(console.log(V.yellow(`
|
|
727
|
+
Please ensure your API keys are correctly configured in .env or ~/.taskgraph/.env`)),console.log(V.yellow(`Run 'taskgraph models --setup' if needed.`)))),e}}catch(e){if(m(`Error analyzing task complexity: ${e.message}`,`error`),p===`text`)console.error(V.red(`Error analyzing task complexity: ${e.message}`)),L(n)&&console.error(e),process.exit(1);else throw e}}function Ri(e,t,n={}){let{projectRoot:r,tag:i}=n;I(`info`,`Reading tasks from ${e}...`);let a=P(e,r,i);(!a||!a.tasks)&&(I(`error`,`No valid tasks found.`),process.exit(1)),z()||console.log(G(B.text.bold(`Clearing Subtasks`),{padding:1,borderColor:N,borderStyle:`round`,margin:{top:1,bottom:1}}));let o=t.split(`,`).map(e=>e.trim()),s=0,c=new q({head:[V.cyan.bold(`Task ID`),V.cyan.bold(`Task Title`),V.cyan.bold(`Subtasks Cleared`)],colWidths:[10,50,20],style:{head:[],border:[]}});o.forEach(e=>{let t=parseInt(e,10);if(Number.isNaN(t)){I(`error`,`Invalid task ID: ${e}`);return}let n=a.tasks.find(e=>e.id===t);if(!n){I(`error`,`Task ${t} not found`);return}if(!n.subtasks||n.subtasks.length===0){I(`info`,`Task ${t} has no subtasks to clear`),c.push([t.toString(),R(n.title,47),V.yellow(`No subtasks`)]);return}let r=n.subtasks.length;n.subtasks=[],s++,I(`info`,`Cleared ${r} subtasks from task ${t}`),c.push([t.toString(),R(n.title,47),V.green(`${r} subtasks cleared`)])}),s>0?(F(e,a,r,i),z()||(console.log(G(B.text.bold(`Subtask Clearing Summary:`),{padding:{left:2,right:2,top:0,bottom:0},margin:{top:1,bottom:0},borderColor:N,borderStyle:`round`})),console.log(c.toString())),z()||(console.log(G(V.green(`Successfully cleared subtasks from ${V.bold(s)} task(s)`),{padding:1,borderColor:`green`,borderStyle:`round`,margin:{top:1}})),console.log(G(B.text.bold(`Next Steps:`)+`
|
|
718
728
|
|
|
719
|
-
${V.cyan(`1.`)} Run ${V.yellow(`taskgraph expand --id=<id>`)} to generate new subtasks\n${V.cyan(`2.`)} Run ${V.yellow(`taskgraph list --with-subtasks`)} to verify changes`,{padding:1,borderColor:`cyan`,borderStyle:`round`,margin:{top:1}})))):z()||console.log(G(V.yellow(`No subtasks were cleared`),{padding:1,borderColor:`yellow`,borderStyle:`round`,margin:{top:1}}))}function Oi(e,t){let n=!!e,r=e||{info:e=>!z()&&I(`info`,e),warn:e=>!z()&&I(`warn`,e),error:e=>!z()&&I(`error`,e),debug:e=>!z()&&L(t)&&I(`debug`,e)};return{logger:r,report:(e,...t)=>{n?typeof r[e]==`function`?r[e](...t):r.info(...t):z()||I(e,...t)},isMCP:n}}async function ki(e,t,n,r=!1,a=``,o={},s=!1){let{session:c,mcpLog:l,projectRoot:u,tag:d,complexityReportPath:f}=o,p=l?`json`:`text`,m=u||Se(e),{logger:h,report:g,isMCP:_}=Oi(l,c);_&&h.info(`expandTask called with context: session=${!!c}`);try{h.info(`Reading tasks from ${e}`);let o=P(e,m,d);if(!o||!o.tasks)throw Error(`Invalid tasks data in ${e}`);let l=o.tasks.findIndex(e=>e.id===parseInt(t,10));if(l===-1)throw Error(`Task ${t} not found`);let u=o.tasks[l];h.info(`Expanding task ${t}: ${u.title}${r?` with research`:``}`),s&&Array.isArray(u.subtasks)&&u.subtasks.length>0&&(h.info(`Force flag set. Clearing existing ${u.subtasks.length} subtasks for task ${t}.`),u.subtasks=[]);let g=``;try{let e=new yi(m,d),n=new Ti(ae(o.tasks),`expand-task`),r=`${u.title} ${u.description}`,i=n.findRelevantTasks(r,{maxResults:5,includeSelf:!0}),a=n.getTaskIds(i),s=[.../* @__PURE__ */ new Set([t.toString(),...a])];s.length>0&&(g=(await e.gather({tasks:s,format:`research`})).context||``)}catch(e){h.warn(`Could not gather context: ${e.message}`)}let _,v=``,y=null;h.info(`Looking for complexity report at: ${f}${d===`master`?``:` (tag-specific for '${d}')`}`);try{W.existsSync(f)?(y=P(f)?.complexityAnalysis?.find(e=>e.taskId===u.id),y?(h.info(`Found complexity analysis for task ${u.id}: Score ${y.complexityScore}`),y.reasoning&&(v=`\nComplexity Analysis Reasoning: ${y.reasoning}`)):h.info(`No complexity analysis found for task ${u.id} in report.`)):h.info(`Complexity report not found at ${f}. Skipping complexity check.`)}catch(e){h.warn(`Could not read or parse complexity report: ${e.message}. Proceeding without it.`)}let b=parseInt(n,10);if(!Number.isNaN(b)&&b>=0)_=b,h.info(`Using explicitly provided subtask count: ${_}`);else if(y?.recommendedSubtasks!=null){if(_=parseInt(y.recommendedSubtasks,10),h.info(`Using subtask count from complexity report: ${_}`),_===0)return h.info(`Complexity report recommends no expansion for task ${t}. Skipping.`),{task:u,skipped:!0}}else _=_e(c),h.info(`Using default number of subtasks: ${_}`);(Number.isNaN(_)||_<0)&&(h.warn(`Invalid subtask count determined (${_}), defaulting to 3.`),_=3);let x=(u.subtasks?.length||0)+1,S=_i(),C=ee(r,m,c),w=``;(a||v)&&(w=`\n\n${a}${v}`.trim()),g&&(w=`${w}\n\n# Project Context\n\n${g}`.trim());let T;y?.expansionPrompt&&(typeof y.expansionPrompt==`string`?T=y.expansionPrompt:typeof y.expansionPrompt==`object`&&y.expansionPrompt.text&&(T=y.expansionPrompt.text));let E=g;typeof g==`object`&&g&&(E=g.data?g.data:g.text?g.text:JSON.stringify(g));let D={task:u,subtaskCount:_,nextSubtaskId:x,additionalContext:a,complexityReasoningContext:v,gatheredContext:E||``,useResearch:r,expansionPrompt:T||void 0,hasCodebaseAnalysis:C,projectRoot:m||``},O=`default`;T?(O=`complexity-report`,h.info(`Using expansion prompt from complexity report for task ${u.id}.`)):r?(O=`research`,h.info(`Using research variant for task ${u.id}.`)):h.info(`Using standard prompt generation for task ${u.id}.`);let{systemPrompt:k,userPrompt:A}=S.loadPrompt(`expand-task`,D,O);h.debug(`Selected variant: ${O}`),h.debug(`Prompt params passed: ${JSON.stringify(D,null,2)}`),h.debug(`System prompt (first 500 chars): ${k.substring(0,500)}...`),h.debug(`User prompt (first 500 chars): ${A.substring(0,500)}...`);let te=[],j=null;p===`text`&&(j=bs(`Generating ${_||`appropriate number of`} subtasks...\n`));let M=null;try{M=await i({prompt:A,systemPrompt:k,role:r?`research`:`main`,session:c,projectRoot:m,schema:ai[`expand-task`],objectName:`subtasks`,commandName:`expand-task`,outputType:p});let e=M?.mainResult;if(!e||!Array.isArray(e.subtasks))throw Error(`AI response did not include a valid subtasks array.`);te=e.subtasks.map(e=>({...e,dependencies:e.dependencies??[],status:e.status??`pending`,testStrategy:e.testStrategy??null})),h.info(`Received ${te.length} subtasks from AI.`)}catch(e){throw j&&$(j),h.error(`Error during AI call or parsing for task ${t}: ${e.message}`,`error`),e}finally{j&&$(j)}return Array.isArray(u.subtasks)||(u.subtasks=[]),u.subtasks.push(...te),o.tasks[l]=u,F(e,o,m,d),p===`text`&&M&&M.telemetryData&&Ps(M.telemetryData,`cli`),{task:u,telemetryData:M?.telemetryData,tagInfo:M?.tagInfo}}catch(e){throw h.error(`Error expanding task ${t}: ${e.message}`,`error`),p===`text`&&L(c)&&console.error(e),e}}async function Ai(e,t,n=!1,r=``,i=!1,a={},o=`text`){let{session:s,mcpLog:c,projectRoot:l,tag:u,complexityReportPath:d}=a,f=!!c,p=l||Se();if(!p)throw Error(`Could not determine project root directory`);let m=c||(o===`json`?{info:e=>{},warn:e=>{},error:e=>console.error(`ERROR: ${e}`),debug:e=>{}}:{info:e=>!z()&&I(`info`,e),warn:e=>!z()&&I(`warn`,e),error:e=>!z()&&I(`error`,e),debug:e=>!z()&&L(s)&&I(`debug`,e)}),h=null,g=0,_=0,v=0,y=0,b=[];!f&&o===`text`&&(h=bs(`Analyzing tasks for expansion...`));try{m.info(`Reading tasks from ${e}`);let s=P(e,p,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));if(y=c.length,m.info(`Found ${y} tasks eligible for expansion.`),h&&$(h,`Analysis complete.`),y===0)return m.info(`No tasks eligible for expansion.`),{success:!0,expandedCount:0,failedCount:0,skippedCount:0,tasksToExpand:0,telemetryData:b,message:`No tasks eligible for expansion.`};for(let l of c){let c=null;!f&&o===`text`&&(c=bs(`Expanding task ${l.id}...`));try{let o=await ki(e,l.id,t,n,r,{...a,projectRoot:p,tag:s.tag||u,complexityReportPath:d},i);if(o?.skipped){v++,c&&$(c,`Task ${l.id} skipped (no expansion recommended).`),m.info(`Skipped task ${l.id}: complexity report recommends no expansion.`);continue}g++,o&&o.telemetryData&&b.push(o.telemetryData),c&&$(c,`Task ${l.id} expanded.`),m.info(`Successfully expanded task ${l.id}.`)}catch(e){_++,c&&$(c,`Failed to expand task ${l.id}.`,!1),m.error(`Failed to expand task ${l.id}: ${e.message}`)}}m.info(`Expansion complete: ${g} expanded, ${v} skipped, ${_} failed.`);let l=ie(b,`expand-all-tasks`);if(o===`text`){let e=`${B.text.bold(`Expansion Summary:`)}\n\n${V.cyan(`-`)} Attempted: ${V.bold(y)}\n${V.green(`-`)} Expanded: ${V.bold(g)}\n${B.muted(`-`)} Skipped: ${V.bold(v)}\n${V.red(`-`)} Failed: ${V.bold(_)}`;console.log(G(e,{padding:1,margin:{top:1},borderColor:_>0?`red`:`green`,borderStyle:`round`}))}return o===`text`&&l&&Ps(l,`cli`),{success:!0,expandedCount:g,failedCount:_,skippedCount:v,tasksToExpand:y,telemetryData:l}}catch(e){throw h&&$(h,`Error.`,!1),m.error(`Error during expand all operation: ${e.message}`),!f&&L(s)&&console.error(e),e}}function ji(e,t,n){if(t.parentTaskId===n||t.dependencies&&t.dependencies.includes(n))return!0;if(t.dependencies)for(let r of t.dependencies){let t=e.find(e=>e.id===r);if(t&&ji(e,t,n))return!0}if(t.subtasks){for(let r of t.subtasks)if(ji(e,r,n))return!0}return!1}async function Mi(e,t,n=null,r=!1,i=`text`,a={}){let{projectRoot:o,tag:s}=a;try{let a;try{let e=await(await b({projectPath:o||process.cwd()})).tasks.list({tag:s});a={tasks:e.tasks},I(`debug`,`Loaded ${e.tasks.length} tasks via tm-core`)}catch(t){I(`warn`,`TmCore failed, falling back to legacy readJSON: ${t.message}`),a=P(e,o,s)}if(!a||!a.tasks)throw Error(`No valid tasks found in ${e}`);let c=we(n);c&&c.complexityAnalysis&&a.tasks.forEach(e=>T(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,d=a.tasks.filter(e=>e.status===`done`||e.status===`completed`).length,f=u>0?d/u*100:0,p=d,m=a.tasks.filter(e=>e.status===`in-progress`).length,h=a.tasks.filter(e=>e.status===`pending`).length,g=a.tasks.filter(e=>e.status===`blocked`).length,_=a.tasks.filter(e=>e.status===`deferred`).length,v=a.tasks.filter(e=>e.status===`cancelled`).length,y=a.tasks.filter(e=>e.status===`review`).length,x=0,S=0,C=0,w=0,ee=0,E=0,D=0,O=0;a.tasks.forEach(e=>{e.subtasks&&e.subtasks.length>0&&(x+=e.subtasks.length,S+=e.subtasks.filter(e=>e.status===`done`||e.status===`completed`).length,C+=e.subtasks.filter(e=>e.status===`in-progress`).length,w+=e.subtasks.filter(e=>e.status===`pending`).length,ee+=e.subtasks.filter(e=>e.status===`blocked`).length,E+=e.subtasks.filter(e=>e.status===`deferred`).length,D+=e.subtasks.filter(e=>e.status===`cancelled`).length,O+=e.subtasks.filter(e=>e.status===`review`).length)});let k=x>0?S/x*100:0,A=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,j=a.tasks.filter(e=>e.status!==`done`&&e.status!==`completed`&&e.dependencies&&e.dependencies.length>0&&e.dependencies.every(e=>A.has(e))).length,M=a.tasks.filter(e=>e.status!==`done`&&e.status!==`completed`&&e.dependencies&&e.dependencies.length>0&&!e.dependencies.every(e=>A.has(e))).length,ne=te+j,re={};a.tasks.forEach(e=>{e.dependencies&&e.dependencies.length>0&&e.dependencies.forEach(e=>{re[e]=(re[e]||0)+1})});let ie=null,ae=0;for(let[e,t]of Object.entries(re))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,N=Wn(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:p,inProgress:m,pending:h,blocked:g,deferred:_,cancelled:v,review:y,completionPercentage:f,subtasks:{total:x,completed:S,inProgress:C,pending:w,blocked:ee,deferred:E,cancelled:D,completionPercentage:k}}};if(i===`markdown-readme`)return Pi(a,l,{totalTasks:u,completedTasks:d,completionPercentage:f,doneCount:p,inProgressCount:m,pendingCount:h,blockedCount:g,deferredCount:_,cancelledCount:v,totalSubtasks:x,completedSubtasks:S,subtaskCompletionPercentage:k,inProgressSubtasks:C,pendingSubtasks:w,blockedSubtasks:ee,deferredSubtasks:E,cancelledSubtasks:D,reviewSubtasks:O,tasksWithNoDeps:te,tasksReadyToWork:ne,tasksWithUnsatisfiedDeps:M,mostDependedOnTask:oe,mostDependedOnTaskId:ie,maxDependents:ae,avgDependenciesPerTask:se,complexityReport:c,withSubtasks:r,nextItem:N});if(i===`compact`)return Ri(l,r);let ce={"in-progress":u>0?m/u*100:0,pending:u>0?h/u*100:0,blocked:u>0?g/u*100:0,deferred:u>0?_/u*100:0,cancelled:u>0?v/u*100:0,review:u>0?y/u*100:0},le={"in-progress":x>0?C/x*100:0,pending:x>0?w/x*100:0,blocked:x>0?ee/x*100:0,deferred:x>0?E/x*100:0,cancelled:x>0?D/x*100:0,review:x>0?O/x*100:0},ue=Cs(f,30,ce),de=Cs(k,30,le),fe;try{fe=process.stdout.columns}catch{I(`debug`,`Could not determine terminal width, using default`)}fe||=80,fe=Math.max(fe,80);let pe=V.bold(`Project Dashboard`)+`
|
|
729
|
+
${V.cyan(`1.`)} Run ${V.yellow(`taskgraph expand --id=<id>`)} to generate new subtasks\n${V.cyan(`2.`)} Run ${V.yellow(`taskgraph list --with-subtasks`)} to verify changes`,{padding:1,borderColor:`cyan`,borderStyle:`round`,margin:{top:1}})))):z()||console.log(G(V.yellow(`No subtasks were cleared`),{padding:1,borderColor:`yellow`,borderStyle:`round`,margin:{top:1}}))}function zi(e,t){let n=!!e,r=e||{info:e=>!z()&&I(`info`,e),warn:e=>!z()&&I(`warn`,e),error:e=>!z()&&I(`error`,e),debug:e=>!z()&&L(t)&&I(`debug`,e)};return{logger:r,report:(e,...t)=>{n?typeof r[e]==`function`?r[e](...t):r.info(...t):z()||I(e,...t)},isMCP:n}}async function Bi(e,t,n,r=!1,a=``,o={},s=!1){let{session:c,mcpLog:l,projectRoot:u,tag:d,complexityReportPath:f}=o,p=l?`json`:`text`,m=u||Se(e),{logger:h,report:g,isMCP:_}=zi(l,c);_&&h.info(`expandTask called with context: session=${!!c}`);try{h.info(`Reading tasks from ${e}`);let o=P(e,m,d);if(!o||!o.tasks)throw Error(`Invalid tasks data in ${e}`);let l=o.tasks.findIndex(e=>e.id===parseInt(t,10));if(l===-1)throw Error(`Task ${t} not found`);let u=o.tasks[l];h.info(`Expanding task ${t}: ${u.title}${r?` with research`:``}`),s&&Array.isArray(u.subtasks)&&u.subtasks.length>0&&(h.info(`Force flag set. Clearing existing ${u.subtasks.length} subtasks for task ${t}.`),u.subtasks=[]);let g=``;try{let e=new Ai(m,d),n=new Ii(ae(o.tasks),`expand-task`),r=`${u.title} ${u.description}`,i=n.findRelevantTasks(r,{maxResults:5,includeSelf:!0}),a=n.getTaskIds(i),s=[.../* @__PURE__ */ new Set([t.toString(),...a])];s.length>0&&(g=(await e.gather({tasks:s,format:`research`})).context||``)}catch(e){h.warn(`Could not gather context: ${e.message}`)}let _,v=``,y=null;h.info(`Looking for complexity report at: ${f}${d===`master`?``:` (tag-specific for '${d}')`}`);try{W.existsSync(f)?(y=P(f)?.complexityAnalysis?.find(e=>e.taskId===u.id),y?(h.info(`Found complexity analysis for task ${u.id}: Score ${y.complexityScore}`),y.reasoning&&(v=`\nComplexity Analysis Reasoning: ${y.reasoning}`)):h.info(`No complexity analysis found for task ${u.id} in report.`)):h.info(`Complexity report not found at ${f}. Skipping complexity check.`)}catch(e){h.warn(`Could not read or parse complexity report: ${e.message}. Proceeding without it.`)}let b=parseInt(n,10);if(!Number.isNaN(b)&&b>=0)_=b,h.info(`Using explicitly provided subtask count: ${_}`);else if(y?.recommendedSubtasks!=null){if(_=parseInt(y.recommendedSubtasks,10),h.info(`Using subtask count from complexity report: ${_}`),_===0)return h.info(`Complexity report recommends no expansion for task ${t}. Skipping.`),{task:u,skipped:!0}}else _=_e(c),h.info(`Using default number of subtasks: ${_}`);(Number.isNaN(_)||_<0)&&(h.warn(`Invalid subtask count determined (${_}), defaulting to 3.`),_=3);let x=(u.subtasks?.length||0)+1,S=Oi(),C=ee(r,m,c),w=``;(a||v)&&(w=`\n\n${a}${v}`.trim()),g&&(w=`${w}\n\n# Project Context\n\n${g}`.trim());let T;y?.expansionPrompt&&(typeof y.expansionPrompt==`string`?T=y.expansionPrompt:typeof y.expansionPrompt==`object`&&y.expansionPrompt.text&&(T=y.expansionPrompt.text));let E=g;typeof g==`object`&&g&&(E=g.data?g.data:g.text?g.text:JSON.stringify(g));let D={task:u,subtaskCount:_,nextSubtaskId:x,additionalContext:a,complexityReasoningContext:v,gatheredContext:E||``,useResearch:r,expansionPrompt:T||void 0,hasCodebaseAnalysis:C,projectRoot:m||``},O=`default`;T?(O=`complexity-report`,h.info(`Using expansion prompt from complexity report for task ${u.id}.`)):r?(O=`research`,h.info(`Using research variant for task ${u.id}.`)):h.info(`Using standard prompt generation for task ${u.id}.`);let{systemPrompt:k,userPrompt:A}=S.loadPrompt(`expand-task`,D,O);h.debug(`Selected variant: ${O}`),h.debug(`Prompt params passed: ${JSON.stringify(D,null,2)}`),h.debug(`System prompt (first 500 chars): ${k.substring(0,500)}...`),h.debug(`User prompt (first 500 chars): ${A.substring(0,500)}...`);let te=[],j=null;p===`text`&&(j=Ms(`Generating ${_||`appropriate number of`} subtasks...\n`));let M=null;try{M=await i({prompt:A,systemPrompt:k,role:r?`research`:`main`,session:c,projectRoot:m,schema:gi[`expand-task`],objectName:`subtasks`,commandName:`expand-task`,outputType:p});let e=M?.mainResult;if(!e||!Array.isArray(e.subtasks))throw Error(`AI response did not include a valid subtasks array.`);te=e.subtasks.map(e=>({...e,dependencies:e.dependencies??[],status:e.status??`pending`,testStrategy:e.testStrategy??null})),h.info(`Received ${te.length} subtasks from AI.`)}catch(e){throw j&&$(j),h.error(`Error during AI call or parsing for task ${t}: ${e.message}`,`error`),e}finally{j&&$(j)}return Array.isArray(u.subtasks)||(u.subtasks=[]),u.subtasks.push(...te),o.tasks[l]=u,F(e,o,m,d),p===`text`&&M&&M.telemetryData&&Ks(M.telemetryData,`cli`),{task:u,telemetryData:M?.telemetryData,tagInfo:M?.tagInfo}}catch(e){throw h.error(`Error expanding task ${t}: ${e.message}`,`error`),p===`text`&&L(c)&&console.error(e),e}}async function Vi(e,t,n=!1,r=``,i=!1,a={},o=`text`){let{session:s,mcpLog:c,projectRoot:l,tag:u,complexityReportPath:d}=a,f=!!c,p=l||Se();if(!p)throw Error(`Could not determine project root directory`);let m=c||(o===`json`?{info:e=>{},warn:e=>{},error:e=>console.error(`ERROR: ${e}`),debug:e=>{}}:{info:e=>!z()&&I(`info`,e),warn:e=>!z()&&I(`warn`,e),error:e=>!z()&&I(`error`,e),debug:e=>!z()&&L(s)&&I(`debug`,e)}),h=null,g=0,_=0,v=0,y=0,b=[];!f&&o===`text`&&(h=Ms(`Analyzing tasks for expansion...`));try{m.info(`Reading tasks from ${e}`);let s=P(e,p,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));if(y=c.length,m.info(`Found ${y} tasks eligible for expansion.`),h&&$(h,`Analysis complete.`),y===0)return m.info(`No tasks eligible for expansion.`),{success:!0,expandedCount:0,failedCount:0,skippedCount:0,tasksToExpand:0,telemetryData:b,message:`No tasks eligible for expansion.`};for(let l of c){let c=null;!f&&o===`text`&&(c=Ms(`Expanding task ${l.id}...`));try{let o=await Bi(e,l.id,t,n,r,{...a,projectRoot:p,tag:s.tag||u,complexityReportPath:d},i);if(o?.skipped){v++,c&&$(c,`Task ${l.id} skipped (no expansion recommended).`),m.info(`Skipped task ${l.id}: complexity report recommends no expansion.`);continue}g++,o&&o.telemetryData&&b.push(o.telemetryData),c&&$(c,`Task ${l.id} expanded.`),m.info(`Successfully expanded task ${l.id}.`)}catch(e){_++,c&&$(c,`Failed to expand task ${l.id}.`,!1),m.error(`Failed to expand task ${l.id}: ${e.message}`)}}m.info(`Expansion complete: ${g} expanded, ${v} skipped, ${_} failed.`);let l=ie(b,`expand-all-tasks`);if(o===`text`){let e=`${B.text.bold(`Expansion Summary:`)}\n\n${V.cyan(`-`)} Attempted: ${V.bold(y)}\n${V.green(`-`)} Expanded: ${V.bold(g)}\n${B.muted(`-`)} Skipped: ${V.bold(v)}\n${V.red(`-`)} Failed: ${V.bold(_)}`;console.log(G(e,{padding:1,margin:{top:1},borderColor:_>0?`red`:`green`,borderStyle:`round`}))}return o===`text`&&l&&Ks(l,`cli`),{success:!0,expandedCount:g,failedCount:_,skippedCount:v,tasksToExpand:y,telemetryData:l}}catch(e){throw h&&$(h,`Error.`,!1),m.error(`Error during expand all operation: ${e.message}`),!f&&L(s)&&console.error(e),e}}function Hi(e,t,n){if(t.parentTaskId===n||t.dependencies&&t.dependencies.includes(n))return!0;if(t.dependencies)for(let r of t.dependencies){let t=e.find(e=>e.id===r);if(t&&Hi(e,t,n))return!0}if(t.subtasks){for(let r of t.subtasks)if(Hi(e,r,n))return!0}return!1}async function Ui(e,t,n=null,r=!1,i=`text`,a={}){let{projectRoot:o,tag:s}=a;try{let a;try{let e=await(await b({projectPath:o||process.cwd()})).tasks.list({tag:s});a={tasks:e.tasks},I(`debug`,`Loaded ${e.tasks.length} tasks via tm-core`)}catch(t){I(`warn`,`TmCore failed, falling back to legacy readJSON: ${t.message}`),a=P(e,o,s)}if(!a||!a.tasks)throw Error(`No valid tasks found in ${e}`);let c=we(n);c&&c.complexityAnalysis&&a.tasks.forEach(e=>T(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,d=a.tasks.filter(e=>e.status===`done`||e.status===`completed`).length,f=u>0?d/u*100:0,p=d,m=a.tasks.filter(e=>e.status===`in-progress`).length,h=a.tasks.filter(e=>e.status===`pending`).length,g=a.tasks.filter(e=>e.status===`blocked`).length,_=a.tasks.filter(e=>e.status===`deferred`).length,v=a.tasks.filter(e=>e.status===`cancelled`).length,y=a.tasks.filter(e=>e.status===`review`).length,x=0,S=0,C=0,w=0,ee=0,E=0,D=0,O=0;a.tasks.forEach(e=>{e.subtasks&&e.subtasks.length>0&&(x+=e.subtasks.length,S+=e.subtasks.filter(e=>e.status===`done`||e.status===`completed`).length,C+=e.subtasks.filter(e=>e.status===`in-progress`).length,w+=e.subtasks.filter(e=>e.status===`pending`).length,ee+=e.subtasks.filter(e=>e.status===`blocked`).length,E+=e.subtasks.filter(e=>e.status===`deferred`).length,D+=e.subtasks.filter(e=>e.status===`cancelled`).length,O+=e.subtasks.filter(e=>e.status===`review`).length)});let k=x>0?S/x*100:0,A=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,j=a.tasks.filter(e=>e.status!==`done`&&e.status!==`completed`&&e.dependencies&&e.dependencies.length>0&&e.dependencies.every(e=>A.has(e))).length,M=a.tasks.filter(e=>e.status!==`done`&&e.status!==`completed`&&e.dependencies&&e.dependencies.length>0&&!e.dependencies.every(e=>A.has(e))).length,ne=te+j,re={};a.tasks.forEach(e=>{e.dependencies&&e.dependencies.length>0&&e.dependencies.forEach(e=>{re[e]=(re[e]||0)+1})});let ie=null,ae=0;for(let[e,t]of Object.entries(re))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,N=Jn(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:p,inProgress:m,pending:h,blocked:g,deferred:_,cancelled:v,review:y,completionPercentage:f,subtasks:{total:x,completed:S,inProgress:C,pending:w,blocked:ee,deferred:E,cancelled:D,completionPercentage:k}}};if(i===`markdown-readme`)return Gi(a,l,{totalTasks:u,completedTasks:d,completionPercentage:f,doneCount:p,inProgressCount:m,pendingCount:h,blockedCount:g,deferredCount:_,cancelledCount:v,totalSubtasks:x,completedSubtasks:S,subtaskCompletionPercentage:k,inProgressSubtasks:C,pendingSubtasks:w,blockedSubtasks:ee,deferredSubtasks:E,cancelledSubtasks:D,reviewSubtasks:O,tasksWithNoDeps:te,tasksReadyToWork:ne,tasksWithUnsatisfiedDeps:M,mostDependedOnTask:oe,mostDependedOnTaskId:ie,maxDependents:ae,avgDependenciesPerTask:se,complexityReport:c,withSubtasks:r,nextItem:N});if(i===`compact`)return Yi(l,r);let ce={"in-progress":u>0?m/u*100:0,pending:u>0?h/u*100:0,blocked:u>0?g/u*100:0,deferred:u>0?_/u*100:0,cancelled:u>0?v/u*100:0,review:u>0?y/u*100:0},le={"in-progress":x>0?C/x*100:0,pending:x>0?w/x*100:0,blocked:x>0?ee/x*100:0,deferred:x>0?E/x*100:0,cancelled:x>0?D/x*100:0,review:x>0?O/x*100:0},ue=Fs(f,30,ce),de=Fs(k,30,le),fe;try{fe=process.stdout.columns}catch{I(`debug`,`Could not determine terminal width, using default`)}fe||=80,fe=Math.max(fe,80);let pe=V.bold(`Project Dashboard`)+`
|
|
720
730
|
Tasks Progress: ${V.greenBright(ue)} ${f.toFixed(0)}%\n${V.green(`█`)} Done: ${V.green(p)} ${V.cyan(`▓`)} In Progress: ${V.cyan(m)} ${V.yellow(`░`)} Pending: ${V.yellow(h)} ${V.red(`!`)} Blocked: ${V.red(g)} ${Q.muted(`─`)} Deferred: ${Q.muted(_)} ${Q.muted(`─`)} Cancelled: ${Q.muted(v)}\n\nSubtasks Progress: ${V.cyan(de)} ${k.toFixed(0)}%\n${V.green(`█`)} Completed: ${V.green(S)}/${x} ${V.cyan(`▓`)} In Progress: ${V.cyan(C)} ${V.yellow(`░`)} Pending: ${V.yellow(w)} ${V.red(`!`)} Blocked: ${V.red(ee)} ${Q.muted(`─`)} Deferred: ${Q.muted(E)} ${Q.muted(`─`)} Cancelled: ${Q.muted(D)}\n\n`+V.cyan.bold(`Priority Breakdown:`)+`
|
|
721
731
|
${V.red(`•`)} ${V.reset(`High priority:`)} ${a.tasks.filter(e=>e.priority===`high`).length}\n${V.yellow(`•`)} ${V.reset(`Medium priority:`)} ${a.tasks.filter(e=>e.priority===`medium`).length}\n${V.green(`•`)} ${V.reset(`Low priority:`)} ${a.tasks.filter(e=>e.priority===`low`).length}`,me=V.bold(`Dependency Status & Next Task`)+`
|
|
722
732
|
`+V.cyan.bold(`Dependency Metrics:`)+`
|
|
723
733
|
${V.green(`•`)} ${V.reset(`Tasks with no dependencies:`)} ${te}\n${V.green(`•`)} ${V.reset(`Tasks ready to work on:`)} ${ne}\n${V.yellow(`•`)} ${V.reset(`Tasks blocked by dependencies:`)} ${M}\n${V.magenta(`•`)} ${V.reset(`Most depended-on task:`)} ${oe?V.cyan(`#${ie} (${ae} dependents)`):Q.muted(`None`)}\n${V.cyan(`•`)} ${V.reset(`Avg dependencies per task:`)} ${se.toFixed(1)}\n\n`+V.cyan.bold(`Next Task:`)+`
|
|
724
734
|
ID: ${V.cyan(N?N.id:`N/A`)} - ${N?V.bold(R(N.title,40)):V.yellow(`No task available`)}
|
|
725
|
-
Priority: ${N?V.reset(N.priority||`medium`):``} Dependencies: ${N?
|
|
726
|
-
Complexity: ${N&&N.complexityScore?
|
|
735
|
+
Priority: ${N?V.reset(N.priority||`medium`):``} Dependencies: ${N?Ls(N.dependencies,a.tasks,!0,c):``}
|
|
736
|
+
Complexity: ${N&&N.complexityScore?zs(N.complexityScore):Q.muted(`N/A`)}`;if(fe>=104){let e=Math.floor(fe/2),t=e-4,n=G(pe,{padding:1,borderColor:Es,borderStyle:`round`,width:t,dimBorder:!1}),r=G(me,{padding:1,borderColor:`magenta`,borderStyle:`round`,width:t,dimBorder:!1}),i=n.split(`
|
|
727
737
|
`),a=r.split(`
|
|
728
738
|
`),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(`
|
|
729
|
-
`))}else{let e=G(pe,{padding:1,borderColor:
|
|
730
|
-
Falling back to simple task list due to terminal width constraints:`)),l.forEach(e=>{console.log(`${V.cyan(e.id)}: ${V.reset(e.title)} - ${
|
|
731
|
-
`));let n=
|
|
739
|
+
`))}else{let e=G(pe,{padding:1,borderColor:Es,borderStyle:`round`,margin:{top:0,bottom:1}}),t=G(me,{padding:1,borderColor:`magenta`,borderStyle:`round`,margin:{top:0,bottom:1}});console.log(e),console.log(t)}if(l.length===0){console.log(G(t?V.yellow(`No tasks with status '${t}' found`):V.yellow(`No tasks found`),{padding:1,borderColor:`yellow`,borderStyle:`round`}));return}let he=r?10:7,ge=100-he-15-12-20-10,F=fe-10,_e=Math.floor(he/100*F),ve=Math.floor(15/100*F),ye=Math.floor(12/100*F),L=Math.floor(20/100*F),be=Math.floor(10/100*F),xe=Math.floor(ge/100*F),Se=new q({head:[V.cyan.bold(`ID`),V.cyan.bold(`Title`),V.cyan.bold(`Status`),V.cyan.bold(`Priority`),V.cyan.bold(`Dependencies`),V.cyan.bold(`Complexity`)],colWidths:[_e,xe,ve,ye,L,be],style:{head:[],border:[],compact:!1},wordWrap:!0,wrapOnWordBoundary:!0});l.forEach(e=>{let t=`None`;t=e.dependencies&&e.dependencies.length>0?Ls(e.dependencies,a.tasks,!0,c):Q.muted(`None`);let n=e.title.replace(/\n/g,` `),i={high:V.red,medium:V.yellow,low:Q.muted}[e.priority||`medium`]||V.reset,o=Is(e.status,!0);Se.push([e.id.toString(),R(n,xe-3),o,i(R(e.priority||`medium`,ye-2)),t,e.complexityScore?zs(e.complexityScore):Q.muted(`N/A`)]),r&&e.subtasks&&e.subtasks.length>0&&e.subtasks.forEach(t=>{let n=`None`;t.dependencies&&t.dependencies.length>0&&(n=t.dependencies.map(t=>{if(typeof t==`number`&&t<100){let n=e.subtasks.find(e=>e.id===t);if(n){let r=n.status===`done`||n.status===`completed`,i=n.status===`in-progress`;return r?V.green.bold(`${e.id}.${t}`):i?Q.active.bold(`${e.id}.${t}`):V.red.bold(`${e.id}.${t}`)}}let n=a.tasks.find(e=>e.id===t);if(n){T(n,c);let e=n.status===`done`||n.status===`completed`,r=n.status===`in-progress`;return e?V.green.bold(`${t}`):r?Q.active.bold(`${t}`):V.red.bold(`${t}`)}return V.cyan(t.toString())}).join(`, `)||Q.muted(`None`)),Se.push([`${e.id}.${t.id}`,V.dim(`└─ ${R(t.title,xe-5)}`),Is(t.status,!0),V.dim(`-`),n,t.complexityScore?Q.muted(`${t.complexityScore}`):Q.muted(`N/A`)])})});try{console.log(Se.toString())}catch(e){I(`error`,`Error rendering table: ${e.message}`),console.log(V.yellow(`
|
|
740
|
+
Falling back to simple task list due to terminal width constraints:`)),l.forEach(e=>{console.log(`${V.cyan(e.id)}: ${V.reset(e.title)} - ${Is(e.status)}`)})}t&&(console.log(V.yellow(`\nFiltered by status: ${t}`)),console.log(V.yellow(`Showing ${l.length} of ${u} tasks`)));let Ce={high:V.red.bold,medium:V.yellow,low:Q.muted};if(N){let e=``,t=a.tasks.find(e=>String(e.id)===String(N.id));t&&t.subtasks&&t.subtasks.length>0&&(e=`\n\n${V.bold(`Subtasks:`)}\n`,e+=t.subtasks.map(e=>{T(e,c);let n=e.status||`pending`,r={done:V.green,completed:V.green,pending:V.yellow,"in-progress":V.cyan,deferred:Q.muted,blocked:V.red,cancelled:Q.muted}[n.toLowerCase()]||V.reset;return`${V.cyan(`${t.id}.${e.id}`)} [${r(n)}] ${e.title}`}).join(`
|
|
741
|
+
`));let n=Pt(N.id,N.status,!!t?.subtasks?.length).slice(0,2).map(e=>`${V.cyan(`Next step:`)} ${V.yellow(e.command)} ${Q.muted(e.description)}`).join(`
|
|
732
742
|
`);console.log(G(Q.heading(`Next task: #${N.id} - ${N.title}`)+`
|
|
733
743
|
|
|
734
|
-
${V.reset(`Priority:`)} ${Ce[N.priority||`medium`](N.priority||`medium`)} ${V.reset(`Status:`)} ${
|
|
744
|
+
${V.reset(`Priority:`)} ${Ce[N.priority||`medium`](N.priority||`medium`)} ${V.reset(`Status:`)} ${Is(N.status,!0)}\n${V.reset(`Dependencies:`)} ${N.dependencies&&N.dependencies.length>0?Ls(N.dependencies,a.tasks,!0,c):Q.muted(`None`)}\n\n${V.reset(`Description:`)} ${Wi(N,a.tasks)}`+e+`
|
|
735
745
|
|
|
736
|
-
${n}\n${V.cyan(`View details:`)} ${V.yellow(`taskgraph show ${N.id}`)}`,{padding:{left:2,right:2,top:1,bottom:1},borderColor:
|
|
746
|
+
${n}\n${V.cyan(`View details:`)} ${V.yellow(`taskgraph show ${N.id}`)}`,{padding:{left:2,right:2,top:1,bottom:1},borderColor:Es,borderStyle:`round`,margin:{top:1,bottom:1},title:`Next task`,titleAlignment:`center`,width:fe-4,fullscreen:!1}))}else console.log(G(Q.heading(`No eligible next task found`)+`
|
|
737
747
|
|
|
738
|
-
All pending tasks have dependencies that are not yet completed, or all tasks are done.`,{padding:1,borderColor:
|
|
748
|
+
All pending tasks have dependencies that are not yet completed, or all tasks are done.`,{padding:1,borderColor:Es,borderStyle:`round`,margin:{top:1,bottom:1},title:`Next task`,titleAlignment:`center`,width:fe-4}));console.log(G(V.bold(`Suggested Next Steps:`)+`
|
|
739
749
|
|
|
740
|
-
${V.cyan(`1.`)} Run ${V.yellow(`taskgraph next`)} to see what to work on next\n${V.cyan(`2.`)} Run ${V.yellow(`taskgraph expand --id=<id>`)} to break down a task into subtasks\n${V.cyan(`3.`)} Run ${V.yellow(`taskgraph set-status --id=<id> --status=done`)} to mark a task as complete`,{padding:1,...ke,borderStyle:`round`,margin:{top:1}}))}catch(e){if(I(`error`,`Error listing tasks: ${e.message}`),i===`json`)throw{code:`TASK_LIST_ERROR`,message:e.message,details:e.stack};console.error(V.red(`Error: ${e.message}`)),process.exit(1)}}function
|
|
750
|
+
${V.cyan(`1.`)} Run ${V.yellow(`taskgraph next`)} to see what to work on next\n${V.cyan(`2.`)} Run ${V.yellow(`taskgraph expand --id=<id>`)} to break down a task into subtasks\n${V.cyan(`3.`)} Run ${V.yellow(`taskgraph set-status --id=<id> --status=done`)} to mark a task as complete`,{padding:1,...ke,borderStyle:`round`,margin:{top:1}}))}catch(e){if(I(`error`,`Error listing tasks: ${e.message}`),i===`json`)throw{code:`TASK_LIST_ERROR`,message:e.message,details:e.stack};console.error(V.red(`Error: ${e.message}`)),process.exit(1)}}function Wi(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 Gi(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:ee,complexityReport:E,withSubtasks:D,nextItem:O}=n,k=``,A=(e,t=20)=>{let n=Math.round(e/100*t),r=t-n;return`█`.repeat(n)+`░`.repeat(r)},te=A(a,20),j=A(m,20);k+=`| Project Dashboard | |
|
|
741
751
|
`,k+=`| :- |:-|
|
|
742
752
|
`,k+=`| Task Progress | ${te} ${Math.round(a)}% |\n`,k+=`| Done | ${o} |\n`,k+=`| In Progress | ${s} |\n`,k+=`| Pending | ${c} |\n`,k+=`| Deferred | ${u} |\n`,k+=`| Cancelled | ${d} |\n`,k+=`|-|-|
|
|
743
753
|
`,k+=`| Subtask Progress | ${j} ${Math.round(m)}% |\n`,k+=`| Completed | ${p} |\n`,k+=`| In Progress | ${h} |\n`,k+=`| Pending | ${g} |\n`,k+=`
|
|
744
754
|
|
|
745
755
|
`,k+=`| ID | Title | Status | Priority | Dependencies | Complexity |
|
|
746
756
|
`,k+=`| :- | :- | :- | :- | :- | :- |
|
|
747
|
-
`;let M=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`}},ne=(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=M(t.status),i=t.priority||`medium`,a=ne(t.dependencies,e.tasks),o=t.complexityScore?`● ${t.complexityScore}`:`N/A`;k+=`| ${t.id} | ${n} | ${r} | ${i} | ${a} | ${o} |\n`,D&&t.subtasks&&t.subtasks.length>0&&t.subtasks.forEach(n=>{let r=`${n.title}`,i=M(n.status),a=ne(n.dependencies,e.tasks),o=n.complexityScore?n.complexityScore.toString():`N/A`;k+=`| ${t.id}.${n.id} | ${r} | ${i} | - | ${a} | ${o} |\n`})}),k}function
|
|
748
|
-
`))}function zi(e,t,n={}){return pe(e,t,{...n,direction:`forward`,logger:{warn:console.warn}})}var X=class extends Error{constructor(e,t,n={}){super(t),this.name=`MoveTaskError`,this.code=e,this.data=n}};const Z={CROSS_TAG_DEPENDENCY_CONFLICTS:`CROSS_TAG_DEPENDENCY_CONFLICTS`,CANNOT_MOVE_SUBTASK:`CANNOT_MOVE_SUBTASK`,SOURCE_TARGET_TAGS_SAME:`SOURCE_TARGET_TAGS_SAME`,TASK_NOT_FOUND:`TASK_NOT_FOUND`,SUBTASK_NOT_FOUND:`SUBTASK_NOT_FOUND`,PARENT_TASK_NOT_FOUND:`PARENT_TASK_NOT_FOUND`,PARENT_TASK_NO_SUBTASKS:`PARENT_TASK_NO_SUBTASKS`,DESTINATION_TASK_NOT_FOUND:`DESTINATION_TASK_NOT_FOUND`,TASK_ALREADY_EXISTS:`TASK_ALREADY_EXISTS`,INVALID_TASKS_FILE:`INVALID_TASKS_FILE`,ID_COUNT_MISMATCH:`ID_COUNT_MISMATCH`,INVALID_SOURCE_TAG:`INVALID_SOURCE_TAG`,INVALID_TARGET_TAG:`INVALID_TARGET_TAG`};function Bi(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 Vi(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 X(Z.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 Vi(e,s[n],c[n],!1,i);t.push(r)}return{message:`Successfully moved ${s.length} tasks/subtasks`,moves:t}}let l=P(e,a,o);if(l&&l._rawTaggedData&&(l=l._rawTaggedData),!l||!l[o]||!Array.isArray(l[o].tasks))throw new X(Z.INVALID_TASKS_FILE,`Invalid tasks file or tag "${o}" not found at ${e}`);let u=l[o].tasks;I(`info`,`Moving task/subtask ${t} to ${n} (tag: ${o})`);let d=t.includes(`.`),f=n.includes(`.`),p;return p=d&&f?Hi(u,t,n):d&&!f?Ui(u,t,n):!d&&f?Wi(u,t,n):Gi(u,t,n),l[o].tasks=u,F(e,l,i.projectRoot,o),p}function Hi(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 X(Z.PARENT_TASK_NOT_FOUND,`Source parent task with ID ${r} not found`);if(!c)throw new X(Z.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 X(Z.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 Ki(u,s,l,c,o);return{message:`Moved subtask ${t} to ${n}`,movedItem:u}}function Ui(e,t,n){let[r,i]=t.split(`.`).map(e=>parseInt(e,10)),a=parseInt(n,10),o=e.find(e=>e.id===r);if(!o)throw new X(Z.PARENT_TASK_NOT_FOUND,`Source parent task with ID ${r} not found`);if(!o.subtasks)throw new X(Z.PARENT_TASK_NO_SUBTASKS,`Source parent task ${r} has no subtasks`);let s=o.subtasks.findIndex(e=>e.id===i);if(s===-1)throw new X(Z.SUBTASK_NOT_FOUND,`Source subtask ${t} not found`);let c=o.subtasks[s];if(e.find(e=>e.id===a))throw new X(Z.TASK_ALREADY_EXISTS,`Cannot move to existing task ID ${a}. Choose a different ID or use subtask destination.`);let l={id:a,title:c.title,description:c.description,status:c.status||`pending`,dependencies:c.dependencies||[],priority:c.priority||`medium`,details:c.details||``,testStrategy:c.testStrategy||``,subtasks:[]};o.subtasks.splice(s,1);let u=e.findIndex(e=>e.id>a);return u===-1?e.push(l):e.splice(u,0,l),{message:`Converted subtask ${t} to task ${n}`,movedItem:l}}function Wi(e,t,n){let r=parseInt(t,10),[i,a]=n.split(`.`).map(e=>parseInt(e,10)),o=e.findIndex(e=>e.id===r),s=e.find(e=>e.id===i);if(o===-1)throw new X(Z.TASK_NOT_FOUND,`Source task with ID ${r} not found`);if(!s)throw new X(Z.PARENT_TASK_NOT_FOUND,`Destination parent task with ID ${i} not found`);let c=e[o];s.subtasks||=[];let l={id:a,title:c.title,description:c.description,status:c.status||`pending`,dependencies:c.dependencies||[],details:c.details||``,testStrategy:c.testStrategy||``},u=-1;s.subtasks.length>0&&(u=s.subtasks.findIndex(e=>e.id===a),u===-1&&(u=s.subtasks.length-1));let d=u===-1?0:u+1;return s.subtasks.splice(d,0,l),e.splice(o,1),{message:`Converted task ${t} to subtask ${n}`,movedItem:l}}function Gi(e,t,n){let r=parseInt(t,10),i=parseInt(n,10),a=e.findIndex(e=>e.id===r);if(a===-1)throw new X(Z.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 X(Z.TASK_ALREADY_EXISTS,`Task with ID ${i} already exists. Use a different destination ID.`);return qi(e,a,o,i)}function Ki(e,t,n,r,i){let a=parseInt(i,10),o={...e,id:a};r.subtasks||=[];let s=-1;r.subtasks.length>0&&(s=r.subtasks.findIndex(e=>e.id===a),s===-1&&(s=r.subtasks.length-1));let c=s===-1?0:s+1;return r.subtasks.splice(c,0,o),t.subtasks.splice(n,1),o}function qi(e,t,n,r){let i=e.findIndex(e=>e.id===r),a={...n,id:r};e.forEach(e=>{if(e.dependencies&&e.dependencies.includes(n.id)){let t=e.dependencies.indexOf(n.id);e.dependencies[t]=r}e.subtasks&&e.subtasks.forEach(e=>{if(e.dependencies&&e.dependencies.includes(n.id)){let t=e.dependencies.indexOf(n.id);e.dependencies[t]=r}})}),Array.isArray(a.subtasks)&&a.subtasks.forEach(e=>{Array.isArray(e.dependencies)&&(e.dependencies=e.dependencies.map(e=>{if(typeof e==`string`&&e.includes(`.`)){let[t,i]=e.split(`.`);if(parseInt(t,10)===n.id)return`${r}.${i}`}return e}))}),e.splice(t,1);let o=t<i?i-1:i;return o>=0&&o<e.length?e[o]=a:e.push(a),I(`info`,`Moved task ${n.id} to new ID ${r}`),{message:`Moved task ${n.id} to new ID ${r}`,movedItem:a}}function Ji(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 Yi(e,t,n,r,i){let{projectRoot:a}=i,o=P(e,a,n);if(o&&o._rawTaggedData&&(o=o._rawTaggedData),!o||!o[n]||!Array.isArray(o[n].tasks))throw new X(Z.INVALID_SOURCE_TAG,`Source tag "${n}" not found or invalid`);o[r]||(o[r]={tasks:[]},I(`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=>{ec(e,n,r)}),{rawData:o,sourceTasks:c}}async function Xi(e){let{rawData:t,sourceTasks:n}=e;return{rawData:t,sourceTasks:n,allTasks:Ji(t)}}async function Zi(e,t,n,r,i,a){let{withDependencies:o=!1,ignoreDependencies:s=!1}=n,c=Array.isArray(t)?t.filter(e=>e&&e.tag===i):[];if(o){let t=zi(e,c,{maxDepth:100,includeSelf:!1}),n=new Set(c.map(e=>typeof e.id==`string`?parseInt(e.id,10):e.id)),i=t.filter(e=>{let t=Bi(e);return Number.isFinite(t)&&n.has(t)}),a=[.../* @__PURE__ */ new Set([...r,...i])];return I(`info`,`Moving ${a.length} tasks (including dependencies): ${a.join(`, `)}`),{tasksToMove:a,dependencyResolution:{type:`with-dependencies`,dependentTasks:i}}}let l=$s(e,i,a,t);if(l.length>0){if(s)return e.forEach(e=>{let n=c,r=Array.isArray(t)?t.filter(e=>e&&e.tag===a):[];e.dependencies=e.dependencies.filter(e=>{let t=Bi(e);return Number.isFinite(t)&&n.some(e=>e.id===t)?!1:(Number.isFinite(t)&&r.some(e=>e.id===t),!0)})}),I(`warn`,`Removed ${l.length} cross-tag dependencies`),{tasksToMove:r,dependencyResolution:{type:`ignored-dependencies`,conflicts:l}};throw new X(Z.CROSS_TAG_DEPENDENCY_CONFLICTS,`Cannot move tasks: ${l.length} cross-tag dependency conflicts found`,{conflicts:l,sourceTag:i,targetTag:a,taskIds:r})}return{tasksToMove:r,dependencyResolution:{type:`no-conflicts`}}}async function Qi(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 X(Z.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 X(Z.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=ta(o,t,n);r[n].tasks.push(c),s.push({id:i,fromTag:t,toTag:n}),I(`info`,`Moved task ${i} from "${t}" to "${n}"`)}return{rawData:r,movedTasks:s}}async function $i(e,t,n,r,i,a){let{projectRoot:o}=n,{rawData:s,movedTasks:c}=e;F(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 ea(e,t,n,r,i={},a={}){let{rawData:o,sourceTasks:s,allTasks:c}=await Xi(await Yi(e,t,n,r,a)),{tasksToMove:l,dependencyResolution:u}=await Zi(s,c,i,t,n,r);return await $i(await Qi(l,n,r,o,a,e),e,a,n,r,u)}function ta(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 na=class e extends Error{constructor(t,n){super(t),this.name=`StreamingError`,this.code=n,Error.captureStackTrace&&Error.captureStackTrace(this,e)}};const ra={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 ia=class e{static async withTimeout(e,t,n=`Operation`){let r,i=new Promise((e,i)=>{r=setTimeout(()=>{i(new na(`${n} timed out after ${t/1e3} seconds`,ra.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 na&&e.code===ra.STREAM_PROCESSING_FAILED&&e.message.includes(`timed out`)}},aa=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 oa=U.object({id:U.number(),title:U.string().min(1),description:U.string().min(1),details:U.string(),testStrategy:U.string(),priority:U.enum(Wr),dependencies:U.array(U.number()),status:U.string()}),sa=U.object({tasks:U.array(oa),metadata:U.union([U.object({projectName:U.string(),totalTasks:U.number(),sourceFile:U.string(),generatedAt:U.string()}),U.null()]).default(null)});var ca=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||aa.seconds(180).milliseconds,this.targetTag=this.tag||M(this.projectRoot)||`master`,this.isMCP=!!this.mcpLog,this.outputFormat=this.isMCP&&!this.reportProgress?`json`:`text`,this.useStreaming=!1}hasCodebaseAnalysis(){return ee(this.research,this.projectRoot,this.session)}},la=class{constructor(e,t){this.isMCP=!!e,this.outputFormat=this.isMCP&&!t?`json`:`text`,this.logFn=e||{info:(...e)=>I(`info`,...e),warn:(...e)=>I(`warn`,...e),error:(...e)=>I(`error`,...e),debug:(...e)=>I(`debug`,...e),success:(...e)=>I(`success`,...e)}}report(e,t=`info`){this.logFn&&typeof this.logFn[t]==`function`?this.logFn[t](e):!z()&&this.outputFormat===`text`&&I(t,e)}};function ua(e){return`${Math.floor(e/60)}m ${Math.floor(e%60).toString().padStart(2,`0`)}s`}const da={BAR_WIDTH:40,TABLE_COL_WIDTHS:[28,50],DEFAULT_MODEL:`Default`,DEFAULT_TEMPERATURE:.7},fa={HIGH:`high`,MEDIUM:`medium`,LOW:`low`},pa={[fa.HIGH]:V.red,[fa.MEDIUM]:V.yellow,[fa.LOW]:B.muted},ma={main:{padding:{top:1,bottom:1,left:2,right:2},margin:{top:0,bottom:0},borderColor:N,borderStyle:`round`},summary:{padding:{top:1,right:1,bottom:1,left:1},borderColor:N,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 ha({prdFilePath:e,outputPath:t,numTasks:n,model:r,temperature:i,append:a,research:o}){let s=a?`Appending`:`Generating`,c=`Model: ${r} | Temperature: ${i}`;return o&&(c+=` | ${V.cyan.bold(`🔬 Research Mode`)}`),V.bold(`🤖 Parsing PRD and ${s} Tasks`)+`
|
|
757
|
+
`;let M=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`}},ne=(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=M(t.status),i=t.priority||`medium`,a=ne(t.dependencies,e.tasks),o=t.complexityScore?`● ${t.complexityScore}`:`N/A`;k+=`| ${t.id} | ${n} | ${r} | ${i} | ${a} | ${o} |\n`,D&&t.subtasks&&t.subtasks.length>0&&t.subtasks.forEach(n=>{let r=`${n.title}`,i=M(n.status),a=ne(n.dependencies,e.tasks),o=n.complexityScore?n.complexityScore.toString():`N/A`;k+=`| ${t.id}.${n.id} | ${r} | ${i} | - | ${a} | ${o} |\n`})}),k}function Ki(e){if(!e||e.length===0)return``;if(e.length>5){let t=e.slice(0,5).join(`,`),n=e.length-5;return` → ${V.cyan(t)}${Q.muted(`... (+`+n+` more)`)}`}return` → ${V.cyan(e.join(`,`))}`}function qi(e,t=50){let n=e.status||`pending`,r=e.priority||`medium`,i=R(e.title||`Untitled`,t),a=Is(n,!0),o={high:V.red,medium:V.yellow,low:Q.muted}[r]||V.reset,s=Ki(e.dependencies);return`${V.cyan(e.id)} ${a} ${V.reset(i)} ${o(`(`+r+`)`)}${s}`}function Ji(e,t,n=47){let r=e.status||`pending`,i=R(e.title||`Untitled`,n),a=Is(r,!0),o=Ki(e.dependencies);return` ${V.cyan(t+`.`+e.id)} ${a} ${V.dim(i)}${o}`}function Yi(e,t){if(e.length===0){console.log(`No tasks found`);return}let n=[];e.forEach(e=>{n.push(qi(e)),t&&e.subtasks&&e.subtasks.length>0&&e.subtasks.forEach(t=>{n.push(Ji(t,e.id))})}),console.log(n.join(`
|
|
758
|
+
`))}function Xi(e,t,n={}){return pe(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 Zi={CROSS_TAG_DEPENDENCY_CONFLICTS:`CROSS_TAG_DEPENDENCY_CONFLICTS`,CANNOT_MOVE_SUBTASK:`CANNOT_MOVE_SUBTASK`,SOURCE_TARGET_TAGS_SAME:`SOURCE_TARGET_TAGS_SAME`,TASK_NOT_FOUND:`TASK_NOT_FOUND`,SUBTASK_NOT_FOUND:`SUBTASK_NOT_FOUND`,PARENT_TASK_NOT_FOUND:`PARENT_TASK_NOT_FOUND`,PARENT_TASK_NO_SUBTASKS:`PARENT_TASK_NO_SUBTASKS`,DESTINATION_TASK_NOT_FOUND:`DESTINATION_TASK_NOT_FOUND`,TASK_ALREADY_EXISTS:`TASK_ALREADY_EXISTS`,INVALID_TASKS_FILE:`INVALID_TASKS_FILE`,ID_COUNT_MISMATCH:`ID_COUNT_MISMATCH`,INVALID_SOURCE_TAG:`INVALID_SOURCE_TAG`,INVALID_TARGET_TAG:`INVALID_TARGET_TAG`};function Qi(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 $i(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(Zi.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 $i(e,s[n],c[n],!1,i);t.push(r)}return{message:`Successfully moved ${s.length} tasks/subtasks`,moves:t}}let l=P(e,a,o);if(l&&l._rawTaggedData&&(l=l._rawTaggedData),!l||!l[o]||!Array.isArray(l[o].tasks))throw new Z(Zi.INVALID_TASKS_FILE,`Invalid tasks file or tag "${o}" not found at ${e}`);let u=l[o].tasks;I(`info`,`Moving task/subtask ${t} to ${n} (tag: ${o})`);let d=t.includes(`.`),f=n.includes(`.`),p;return p=d&&f?ea(u,t,n):d&&!f?ta(u,t,n):!d&&f?na(u,t,n):ra(u,t,n),l[o].tasks=u,F(e,l,i.projectRoot,o),p}function ea(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(Zi.PARENT_TASK_NOT_FOUND,`Source parent task with ID ${r} not found`);if(!c)throw new Z(Zi.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(Zi.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 ia(u,s,l,c,o);return{message:`Moved subtask ${t} to ${n}`,movedItem:u}}function ta(e,t,n){let[r,i]=t.split(`.`).map(e=>parseInt(e,10)),a=parseInt(n,10),o=e.find(e=>e.id===r);if(!o)throw new Z(Zi.PARENT_TASK_NOT_FOUND,`Source parent task with ID ${r} not found`);if(!o.subtasks)throw new Z(Zi.PARENT_TASK_NO_SUBTASKS,`Source parent task ${r} has no subtasks`);let s=o.subtasks.findIndex(e=>e.id===i);if(s===-1)throw new Z(Zi.SUBTASK_NOT_FOUND,`Source subtask ${t} not found`);let c=o.subtasks[s];if(e.find(e=>e.id===a))throw new Z(Zi.TASK_ALREADY_EXISTS,`Cannot move to existing task ID ${a}. Choose a different ID or use subtask destination.`);let l={id:a,title:c.title,description:c.description,status:c.status||`pending`,dependencies:c.dependencies||[],priority:c.priority||`medium`,details:c.details||``,testStrategy:c.testStrategy||``,subtasks:[]};o.subtasks.splice(s,1);let u=e.findIndex(e=>e.id>a);return u===-1?e.push(l):e.splice(u,0,l),{message:`Converted subtask ${t} to task ${n}`,movedItem:l}}function na(e,t,n){let r=parseInt(t,10),[i,a]=n.split(`.`).map(e=>parseInt(e,10)),o=e.findIndex(e=>e.id===r),s=e.find(e=>e.id===i);if(o===-1)throw new Z(Zi.TASK_NOT_FOUND,`Source task with ID ${r} not found`);if(!s)throw new Z(Zi.PARENT_TASK_NOT_FOUND,`Destination parent task with ID ${i} not found`);let c=e[o];s.subtasks||=[];let l={id:a,title:c.title,description:c.description,status:c.status||`pending`,dependencies:c.dependencies||[],details:c.details||``,testStrategy:c.testStrategy||``},u=-1;s.subtasks.length>0&&(u=s.subtasks.findIndex(e=>e.id===a),u===-1&&(u=s.subtasks.length-1));let d=u===-1?0:u+1;return s.subtasks.splice(d,0,l),e.splice(o,1),{message:`Converted task ${t} to subtask ${n}`,movedItem:l}}function ra(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(Zi.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(Zi.TASK_ALREADY_EXISTS,`Task with ID ${i} already exists. Use a different destination ID.`);return aa(e,a,o,i)}function ia(e,t,n,r,i){let a=parseInt(i,10),o={...e,id:a};r.subtasks||=[];let s=-1;r.subtasks.length>0&&(s=r.subtasks.findIndex(e=>e.id===a),s===-1&&(s=r.subtasks.length-1));let c=s===-1?0:s+1;return r.subtasks.splice(c,0,o),t.subtasks.splice(n,1),o}function aa(e,t,n,r){let i=e.findIndex(e=>e.id===r),a={...n,id:r};e.forEach(e=>{if(e.dependencies&&e.dependencies.includes(n.id)){let t=e.dependencies.indexOf(n.id);e.dependencies[t]=r}e.subtasks&&e.subtasks.forEach(e=>{if(e.dependencies&&e.dependencies.includes(n.id)){let t=e.dependencies.indexOf(n.id);e.dependencies[t]=r}})}),Array.isArray(a.subtasks)&&a.subtasks.forEach(e=>{Array.isArray(e.dependencies)&&(e.dependencies=e.dependencies.map(e=>{if(typeof e==`string`&&e.includes(`.`)){let[t,i]=e.split(`.`);if(parseInt(t,10)===n.id)return`${r}.${i}`}return e}))}),e.splice(t,1);let o=t<i?i-1:i;return o>=0&&o<e.length?e[o]=a:e.push(a),I(`info`,`Moved task ${n.id} to new ID ${r}`),{message:`Moved task ${n.id} to new ID ${r}`,movedItem:a}}function oa(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 sa(e,t,n,r,i){let{projectRoot:a}=i,o=P(e,a,n);if(o&&o._rawTaggedData&&(o=o._rawTaggedData),!o||!o[n]||!Array.isArray(o[n].tasks))throw new Z(Zi.INVALID_SOURCE_TAG,`Source tag "${n}" not found or invalid`);o[r]||(o[r]={tasks:[]},I(`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=>{fc(e,n,r)}),{rawData:o,sourceTasks:c}}async function ca(e){let{rawData:t,sourceTasks:n}=e;return{rawData:t,sourceTasks:n,allTasks:oa(t)}}async function la(e,t,n,r,i,a){let{withDependencies:o=!1,ignoreDependencies:s=!1}=n,c=Array.isArray(t)?t.filter(e=>e&&e.tag===i):[];if(o){let t=Xi(e,c,{maxDepth:100,includeSelf:!1}),n=new Set(c.map(e=>typeof e.id==`string`?parseInt(e.id,10):e.id)),i=t.filter(e=>{let t=Qi(e);return Number.isFinite(t)&&n.has(t)}),a=[.../* @__PURE__ */ new Set([...r,...i])];return I(`info`,`Moving ${a.length} tasks (including dependencies): ${a.join(`, `)}`),{tasksToMove:a,dependencyResolution:{type:`with-dependencies`,dependentTasks:i}}}let l=dc(e,i,a,t);if(l.length>0){if(s)return e.forEach(e=>{let n=c,r=Array.isArray(t)?t.filter(e=>e&&e.tag===a):[];e.dependencies=e.dependencies.filter(e=>{let t=Qi(e);return Number.isFinite(t)&&n.some(e=>e.id===t)?!1:(Number.isFinite(t)&&r.some(e=>e.id===t),!0)})}),I(`warn`,`Removed ${l.length} cross-tag dependencies`),{tasksToMove:r,dependencyResolution:{type:`ignored-dependencies`,conflicts:l}};throw new Z(Zi.CROSS_TAG_DEPENDENCY_CONFLICTS,`Cannot move tasks: ${l.length} cross-tag dependency conflicts found`,{conflicts:l,sourceTag:i,targetTag:a,taskIds:r})}return{tasksToMove:r,dependencyResolution:{type:`no-conflicts`}}}async function ua(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(Zi.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(Zi.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=pa(o,t,n);r[n].tasks.push(c),s.push({id:i,fromTag:t,toTag:n}),I(`info`,`Moved task ${i} from "${t}" to "${n}"`)}return{rawData:r,movedTasks:s}}async function da(e,t,n,r,i,a){let{projectRoot:o}=n,{rawData:s,movedTasks:c}=e;F(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 fa(e,t,n,r,i={},a={}){let{rawData:o,sourceTasks:s,allTasks:c}=await ca(await sa(e,t,n,r,a)),{tasksToMove:l,dependencyResolution:u}=await la(s,c,i,t,n,r);return await da(await ua(l,n,r,o,a,e),e,a,n,r,u)}function pa(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 ma=class e extends Error{constructor(t,n){super(t),this.name=`StreamingError`,this.code=n,Error.captureStackTrace&&Error.captureStackTrace(this,e)}};const ha={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 ga=class e{static async withTimeout(e,t,n=`Operation`){let r,i=new Promise((e,i)=>{r=setTimeout(()=>{i(new ma(`${n} timed out after ${t/1e3} seconds`,ha.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 ma&&e.code===ha.STREAM_PROCESSING_FAILED&&e.message.includes(`timed out`)}},_a=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 va=U.object({id:U.number(),title:U.string().min(1),description:U.string().min(1),details:U.string(),testStrategy:U.string(),priority:U.enum(ti),dependencies:U.array(U.number()),status:U.string()}),ya=U.object({tasks:U.array(va),metadata:U.union([U.object({projectName:U.string(),totalTasks:U.number(),sourceFile:U.string(),generatedAt:U.string()}),U.null()]).default(null)});var ba=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||_a.seconds(180).milliseconds,this.targetTag=this.tag||M(this.projectRoot)||`master`,this.isMCP=!!this.mcpLog,this.outputFormat=this.isMCP&&!this.reportProgress?`json`:`text`,this.useStreaming=!1}hasCodebaseAnalysis(){return ee(this.research,this.projectRoot,this.session)}},xa=class{constructor(e,t){this.isMCP=!!e,this.outputFormat=this.isMCP&&!t?`json`:`text`,this.logFn=e||{info:(...e)=>I(`info`,...e),warn:(...e)=>I(`warn`,...e),error:(...e)=>I(`error`,...e),debug:(...e)=>I(`debug`,...e),success:(...e)=>I(`success`,...e)}}report(e,t=`info`){this.logFn&&typeof this.logFn[t]==`function`?this.logFn[t](e):!z()&&this.outputFormat===`text`&&I(t,e)}};function Sa(e){return`${Math.floor(e/60)}m ${Math.floor(e%60).toString().padStart(2,`0`)}s`}const Ca={BAR_WIDTH:40,TABLE_COL_WIDTHS:[28,50],DEFAULT_MODEL:`Default`,DEFAULT_TEMPERATURE:.7},wa={HIGH:`high`,MEDIUM:`medium`,LOW:`low`},Ta={[wa.HIGH]:V.red,[wa.MEDIUM]:V.yellow,[wa.LOW]:B.muted},Ea={main:{padding:{top:1,bottom:1,left:2,right:2},margin:{top:0,bottom:0},borderColor:N,borderStyle:`round`},summary:{padding:{top:1,right:1,bottom:1,left:1},borderColor:N,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 Da({prdFilePath:e,outputPath:t,numTasks:n,model:r,temperature:i,append:a,research:o}){let s=a?`Appending`:`Generating`,c=`Model: ${r} | Temperature: ${i}`;return o&&(c+=` | ${V.cyan.bold(`🔬 Research Mode`)}`),V.bold(`🤖 Parsing PRD and ${s} Tasks`)+`
|
|
749
759
|
`+V.dim(c)+`
|
|
750
760
|
|
|
751
761
|
`+B.brand(`Input: ${e}`)+`
|
|
752
762
|
`+B.brand(`Output: ${t}`)+`
|
|
753
|
-
`+B.brand(`Tasks to ${a?`Append`:`Generate`}: ${n}`)}function
|
|
754
|
-
`);console.log(G(u,
|
|
763
|
+
`+B.brand(`Tasks to ${a?`Append`:`Generate`}: ${n}`)}function Oa(e){console.log(G(e,Ea.main))}function ka(e,t){console.log(V.yellow.bold(`📝 Append mode`)+` - Adding to ${e} existing tasks (next ID: ${t})`)}function Aa(e){let t=V.red.bold(`⚠️ Force flag enabled`);return e?`${t} - Will overwrite if conflicts occur`:`${t} - Overwriting existing tasks`}function ja({prdFilePath:e,outputPath:t,numTasks:n,model:r=Ca.DEFAULT_MODEL,temperature:i=Ca.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`);Oa(Da({prdFilePath:e,outputPath:t,numTasks:n,model:r,temperature:i,append:a,research:o})),(a||s)&&(a&&ka(c.length,l),s&&console.log(Aa(a)),console.log())}function Ma(e,t){let n={};return Object.values(wa).forEach(r=>{let i=e[r]||0;n[r]={count:i,percentage:t>0?Math.round(i/t*100):0}}),n}function Na(e,t){let n=Ca.BAR_WIDTH,r={};if(t===0)return Object.values(wa).forEach(e=>{r[e]=0}),r;let i={};Object.values(wa).forEach(r=>{i[r]=e[r].count/t*n}),Object.values(wa).forEach(e=>{r[e]=Math.floor(i[e])}),Object.values(wa).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(wa).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 Pa(e){let t=``;t+=Ta[wa.HIGH](`█`.repeat(e[wa.HIGH])),t+=Ta[wa.MEDIUM](`█`.repeat(e[wa.MEDIUM])),t+=Ta[wa.LOW](`█`.repeat(e[wa.LOW]));let n=Object.values(e).reduce((e,t)=>e+t,0);return n<Ca.BAR_WIDTH&&(t+=B.muted(`░`.repeat(Ca.BAR_WIDTH-n))),t}function Fa(e){let t=[];return Object.entries(wa).forEach(([n,r])=>{let i=e[r],a=Ta[r],o=n.charAt(0)+n.slice(1).toLowerCase();t.push(`${a.bold(i.count)} ${a(o)} (${i.percentage}%)`)}),[V.cyan(`Priority distribution:`),t.join(` · `)]}function Ia(e){let{totalTasks:t,taskPriorities:n={},prdFilePath:r,outputPath:i,elapsedTime:a,usedFallback:o=!1,actionVerb:s=`generated`}=e,c=Sa(a),l=new q({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:Ca.TABLE_COL_WIDTHS});if(l.push([V.cyan(`Total tasks ${s}:`),V.bold(t)],[V.cyan(`Processing time:`),V.bold(c)]),n&&Object.keys(n).length>0){let e=Ma(n,t),r=Fa(e);l.push(r);let i=Pa(Na(e,t));l.push([V.cyan(`Distribution:`),i])}l.push([V.cyan(`PRD source:`),V.italic(r)],[V.cyan(`Tasks file:`),V.italic(i)]),o&&l.push([V.yellow(`Fallback parsing:`),V.yellow(`✓ Used fallback parsing`)]);let u=[V.bold.underline(`PRD Parsing Complete - Tasks ${s.charAt(0).toUpperCase()+s.slice(1)}`),``,l.toString()].join(`
|
|
764
|
+
`);console.log(G(u,Ea.summary)),o&&La(),Ra()}function La(){let e=V.yellow.bold(`⚠️ Fallback Parsing Used`)+`
|
|
755
765
|
|
|
756
766
|
`+B.text(`The system used fallback parsing to complete task generation.`)+`
|
|
757
767
|
`+B.text(`This typically happens when streaming JSON parsing is incomplete.`)+`
|
|
@@ -759,22 +769,22 @@ ${V.cyan(`1.`)} Run ${V.yellow(`taskgraph next`)} to see what to work on next\n$
|
|
|
759
769
|
`+B.text(`• Reviewing task completeness`)+`
|
|
760
770
|
`+B.text(`• Checking for any missing details`)+`
|
|
761
771
|
|
|
762
|
-
`+B.text(`This is normal and usually doesn't indicate any issues.`);console.log(G(e,
|
|
772
|
+
`+B.text(`This is normal and usually doesn't indicate any issues.`);console.log(G(e,Ea.warning))}function Ra(){let e=B.text.bold(`Next Steps:`)+`
|
|
763
773
|
|
|
764
|
-
${V.cyan(`1.`)} Run ${V.yellow(`taskgraph list`)} to view all tasks\n${V.cyan(`2.`)} Run ${V.yellow(`taskgraph expand --id=<id>`)} to break down a task into subtasks\n${V.cyan(`3.`)} Run ${V.yellow(`taskgraph analyze-complexity`)} to analyze task complexity`;console.log(G(e,
|
|
774
|
+
${V.cyan(`1.`)} Run ${V.yellow(`taskgraph list`)} to view all tasks\n${V.cyan(`2.`)} Run ${V.yellow(`taskgraph expand --id=<id>`)} to break down a task into subtasks\n${V.cyan(`3.`)} Run ${V.yellow(`taskgraph analyze-complexity`)} to analyze task complexity`;console.log(G(e,Ea.nextSteps))}function za(e){return Math.ceil(e.length/4)}function Ba(e){let t=W.readFileSync(e,`utf8`);if(!t)throw Error(`Input file ${e} is empty or could not be read.`);return t}function Va(e,t){let n=[],r=1;if(!W.existsSync(e))return{existingTasks:n,nextId:r};try{let i=W.readFileSync(e,`utf8`),a=JSON.parse(i);a[t]?.tasks&&Array.isArray(a[t].tasks)&&(n=a[t].tasks,n.length>0&&(r=Math.max(...n.map(e=>e.id||0))+1))}catch{return{existingTasks:[],nextId:1}}return{existingTasks:n,nextId:r}}function Ha({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.`,`info`);else if(n)a.report(`Append mode enabled. Found ${e.length} existing tasks in tag '${t}'.`,`info`);else{if(!r){let n=`Tag '${t}' already contains ${e.length} tasks. Use --force to overwrite or --append to add to existing tasks.`;if(a.report(n,`error`),i)throw Error(n);console.error(V.red(n)),process.exit(1)}a.report(`Force flag enabled. Overwriting existing tasks in tag '${t}'.`,`debug`)}}function Ua(e,t,n,r){Wa(e,t);let i=t,a=/* @__PURE__ */ new Map,o=e.map(e=>{let t=i++;return a.set(e.id,t),{...e,id:t,status:e.status||`pending`,priority:e.priority||r,dependencies:Array.isArray(e.dependencies)?e.dependencies:[],subtasks:e.subtasks||[],title:e.title||``,description:e.description||``,details:e.details||``,testStrategy:e.testStrategy||``}});return o.forEach(e=>{e.dependencies=e.dependencies.map(e=>a.get(e)).filter(t=>t!=null&&t<e.id&&(O(n,t)||o.some(e=>e.id===t)))}),o}function Wa(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 Ga(e,t,n,r){let i=H.dirname(e);W.existsSync(i)||W.mkdirSync(i,{recursive:!0});let a={};if(W.existsSync(e))try{let t=W.readFileSync(e,`utf8`);a=JSON.parse(t)}catch{a={}}a[n]={tasks:t,metadata:{created:a[n]?.metadata?.created||(/* @__PURE__ */ new Date()).toISOString(),updated:(/* @__PURE__ */ new Date()).toISOString(),description:`Tasks for ${n} context`}},D(a[n],{description:`Tasks for ${n} context`}),W.writeFileSync(e,JSON.stringify(a,null,2)),r.report(`Successfully saved ${t.length} tasks to ${e}`,`debug`)}async function Ka(e,t,n){let r=Oi(),i=ue(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 qa({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 Ja({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`})();Ia({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 ga.withSoftTimeout(o.mainResult.usage,1e3,void 0),Ks(o.telemetryData,`cli`))}function Ya({processedTasks:e,research:t,finalTasks:n,tasksPath:r,aiServiceResponse:i}){console.log(G(V.green(`Successfully generated ${e.length} new tasks${t?` with research-backed analysis`:``}. Total tasks in ${r}: ${n.length}`),{padding:1,borderColor:`green`,borderStyle:`round`})),console.log(G(B.text.bold(`Next Steps:`)+`
|
|
765
775
|
|
|
766
|
-
${V.cyan(`1.`)} Run ${V.yellow(`taskgraph list`)} to view all tasks\n${V.cyan(`2.`)} Run ${V.yellow(`taskgraph expand --id=<id>`)} to break down a task into subtasks`,{padding:1,borderColor:`cyan`,borderStyle:`round`,margin:{top:1}})),i?.telemetryData&&
|
|
767
|
-
`));try{n.report(`Calling AI service to generate tasks from PRD${e.research?` with research-backed analysis`:``}...`,`info`);let t=await i({role:e.research?`research`:`main`,session:e.session,projectRoot:e.projectRoot,schema:sa,objectName:`tasks_data`,systemPrompt:r,prompt:a,commandName:`parse-prd`,outputType:e.isMCP?`mcp`:`cli`}),c=null;if(t?.mainResult&&(typeof t.mainResult==`object`&&t.mainResult!==null&&`tasks`in t.mainResult?c=t.mainResult:typeof t.mainResult.object==`object`&&t.mainResult.object!==null&&`tasks`in t.mainResult.object&&(c=t.mainResult.object)),!c||!Array.isArray(c.tasks))throw Error(`AI service returned unexpected data structure after validation.`);return s&&xs(s,`Tasks generated successfully!`),{parsedTasks:c.tasks,aiServiceResponse:t,estimatedInputTokens:o}}catch(e){throw s&&Ss(s,`Error parsing PRD: ${e.message}`),e}}const[za,Ba,Va]=Wr,Ha=/* @__PURE__ */ new Map;var Ua=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]||B.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 Wa={cli:{filled:`●`,empty:`○`},statusBar:{high:`⋮`,medium:`:`,low:`.`},mcp:{high:`🔴`,medium:`🟠`,low:`🟢`}},Ga=new Ua(`priority`,[za,Ba,Va],{[za]:V.red,[Ba]:V.yellow,[Va]:B.muted});function Ka(e,t){let n=Wa.cli.filled,r=Wa.cli.empty,i=``;for(let a=0;a<3;a++)i+=a<e?t(n):B.text(r);return i}function qa(e,t){return 3-t.indexOf(e)}function Ja(e,t){if(Ha.has(e))return Ha.get(e);let n=t();return Ha.set(e,n),n}function Ya(){return Ja(`mcp-priority-all`,()=>({[za]:Wa.mcp.high,[Ba]:Wa.mcp.medium,[Va]:Wa.mcp.low}))}function Xa(){return Ja(`cli-priority-all`,()=>{let e={};return Ga.levels.forEach(t=>{let n=qa(t,Ga.levels),r=Ga.getColor(t);e[t]=Ka(n,r)}),e})}function Za(){return Ja(`statusbar-priority-all`,()=>{let e={};return Ga.levels.forEach((t,n)=>{let r=n===0?Wa.statusBar.high:n===1?Wa.statusBar.medium:Wa.statusBar.low,i=Ga.getColor(t);e[t]=i(r)}),e})}function Qa(){return{[za]:Ga.colors[za],[Ba]:Ga.colors[Ba],[Va]:Ga.colors[Va]}}function $a(e=!1){return e?Ya():Xa()}function eo(e,t=!1){let n=$a(t);return n[e]||n[Ba]}new Ua(`complexity`,[`high`,`medium`,`low`],{high:V.red,medium:V.yellow,low:V.green},{high:e=>e>=7,medium:e=>e>=4&&e<=6,low:e=>e<=3});const to={clearOnComplete:!1,stopOnComplete:!0,hideCursor:!0,barsize:40},no={shades_classic:Ge.Presets.shades_classic,shades_grey:Ge.Presets.shades_grey,rect:Ge.Presets.rect,legacy:Ge.Presets.legacy},ro=new class{constructor(e={},t=no.shades_classic){this.defaultOptions={...to,...e},this.defaultPreset=t}createSingleBar(e={},t=null){let n=this._mergeConfig(e),r=t||this.defaultPreset;return new Ge.SingleBar(n,r)}createMultiBar(e={},t=null){let n=this._mergeConfig(e),r=t||this.defaultPreset;return new Ge.MultiBar(n,r)}_mergeConfig(e){return{...this.defaultOptions,...e}}setDefaultOptions(e){this.defaultOptions={...this.defaultOptions,...e}}setDefaultPreset(e){this.defaultPreset=e}};function io(e={}){return ro.createMultiBar(e)}var ao=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=io(),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(){}},oo=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 so(e,t,n){new oo(e).createHeader(t,n)}function co(e,t,n){new oo(e).createRow(t,n)}function lo(e,t){new oo(e).createBorder(t)}Xa();const uo=Za();Qa();const fo={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 po=class{constructor(e=fo.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}},mo=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():fo.DEFAULT_PRIORITY;return fo.VALID_PRIORITIES.includes(t)?t:fo.DEFAULT_PRIORITY}getCounts(){return{...this.priorities}}},ho=class{static formatTitle(e,t){return e?e.length>fo.MAX_TITLE_LENGTH?e.substring(0,fo.TRUNCATED_LENGTH)+`...`:e:`Task ${t}`}static formatPriority(e){return eo(e,!1).padEnd(fo.PRIORITY_PAD_END,` `)}static formatTaskId(e){return e.toString().padStart(fo.TASK_ID_PAD_START,` `).padEnd(fo.TASK_ID_PAD_END,` `)}},go=class extends ao{_initializeCustomProperties(e){this.append=e.append,this.priorityManager=new mo,this.debouncer=new po,this.headerShown=!1}_getTimeTokensBarFormat(){return`{clock} {elapsed} | ${uo.high} {high} ${uo.medium} {medium} ${uo.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,so(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=ho.formatTitle(t,e),i=ho.formatPriority(n),a=ho.formatTaskId(e);co(this.multibar,` ${a} | ${i} | {title}`,{title:r}),lo(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 _o(e={}){return new go(e)}async function vo(e,t,n){let r=yo(e,t,n);await xo(e,n,r.estimatedInputTokens);let i=await So(e,t,e.streamingTimeout),{progressTracker:a,priorityMap:o}=await Co(e,n),s=await wo(i.mainResult,e,t,n,a,o,r.defaultPriority,r.estimatedInputTokens,r.logger);if(bo(s),s.usage&&e.projectRoot){let{logAiUsage:t}=await import(`./ai-services-unified-CQMZv2X-.js`),{getUserId:n}=await import(`./config-manager-BsUS_HoV.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 Po(s,i,r.estimatedInputTokens,a)}function yo(e,t,n){let{systemPrompt:r,userPrompt:i}=t;return{logger:new la(e.mcpLog,e.reportProgress),estimatedInputTokens:Da(r+i),defaultPriority:ue(e.projectRoot)||`medium`}}function bo(e){if(e.parsedTasks.length===0)throw Error(`No tasks were generated from the PRD`)}async function xo(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 So(e,n,r){let{systemPrompt:i,userPrompt:a}=n;return await ia.withTimeout(t({role:e.research?`research`:`main`,session:e.session,projectRoot:e.projectRoot,schema:sa,systemPrompt:i,prompt:a,commandName:`parse-prd`,outputType:e.isMCP?`mcp`:`cli`}),r,`Streaming operation`)}async function Co(e,t){let n=$a(e.isMCP),r=null;if(e.outputFormat===`text`&&!e.isMCP){r=_o({numUnits:t,unitName:`task`,append:e.append});let n=e.research?Ee():xe(),i=ge(e.research?`research`:`main`);ya({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 wo(e,t,n,r,i,a,o,s,c){let{systemPrompt:l,userPrompt:u}=n,d={config:{...t,schema:sa},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 To(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 ko(t,d)}catch(e){return c.report(`StreamObject processing failed: ${e.message}. Falling back to generateObject.`,`debug`),await No(d,c)}}async function To(e,t,n){for await(let r of e)t.lastPartialObject=r,r&&(t.estimatedOutputTokens=Da(JSON.stringify(r))),await Eo(r,t,n)}async function Eo(e,t,n){if(!e?.tasks||!Array.isArray(e.tasks))return;let r=e.tasks.length;r>t.taskCount?(await Do(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 Do(e,t,n,r,i){for(let a=t;a<n;a++){let t=e[a]||{};t.title?await Fa({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 Oo(a+1,r,i)}}async function Oo(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 ko(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 Ao(n.tasks,i,a?o:r,t,a?s:null),{parsedTasks:n.tasks,estimatedOutputTokens:o,actualInputTokens:s,usage:a,usedFallback:!1}}async function Ao(e,t,n,r,i=null){let{progressTracker:a,defaultPriority:o,estimatedInputTokens:s}=r;t>0?jo(e,a,o):await Mo(e,n,r),a.updateTokens(i||s,n,!1),a.stop()}function jo(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 Mo(e,t,n){for(let r=0;r<e.length;r++){let i=e[r];i?.title&&await Fa({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 No(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 i({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||Da(JSON.stringify(r)),i=n.telemetryData?.inputTokens||e.estimatedInputTokens;e.progressTracker.updateTokens(i,t,!1)}return{parsedTasks:r.tasks,estimatedOutputTokens:n.telemetryData?.outputTokens||Da(JSON.stringify(r)),actualInputTokens:n.telemetryData?.inputTokens,telemetryData:n.telemetryData,usedFallback:!0}}throw Error(`Failed to generate tasks using generateObject fallback`)}function Po(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 Fo(e,t,n){let r=new la(e.mcpLog,e.reportProgress);r.report(`Parsing PRD file: ${e.prdPath}, Force: ${e.force}, Append: ${e.append}, Research: ${e.research}`,`debug`);try{let{existingTasks:i,nextId:a}=ka(e.tasksPath,e.targetTag);Aa({existingTasks:i,targetTag:e.targetTag,append:e.append,force:e.force,isMCP:e.isMCP,logger:r});let o=await t(e,await Pa(e,Oa(e.prdPath),a),e.numTasks),s=ue(e.projectRoot)||`medium`,c=ja(o.parsedTasks,a,i,s),l=e.append?[...i,...c]:c;return Na(e.tasksPath,l,e.targetTag,r),await Io(e,o,c,l,a,n),{success:!0,tasksPath:e.tasksPath,telemetryData:o.aiServiceResponse?.telemetryData,tagInfo:o.aiServiceResponse?.tagInfo}}catch(t){throw r.report(`Error parsing PRD: ${t.message}`,`error`),e.isMCP||(console.error(V.red(`Error: ${t.message}`)),L(e.projectRoot)&&console.error(t)),t}}async function Io(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 Ia({processedTasks:n,nextId:i,summary:t.summary,prdPath:e.prdPath,tasksPath:e.tasksPath,usedFallback:t.usedFallback,aiServiceResponse:o}):a||La({processedTasks:n,research:e.research,finalTasks:r,tasksPath:e.tasksPath,aiServiceResponse:o}))}async function Lo(e,t,n,r={}){return Fo(new ca(e,t,n,r),vo,!0)}async function Ro(e,t,n,r={}){return Fo(new ca(e,t,n,r),Ra,!1)}async function zo(e,t,n,r={}){let i=new ca(e,t,n,r);if(i.useStreaming)try{return await Lo(e,t,n,r)}catch(a){if(a instanceof na||a.code===ra.NOT_ASYNC_ITERABLE||a.code===ra.STREAM_PROCESSING_FAILED||a.code===ra.STREAM_NOT_ITERABLE||ia.isTimeoutError(a)){let o=new la(i.mcpLog,i.reportProgress);return i.outputFormat===`text`&&!i.isMCP?console.log(V.yellow(`⚠️ Streaming operation ${a.message.includes(`timed out`)?`timed out`:`failed`}. Falling back to non-streaming mode...`)):o.report(`Streaming failed (${a.message}), falling back to non-streaming mode...`,`warn`),await Ro(e,t,n,r)}throw a}return await Ro(e,t,n,r)}async function Bo(e,t,n=!1,r=!1,i={}){let{projectRoot:a,tag:o}=i;try{I(`info`,`Removing subtask ${t}...`);let r=P(e,a,o);if(!r||!r.tasks)throw Error(`Invalid or missing tasks file at ${e}`);if(!t.includes(`.`))throw Error(`Invalid subtask ID format: ${t}. Expected format: "parentId.subtaskId"`);let[i,s]=t.split(`.`),c=parseInt(i,10),l=parseInt(s,10),u=r.tasks.find(e=>e.id===c);if(!u)throw Error(`Parent task with ID ${c} not found`);if(!u.subtasks||u.subtasks.length===0)throw Error(`Parent task ${c} has no subtasks`);let d=u.subtasks.findIndex(e=>e.id===l);if(d===-1)throw Error(`Subtask ${t} not found`);let f={...u.subtasks[d]};u.subtasks.splice(d,1),u.subtasks.length===0&&(u.subtasks=void 0);let p=null;if(n){I(`info`,`Converting subtask ${t} to a standalone task...`);let e=Math.max(...r.tasks.map(e=>e.id))+1;p={id:e,title:f.title,description:f.description||``,details:f.details||``,status:f.status||`pending`,dependencies:f.dependencies||[],priority:u.priority||`medium`},p.dependencies.includes(c)||p.dependencies.push(c),r.tasks.push(p),I(`info`,`Created new task ${e} from subtask ${t}`)}else I(`info`,`Subtask ${t} deleted`);return F(e,r,a,o),p}catch(e){throw I(`error`,`Error removing subtask: ${e.message}`),e}}function Vo(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 Ho(e,t,n={}){let{projectRoot:r,tag:i}=n,a={success:!0,messages:[],errors:[],removedTasks:[]},o=t.split(`,`).map(e=>e.trim()).filter(Boolean);if(o.length===0)return a.success=!1,a.errors.push(`No valid task IDs provided.`),a;try{let t=P(e,r,i);if(!t)throw Error(`Could not read tasks file at ${e}`);let n=t._rawTaggedData||t;if(!n[i]||!n[i].tasks)throw Error(`Tag '${i}' not found or has no tasks.`);let s=n[i].tasks,c=[];for(let e of o)if(Vo(s,e))try{if(typeof e==`string`&&e.includes(`.`)){let[t,n]=e.split(`.`).map(e=>parseInt(e,10)),r=s.find(e=>e.id===t);if(!r||!r.subtasks)throw Error(`Parent task ${t} or its subtasks not found for subtask ${e}`);let o=r.subtasks.findIndex(e=>e.id===n);if(o===-1)throw Error(`Subtask ${n} not found in parent task ${t}`);let c={...r.subtasks[o],parentTaskId:t};a.removedTasks.push(c),r.subtasks.splice(o,1),a.messages.push(`Successfully removed subtask ${e} from tag '${i}'`)}else{let t=parseInt(e,10),n=s.findIndex(e=>e.id===t);if(n===-1)throw Error(`Task with ID ${e} not found in tag '${i}'`);let r=s[n];a.removedTasks.push(r),c.push(t),s.splice(n,1),a.messages.push(`Successfully removed task ${e} from tag '${i}'`)}}catch(t){let n=`Error processing ID ${e}: ${t.message}`;a.errors.push(n),a.success=!1,I(`warn`,n)}else{let t=`Task with ID ${e} in tag '${i}' not found or already removed.`;a.errors.push(t),a.success=!1}if(a.removedTasks.length>0){let t=new Set(o.map(e=>typeof e==`string`&&e.includes(`.`)?e:parseInt(e,10)));n[i].tasks=s;for(let e in n)Object.prototype.hasOwnProperty.call(n,e)&&n[e]&&n[e].tasks&&n[e].tasks.forEach(e=>{e.dependencies&&=e.dependencies.filter(e=>!t.has(e)),e.subtasks&&e.subtasks.forEach(n=>{n.dependencies&&=n.dependencies.filter(n=>!t.has(`${e.id}.${n}`)&&!t.has(n))})});F(e,n,r,i);for(let t of c){let n=H.join(H.dirname(e),`task_${t.toString().padStart(3,`0`)}.txt`);if(Ne.existsSync(n))try{Ne.unlinkSync(n),a.messages.push(`Deleted task file: ${n}`)}catch(e){let t=`Failed to delete task file ${n}: ${e.message}`;a.errors.push(t),a.success=!1,I(`warn`,t)}}}else a.errors.length===0&&a.messages.push(`No tasks found matching the provided IDs.`);let l=a.messages.join(`
|
|
776
|
+
${V.cyan(`1.`)} Run ${V.yellow(`taskgraph list`)} to view all tasks\n${V.cyan(`2.`)} Run ${V.yellow(`taskgraph expand --id=<id>`)} to break down a task into subtasks`,{padding:1,borderColor:`cyan`,borderStyle:`round`,margin:{top:1}})),i?.telemetryData&&Ks(i.telemetryData,`cli`)}async function Xa(e,t){let n=new xa(e.mcpLog,e.reportProgress),{systemPrompt:r,userPrompt:a}=t,o=za(r+a),s=null;e.outputFormat===`text`&&!e.isMCP&&(s=Ms(`Parsing PRD and generating tasks...
|
|
777
|
+
`));try{n.report(`Calling AI service to generate tasks from PRD${e.research?` with research-backed analysis`:``}...`,`info`);let t=await i({role:e.research?`research`:`main`,session:e.session,projectRoot:e.projectRoot,schema:ya,objectName:`tasks_data`,systemPrompt:r,prompt:a,commandName:`parse-prd`,outputType:e.isMCP?`mcp`:`cli`}),c=null;if(t?.mainResult&&(typeof t.mainResult==`object`&&t.mainResult!==null&&`tasks`in t.mainResult?c=t.mainResult:typeof t.mainResult.object==`object`&&t.mainResult.object!==null&&`tasks`in t.mainResult.object&&(c=t.mainResult.object)),!c||!Array.isArray(c.tasks))throw Error(`AI service returned unexpected data structure after validation.`);return s&&Ns(s,`Tasks generated successfully!`),{parsedTasks:c.tasks,aiServiceResponse:t,estimatedInputTokens:o}}catch(e){throw s&&Ps(s,`Error parsing PRD: ${e.message}`),e}}const[Za,Qa,$a]=ti,eo=/* @__PURE__ */ new Map;var to=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]||B.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 no={cli:{filled:`●`,empty:`○`},statusBar:{high:`⋮`,medium:`:`,low:`.`},mcp:{high:`🔴`,medium:`🟠`,low:`🟢`}},ro=new to(`priority`,[Za,Qa,$a],{[Za]:V.red,[Qa]:V.yellow,[$a]:B.muted});function io(e,t){let n=no.cli.filled,r=no.cli.empty,i=``;for(let a=0;a<3;a++)i+=a<e?t(n):B.text(r);return i}function ao(e,t){return 3-t.indexOf(e)}function oo(e,t){if(eo.has(e))return eo.get(e);let n=t();return eo.set(e,n),n}function so(){return oo(`mcp-priority-all`,()=>({[Za]:no.mcp.high,[Qa]:no.mcp.medium,[$a]:no.mcp.low}))}function co(){return oo(`cli-priority-all`,()=>{let e={};return ro.levels.forEach(t=>{let n=ao(t,ro.levels),r=ro.getColor(t);e[t]=io(n,r)}),e})}function lo(){return oo(`statusbar-priority-all`,()=>{let e={};return ro.levels.forEach((t,n)=>{let r=n===0?no.statusBar.high:n===1?no.statusBar.medium:no.statusBar.low,i=ro.getColor(t);e[t]=i(r)}),e})}function uo(){return{[Za]:ro.colors[Za],[Qa]:ro.colors[Qa],[$a]:ro.colors[$a]}}function fo(e=!1){return e?so():co()}function po(e,t=!1){let n=fo(t);return n[e]||n[Qa]}new to(`complexity`,[`high`,`medium`,`low`],{high:V.red,medium:V.yellow,low:V.green},{high:e=>e>=7,medium:e=>e>=4&&e<=6,low:e=>e<=3});const mo={clearOnComplete:!1,stopOnComplete:!0,hideCursor:!0,barsize:40},ho={shades_classic:Ge.Presets.shades_classic,shades_grey:Ge.Presets.shades_grey,rect:Ge.Presets.rect,legacy:Ge.Presets.legacy},go=new class{constructor(e={},t=ho.shades_classic){this.defaultOptions={...mo,...e},this.defaultPreset=t}createSingleBar(e={},t=null){let n=this._mergeConfig(e),r=t||this.defaultPreset;return new Ge.SingleBar(n,r)}createMultiBar(e={},t=null){let n=this._mergeConfig(e),r=t||this.defaultPreset;return new Ge.MultiBar(n,r)}_mergeConfig(e){return{...this.defaultOptions,...e}}setDefaultOptions(e){this.defaultOptions={...this.defaultOptions,...e}}setDefaultPreset(e){this.defaultPreset=e}};function _o(e={}){return go.createMultiBar(e)}var vo=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=_o(),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(){}},yo=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 bo(e,t,n){new yo(e).createHeader(t,n)}function xo(e,t,n){new yo(e).createRow(t,n)}function So(e,t){new yo(e).createBorder(t)}co();const Co=lo();uo();const wo={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 To=class{constructor(e=wo.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}},Eo=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():wo.DEFAULT_PRIORITY;return wo.VALID_PRIORITIES.includes(t)?t:wo.DEFAULT_PRIORITY}getCounts(){return{...this.priorities}}},Do=class{static formatTitle(e,t){return e?e.length>wo.MAX_TITLE_LENGTH?e.substring(0,wo.TRUNCATED_LENGTH)+`...`:e:`Task ${t}`}static formatPriority(e){return po(e,!1).padEnd(wo.PRIORITY_PAD_END,` `)}static formatTaskId(e){return e.toString().padStart(wo.TASK_ID_PAD_START,` `).padEnd(wo.TASK_ID_PAD_END,` `)}},Oo=class extends vo{_initializeCustomProperties(e){this.append=e.append,this.priorityManager=new Eo,this.debouncer=new To,this.headerShown=!1}_getTimeTokensBarFormat(){return`{clock} {elapsed} | ${Co.high} {high} ${Co.medium} {medium} ${Co.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,bo(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=Do.formatTitle(t,e),i=Do.formatPriority(n),a=Do.formatTaskId(e);xo(this.multibar,` ${a} | ${i} | {title}`,{title:r}),So(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 ko(e={}){return new Oo(e)}async function Ao(e,t,n){let r=jo(e,t,n);await No(e,n,r.estimatedInputTokens);let i=await Po(e,t,e.streamingTimeout),{progressTracker:a,priorityMap:o}=await Fo(e,n),s=await Io(i.mainResult,e,t,n,a,o,r.defaultPriority,r.estimatedInputTokens,r.logger);if(Mo(s),s.usage&&e.projectRoot){let{logAiUsage:t}=await import(`./ai-services-unified-CHZ3zO7j.js`),{getUserId:n}=await import(`./config-manager-96j0so3y.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 Ko(s,i,r.estimatedInputTokens,a)}function jo(e,t,n){let{systemPrompt:r,userPrompt:i}=t;return{logger:new xa(e.mcpLog,e.reportProgress),estimatedInputTokens:za(r+i),defaultPriority:ue(e.projectRoot)||`medium`}}function Mo(e){if(e.parsedTasks.length===0)throw Error(`No tasks were generated from the PRD`)}async function No(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 Po(e,n,r){let{systemPrompt:i,userPrompt:a}=n;return await ga.withTimeout(t({role:e.research?`research`:`main`,session:e.session,projectRoot:e.projectRoot,schema:ya,systemPrompt:i,prompt:a,commandName:`parse-prd`,outputType:e.isMCP?`mcp`:`cli`}),r,`Streaming operation`)}async function Fo(e,t){let n=fo(e.isMCP),r=null;if(e.outputFormat===`text`&&!e.isMCP){r=ko({numUnits:t,unitName:`task`,append:e.append});let n=e.research?Ee():xe(),i=ge(e.research?`research`:`main`);ja({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 Io(e,t,n,r,i,a,o,s,c){let{systemPrompt:l,userPrompt:u}=n,d={config:{...t,schema:ya},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 Lo(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 Vo(t,d)}catch(e){return c.report(`StreamObject processing failed: ${e.message}. Falling back to generateObject.`,`debug`),await Go(d,c)}}async function Lo(e,t,n){for await(let r of e)t.lastPartialObject=r,r&&(t.estimatedOutputTokens=za(JSON.stringify(r))),await Ro(r,t,n)}async function Ro(e,t,n){if(!e?.tasks||!Array.isArray(e.tasks))return;let r=e.tasks.length;r>t.taskCount?(await zo(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 zo(e,t,n,r,i){for(let a=t;a<n;a++){let t=e[a]||{};t.title?await qa({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 Bo(a+1,r,i)}}async function Bo(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 Vo(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 Ho(n.tasks,i,a?o:r,t,a?s:null),{parsedTasks:n.tasks,estimatedOutputTokens:o,actualInputTokens:s,usage:a,usedFallback:!1}}async function Ho(e,t,n,r,i=null){let{progressTracker:a,defaultPriority:o,estimatedInputTokens:s}=r;t>0?Uo(e,a,o):await Wo(e,n,r),a.updateTokens(i||s,n,!1),a.stop()}function Uo(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 Wo(e,t,n){for(let r=0;r<e.length;r++){let i=e[r];i?.title&&await qa({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 Go(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 i({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||za(JSON.stringify(r)),i=n.telemetryData?.inputTokens||e.estimatedInputTokens;e.progressTracker.updateTokens(i,t,!1)}return{parsedTasks:r.tasks,estimatedOutputTokens:n.telemetryData?.outputTokens||za(JSON.stringify(r)),actualInputTokens:n.telemetryData?.inputTokens,telemetryData:n.telemetryData,usedFallback:!0}}throw Error(`Failed to generate tasks using generateObject fallback`)}function Ko(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 qo(e,t,n){let r=new xa(e.mcpLog,e.reportProgress);r.report(`Parsing PRD file: ${e.prdPath}, Force: ${e.force}, Append: ${e.append}, Research: ${e.research}`,`debug`);try{let{existingTasks:i,nextId:a}=Va(e.tasksPath,e.targetTag);Ha({existingTasks:i,targetTag:e.targetTag,append:e.append,force:e.force,isMCP:e.isMCP,logger:r});let o=await t(e,await Ka(e,Ba(e.prdPath),a),e.numTasks),s=ue(e.projectRoot)||`medium`,c=Ua(o.parsedTasks,a,i,s),l=e.append?[...i,...c]:c;return Ga(e.tasksPath,l,e.targetTag,r),await Jo(e,o,c,l,a,n),{success:!0,tasksPath:e.tasksPath,telemetryData:o.aiServiceResponse?.telemetryData,tagInfo:o.aiServiceResponse?.tagInfo}}catch(t){throw r.report(`Error parsing PRD: ${t.message}`,`error`),e.isMCP||(console.error(V.red(`Error: ${t.message}`)),L(e.projectRoot)&&console.error(t)),t}}async function Jo(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 Ja({processedTasks:n,nextId:i,summary:t.summary,prdPath:e.prdPath,tasksPath:e.tasksPath,usedFallback:t.usedFallback,aiServiceResponse:o}):a||Ya({processedTasks:n,research:e.research,finalTasks:r,tasksPath:e.tasksPath,aiServiceResponse:o}))}async function Yo(e,t,n,r={}){return qo(new ba(e,t,n,r),Ao,!0)}async function Xo(e,t,n,r={}){return qo(new ba(e,t,n,r),Xa,!1)}async function Zo(e,t,n,r={}){let i=new ba(e,t,n,r);if(i.useStreaming)try{return await Yo(e,t,n,r)}catch(a){if(a instanceof ma||a.code===ha.NOT_ASYNC_ITERABLE||a.code===ha.STREAM_PROCESSING_FAILED||a.code===ha.STREAM_NOT_ITERABLE||ga.isTimeoutError(a)){let o=new xa(i.mcpLog,i.reportProgress);return i.outputFormat===`text`&&!i.isMCP?console.log(V.yellow(`⚠️ Streaming operation ${a.message.includes(`timed out`)?`timed out`:`failed`}. Falling back to non-streaming mode...`)):o.report(`Streaming failed (${a.message}), falling back to non-streaming mode...`,`warn`),await Xo(e,t,n,r)}throw a}return await Xo(e,t,n,r)}async function Qo(e,t,n=!1,r=!1,i={}){let{projectRoot:a,tag:o}=i;try{I(`info`,`Removing subtask ${t}...`);let r=P(e,a,o);if(!r||!r.tasks)throw Error(`Invalid or missing tasks file at ${e}`);if(!t.includes(`.`))throw Error(`Invalid subtask ID format: ${t}. Expected format: "parentId.subtaskId"`);let[i,s]=t.split(`.`),c=parseInt(i,10),l=parseInt(s,10),u=r.tasks.find(e=>e.id===c);if(!u)throw Error(`Parent task with ID ${c} not found`);if(!u.subtasks||u.subtasks.length===0)throw Error(`Parent task ${c} has no subtasks`);let d=u.subtasks.findIndex(e=>e.id===l);if(d===-1)throw Error(`Subtask ${t} not found`);let f={...u.subtasks[d]};u.subtasks.splice(d,1),u.subtasks.length===0&&(u.subtasks=void 0);let p=null;if(n){I(`info`,`Converting subtask ${t} to a standalone task...`);let e=Math.max(...r.tasks.map(e=>e.id))+1;p={id:e,title:f.title,description:f.description||``,details:f.details||``,status:f.status||`pending`,dependencies:f.dependencies||[],priority:u.priority||`medium`},p.dependencies.includes(c)||p.dependencies.push(c),r.tasks.push(p),I(`info`,`Created new task ${e} from subtask ${t}`)}else I(`info`,`Subtask ${t} deleted`);return F(e,r,a,o),p}catch(e){throw I(`error`,`Error removing subtask: ${e.message}`),e}}function $o(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 es(e,t,n={}){let{projectRoot:r,tag:i}=n,a={success:!0,messages:[],errors:[],removedTasks:[]},o=t.split(`,`).map(e=>e.trim()).filter(Boolean);if(o.length===0)return a.success=!1,a.errors.push(`No valid task IDs provided.`),a;try{let t=P(e,r,i);if(!t)throw Error(`Could not read tasks file at ${e}`);let n=t._rawTaggedData||t;if(!n[i]||!n[i].tasks)throw Error(`Tag '${i}' not found or has no tasks.`);let s=n[i].tasks,c=[];for(let e of o)if($o(s,e))try{if(typeof e==`string`&&e.includes(`.`)){let[t,n]=e.split(`.`).map(e=>parseInt(e,10)),r=s.find(e=>e.id===t);if(!r||!r.subtasks)throw Error(`Parent task ${t} or its subtasks not found for subtask ${e}`);let o=r.subtasks.findIndex(e=>e.id===n);if(o===-1)throw Error(`Subtask ${n} not found in parent task ${t}`);let c={...r.subtasks[o],parentTaskId:t};a.removedTasks.push(c),r.subtasks.splice(o,1),a.messages.push(`Successfully removed subtask ${e} from tag '${i}'`)}else{let t=parseInt(e,10),n=s.findIndex(e=>e.id===t);if(n===-1)throw Error(`Task with ID ${e} not found in tag '${i}'`);let r=s[n];a.removedTasks.push(r),c.push(t),s.splice(n,1),a.messages.push(`Successfully removed task ${e} from tag '${i}'`)}}catch(t){let n=`Error processing ID ${e}: ${t.message}`;a.errors.push(n),a.success=!1,I(`warn`,n)}else{let t=`Task with ID ${e} in tag '${i}' not found or already removed.`;a.errors.push(t),a.success=!1}if(a.removedTasks.length>0){let t=new Set(o.map(e=>typeof e==`string`&&e.includes(`.`)?e:parseInt(e,10)));n[i].tasks=s;for(let e in n)Object.prototype.hasOwnProperty.call(n,e)&&n[e]&&n[e].tasks&&n[e].tasks.forEach(e=>{e.dependencies&&=e.dependencies.filter(e=>!t.has(e)),e.subtasks&&e.subtasks.forEach(n=>{n.dependencies&&=n.dependencies.filter(n=>!t.has(`${e.id}.${n}`)&&!t.has(n))})});F(e,n,r,i);for(let t of c){let n=H.join(H.dirname(e),`task_${t.toString().padStart(3,`0`)}.txt`);if(Ne.existsSync(n))try{Ne.unlinkSync(n),a.messages.push(`Deleted task file: ${n}`)}catch(e){let t=`Failed to delete task file ${n}: ${e.message}`;a.errors.push(t),a.success=!1,I(`warn`,t)}}}else a.errors.length===0&&a.messages.push(`No tasks found matching the provided IDs.`);let l=a.messages.join(`
|
|
768
778
|
`),u=a.errors.join(`
|
|
769
779
|
`);return{success:a.success,message:l||`No tasks were removed.`,error:u||null,removedTasks:a.removedTasks}}catch(e){return I(`error`,`Error removing tasks: ${e.message}`),{success:!1,message:``,error:`Operation failed: ${e.message}`,removedTasks:[]}}}Re.use(ze({code:e=>e.split(`
|
|
770
780
|
`).map(e=>` `+V.cyan(e)).join(`
|
|
771
|
-
`),blockquote:B.muted.italic,html:B.muted,heading:B.text.bold,hr:B.muted,listitem:B.text,paragraph:B.text,strong:B.text.bold,em:B.text.italic,codespan:V.cyan,del:V.dim.strikethrough,link:B.brand,href:B.brand.underline,showSectionPrefix:!1,unescape:!0,emoji:!1,tab:4,width:100})),Re.setOptions({breaks:!0,gfm:!0});async function
|
|
781
|
+
`),blockquote:B.muted.italic,html:B.muted,heading:B.text.bold,hr:B.muted,listitem:B.text,paragraph:B.text,strong:B.text.bold,em:B.text.italic,codespan:V.cyan,del:V.dim.strikethrough,link:B.brand,href:B.brand.underline,showSectionPrefix:!1,unescape:!0,emoji:!1,tab:4,width:100})),Re.setOptions({breaks:!0,gfm:!0});async function ts(t,r={},i={},a=`text`,o=!0){let{taskIds:s=[],filePaths:c=[],customContext:l=``,includeProjectTree:u=!1,detailLevel:d=`medium`,projectRoot:f,tag:p,saveToFile:m=!1}=r,{session:h,mcpLog:g,commandName:_=`research`,outputType:v=`cli`}=i,y=!!g,b=f||Se();if(!b)throw Error(`Could not determine project root directory`);let x=y?g:{info:(...e)=>I(`info`,...e),warn:(...e)=>I(`warn`,...e),error:(...e)=>I(`error`,...e),debug:(...e)=>I(`debug`,...e),success:(...e)=>I(`success`,...e)};a===`text`&&console.log(G(V.cyan.bold(`🔍 AI Research Query`),{padding:1,borderColor:`cyan`,borderStyle:`round`,margin:{top:1,bottom:1}}));try{let f=new Ai(b,p),g=[...s],S=[];try{let e=H.join(b,`.taskgraph`,`tasks`,`tasks.json`),n=await P(e,b,p);if(n&&n.tasks&&n.tasks.length>0){let e=new Ii(ae(n.tasks),`research`),r=e.findRelevantTasks(t,{maxResults:8,includeRecent:!0,includeCategoryMatches:!0});S=e.getTaskIds(r);let i=S.filter(e=>!g.includes(e));if(g=[...g,...i],a===`text`&&g.length>0){let e=g.map(e=>parseInt(e)).sort((e,t)=>e-t).map(e=>e.toString());if(s.length>0){let e=s.map(e=>parseInt(e)).sort((e,t)=>e-t).map(e=>e.toString());if(console.log(B.muted(`Provided tasks: `)+V.cyan(e.join(`, `))),i.length>0){let e=i.map(e=>parseInt(e)).sort((e,t)=>e-t).map(e=>e.toString());console.log(B.muted(`+ Auto-discovered related tasks: `)+V.cyan(e.join(`, `)))}}else console.log(B.muted(`Auto-discovered relevant tasks: `)+V.cyan(e.join(`, `)))}}}catch(e){x.debug(`Could not auto-discover tasks: ${e.message}`)}let C=await f.gather({tasks:g,files:c,customContext:l,includeProjectTree:u,format:`research`,includeTokenCounts:!0}),w=C.context,T=C.tokenBreakdown,ee=Oi(),E={query:t,gatheredContext:w||``,detailLevel:d,projectInfo:{root:b,taskCount:g.length,fileCount:c.length}},{systemPrompt:D,userPrompt:O}=await ee.loadPrompt(`research`,E),k=f.countTokens(D),A=f.countTokens(O),te=k+A;a===`text`&&ns(T,k,A),a!==`text`&&x.info(`Calling AI service with research role, context size: ${T.total} tokens (${w.length} characters)`);let j,M=``;try{if(a===`text`){console.log(V.cyan(`
|
|
772
782
|
🔍 Researching with AI...
|
|
773
783
|
`)),j=await e({role:`research`,session:h,projectRoot:b,systemPrompt:D,prompt:O,commandName:_,outputType:v,experimental_transform:Xe({delayInMs:15,chunking:`word`})});for await(let e of j.mainResult.textStream){M+=e;let t=``;for(let n=0;n<e.length;n++)e.slice(n).startsWith(`<think>`)?n+=6:e.slice(n).startsWith(`</think>`)?n+=7:t+=e[n];t&&process.stdout.write(B.muted(t))}if(console.log(`
|
|
774
784
|
`),j.mainResult.usage){let e=await j.mainResult.usage,t=e.promptTokens||e.inputTokens||0,n=e.completionTokens||e.outputTokens||0,r=e.totalTokens||t+n;j.telemetryData={...j.telemetryData,inputTokens:t,outputTokens:n,totalTokens:r}}let n=process.stdout.columns||80,r=Math.min(n-4,120),i=G(V.green.bold(`Research Results`)+`
|
|
775
785
|
|
|
776
786
|
`+B.muted(`Query: `)+B.text(t)+`
|
|
777
|
-
`+B.muted(`Detail Level: `)+V.cyan(d),{padding:{top:1,bottom:1,left:2,right:2},margin:{top:0,bottom:0},borderStyle:`round`,borderColor:`green`,width:r});console.log(i);let a=M.replace(/<think>[\s\S]*?<\/think>/g,``).trim(),o=await Re.parse(a),s=G(o.trim(),{padding:{top:1,bottom:1,left:2,right:2},margin:{top:0,bottom:1},borderStyle:`single`,borderColor:`white`,width:r});console.log(s)}else j=await n({role:`research`,session:h,projectRoot:b,systemPrompt:D,prompt:O,commandName:_,outputType:v}),M=j.mainResult}catch(e){throw e}let ne=j.telemetryData,re=j.tagInfo,ie={interactiveSaveOccurred:!1};if(a===`text`&&(ne&&
|
|
787
|
+
`+B.muted(`Detail Level: `)+V.cyan(d),{padding:{top:1,bottom:1,left:2,right:2},margin:{top:0,bottom:0},borderStyle:`round`,borderColor:`green`,width:r});console.log(i);let a=M.replace(/<think>[\s\S]*?<\/think>/g,``).trim(),o=await Re.parse(a),s=G(o.trim(),{padding:{top:1,bottom:1,left:2,right:2},margin:{top:0,bottom:1},borderStyle:`single`,borderColor:`white`,width:r});console.log(s)}else j=await n({role:`research`,session:h,projectRoot:b,systemPrompt:D,prompt:O,commandName:_,outputType:v}),M=j.mainResult}catch(e){throw e}let ne=j.telemetryData,re=j.tagInfo,ie={interactiveSaveOccurred:!1};if(a===`text`&&(ne&&Ks(ne,`cli`),o&&!y&&(ie=await rs(r,i,a,b,x,t,M))),m&&y){let e=await as([{question:t,answer:M,type:`initial`,timestamp:(/* @__PURE__ */ new Date()).toISOString()}],b,i,x);return{query:t,result:M,contextSize:w.length,contextTokens:T.total,tokenBreakdown:T,systemPromptTokens:k,userPromptTokens:A,totalInputTokens:te,detailLevel:d,telemetryData:ne,tagInfo:re,savedFilePath:e,interactiveSaveOccurred:!1}}return x.success(`Research query completed successfully`),{query:t,result:M,contextSize:w.length,contextTokens:T.total,tokenBreakdown:T,systemPromptTokens:k,userPromptTokens:A,totalInputTokens:te,detailLevel:d,telemetryData:ne,tagInfo:re,interactiveSaveOccurred:ie?.interactiveSaveOccurred||!1}}catch(e){throw x.error(`Research query failed: ${e.message}`),a===`text`&&console.error(V.red(`\n❌ Research failed: ${e.message}`)),e}}function ns(e,t,n){let r=[];if(e.customContext&&r.push(V.cyan(`Custom: `)+V.yellow(e.customContext.tokens.toLocaleString())),e.tasks&&e.tasks.length>0){let t=e.tasks.reduce((e,t)=>e+t.tokens,0),n=e.tasks.map(e=>{let t=e.title.length>30?e.title.substring(0,30)+`...`:e.title;return` ${B.muted(e.id)} ${B.text(t)} ${V.yellow(e.tokens.toLocaleString())} tokens`}).join(`
|
|
778
788
|
`);r.push(V.cyan(`Tasks: `)+V.yellow(t.toLocaleString())+B.muted(` (${e.tasks.length} items)`)+`
|
|
779
789
|
`+n)}if(e.files&&e.files.length>0){let t=e.files.reduce((e,t)=>e+t.tokens,0),n=e.files.map(e=>{let t=e.path.length>40?`...`+e.path.substring(e.path.length-37):e.path;return` ${B.muted(t)} ${V.yellow(e.tokens.toLocaleString())} tokens ${B.muted(`(${e.sizeKB}KB)`)}`}).join(`
|
|
780
790
|
`);r.push(V.cyan(`Files: `)+V.yellow(t.toLocaleString())+B.muted(` (${e.files.length} files)`)+`
|
|
@@ -782,9 +792,9 @@ ${V.cyan(`1.`)} Run ${V.yellow(`taskgraph list`)} to view all tasks\n${V.cyan(`2
|
|
|
782
792
|
`);if(r.push(V.cyan(`Prompts: `)+V.yellow(i.toLocaleString())+B.muted(` (generated)`)+`
|
|
783
793
|
`+a),r.length>0){let e=r.join(`
|
|
784
794
|
|
|
785
|
-
`),t=G(e,{title:B.brand.bold(`Context Analysis`),titleAlignment:`left`,padding:{top:1,bottom:1,left:2,right:2},margin:{top:0,bottom:1},borderStyle:`single`,borderColor:N});console.log(t)}}async function
|
|
795
|
+
`),t=G(e,{title:B.brand.bold(`Context Analysis`),titleAlignment:`left`,padding:{top:1,bottom:1,left:2,right:2},margin:{top:0,bottom:1},borderStyle:`single`,borderColor:N});console.log(t)}}async function rs(e,t,n,r,i,a,o){let s=!1;try{let{readJSON:c}=await import(`./utils-CDh4OilX.js`);(await import(`./update-task-by-id-D5vcjz54.js`)).default;let{updateSubtaskById:l}=await import(`./update-subtask-by-id-D8UzfSSD.js`),u=[{question:a,answer:o,type:`initial`,timestamp:(/* @__PURE__ */ new Date()).toISOString()}];for(;;){let{action:a}=await Ke.prompt([{type:`list`,name:`action`,message:`What would you like to do next?`,choices:[{name:`Ask a follow-up question`,value:`followup`},{name:`Save to file`,value:`savefile`},{name:`Save to task/subtask`,value:`save`},{name:`Quit`,value:`quit`}],pageSize:4}]);if(a===`quit`)break;if(a===`savefile`)await as(u,r,t,i);else if(a===`save`)await is(u,r,t,i)&&(s=!0);else if(a===`followup`){let{followUpQuery:r}=await Ke.prompt([{type:`input`,name:`followUpQuery`,message:`Enter your follow-up question:`,validate:e=>!e||e.trim().length===0?`Please enter a valid question.`:!0}]);if(!r||r.trim().length===0)continue;console.log(`
|
|
786
796
|
`+B.muted(`─`.repeat(60))+`
|
|
787
|
-
`);let i=
|
|
797
|
+
`);let i=cs(u),a={...e,taskIds:[],customContext:i+(e.customContext?`\n\n--- Original Context ---\n${e.customContext}`:``)},o=await ts(r.trim(),a,t,n,!1);u.push({question:r.trim(),answer:o.result,type:`followup`,timestamp:(/* @__PURE__ */ new Date()).toISOString()})}}}catch(e){i.debug(`Follow-up questions not available: ${e.message}`)}return{interactiveSaveOccurred:s}}async function is(e,t,n,r){try{let{readJSON:r}=await import(`./utils-CDh4OilX.js`),i=(await import(`./update-task-by-id-D5vcjz54.js`)).default,{updateSubtaskById:a}=await import(`./update-subtask-by-id-D8UzfSSD.js`),{taskId:o}=await Ke.prompt([{type:`input`,name:`taskId`,message:`Enter task ID (e.g., "15" for task or "15.2" for subtask):`,validate:e=>{if(!e||e.trim().length===0)return`Please enter a task ID.`;let t=e.trim();return/^\d+(\.\d+)?$/.test(t)?!0:`Invalid format. Use "15" for task or "15.2" for subtask.`}}]),s=o.trim(),c=ss(e),l=s.includes(`.`),u=H.join(t,`.taskgraph`,`tasks`,`tasks.json`);if(!W.existsSync(u)){console.log(V.red(`❌ Tasks file not found. Please run taskgraph init first.`));return}let d=r(u,t,n.tag);if(!d||!d.tasks){console.log(V.red(`❌ No valid tasks found.`));return}if(l){let[e,t]=s.split(`.`).map(e=>parseInt(e,10)),r=d.tasks.find(t=>t.id===e);if(!r){console.log(V.red(`❌ Parent task ${e} not found.`));return}if(!r.subtasks||!r.subtasks.find(e=>e.id===t)){console.log(V.red(`❌ Subtask ${s} not found.`));return}console.log(B.brand(`💾 Saving research conversation to subtask...`)),await a(u,s,c,!1,n,`text`),console.log(V.green(`✅ Research conversation saved to subtask ${s}`))}else{let e=parseInt(s,10);if(!d.tasks.find(t=>t.id===e)){console.log(V.red(`❌ Task ${s} not found.`));return}console.log(B.brand(`💾 Saving research conversation to task...`)),await i(u,e,c,!1,n,`text`,!0),console.log(V.green(`✅ Research conversation saved to task ${s}`))}return!0}catch(e){return console.log(V.red(`❌ Error saving conversation: ${e.message}`)),r.error(`Error saving conversation: ${e.message}`),!1}}async function as(e,t,n,r){try{let n=H.join(t,`.taskgraph`,`docs`,`research`);W.existsSync(n)||W.mkdirSync(n,{recursive:!0});let i=e[0]?.question||`research-query`,a=`${(/* @__PURE__ */ new Date()).toISOString().split(`T`)[0]}_${i.toLowerCase().replace(/[^a-z0-9\s-]/g,``).replace(/\s+/g,`-`).replace(/-+/g,`-`).substring(0,50).replace(/^-+|-+$/g,``)}.md`,o=H.join(n,a),s=os(e,i);W.writeFileSync(o,s,`utf8`);let c=H.relative(t,o);return console.log(V.green(`✅ Research saved to: ${V.cyan(c)}`)),r.success(`Research conversation saved to ${c}`),o}catch(e){throw console.log(V.red(`❌ Error saving research file: ${e.message}`)),r.error(`Error saving research file: ${e.message}`),e}}function os(e,t){let n=(/* @__PURE__ */ new Date()).toISOString(),r=`---
|
|
788
798
|
title: Research Session
|
|
789
799
|
query: "${t}"
|
|
790
800
|
date: ${(/* @__PURE__ */ new Date()).toLocaleDateString()}
|
|
@@ -797,10 +807,10 @@ exchanges: ${e.length}
|
|
|
797
807
|
|
|
798
808
|
`;return e.forEach((t,n)=>{t.type===`initial`?r+=`## Initial Query\n\n**Question:** ${t.question}\n\n**Response:**\n\n${t.answer}\n\n`:r+=`## Follow-up ${n}\n\n**Question:** ${t.question}\n\n**Response:**\n\n${t.answer}\n\n`,n<e.length-1&&(r+=`---
|
|
799
809
|
|
|
800
|
-
`)}),r+=`\n---\n\n*Generated by TaskGraph Research Command* \n*Timestamp: ${n}*\n`,r}function
|
|
810
|
+
`)}),r+=`\n---\n\n*Generated by TaskGraph Research Command* \n*Timestamp: ${n}*\n`,r}function ss(e){(/* @__PURE__ */ new Date()).toISOString();let t=`## Research Session - ${(/* @__PURE__ */ new Date()).toLocaleDateString()} ${(/* @__PURE__ */ new Date()).toLocaleTimeString()}\n\n`;return e.forEach((n,r)=>{n.type===`initial`?(t+=`**Initial Query:** ${n.question}\n\n`,t+=`**Response:** ${n.answer}\n\n`):(t+=`**Follow-up ${r}:** ${n.question}\n\n`,t+=`**Response:** ${n.answer}\n\n`),r<e.length-1&&(t+=`---
|
|
801
811
|
|
|
802
|
-
`)}),t}function
|
|
803
|
-
`)}const
|
|
812
|
+
`)}),t}function cs(e){if(e.length===0)return``;let t=[`--- Conversation History ---`];return e.forEach((e,n)=>{let r=e.type===`initial`?`Initial Question`:`Follow-up ${n}`,i=e.type===`initial`?`Initial Answer`:`Answer ${n}`;t.push(`\n${r}: ${e.question}`),t.push(`${i}: ${e.answer}`)}),t.join(`
|
|
813
|
+
`)}const ls=[`light`,`regular`,`heavy`],us=[`done`,`in-progress`,`review`,`cancelled`,`deferred`,`blocked`],ds=[`pending`];function fs(e){return ls.includes(e)}async function ps(e,t,n){let{projectRoot:r,tag:i,session:a}=n;try{let n={tasks:[e],metadata:{analyzedAt:(/* @__PURE__ */ new Date()).toISOString()}},o=A(null,{projectRoot:r,tag:i},null);if(!o)return I(`warn`,`No complexity report found - cannot re-analyze complexity`),null;await Li({file:t,output:o,id:e.id.toString(),projectRoot:r,tag:i,_filteredTasksData:n,_originalTaskCount:1},{session:a});let s=we(o);if(s){let t=oe(s,e.id);if(t)return I(`info`,`Re-analyzed task ${e.id} complexity: ${t.complexityScore}/10`),t.complexityScore}return I(`warn`,`Could not find updated complexity analysis for task ${e.id}`),null}catch(e){return I(`error`,`Failed to re-analyze task complexity: ${e.message}`),null}}function ms(e,t){let{projectRoot:n,tag:r}=t;try{let t=A(null,{projectRoot:n,tag:r},null);if(!t)return null;let i=we(t);if(!i)return null;let a=oe(i,e);return a?a.complexityScore:null}catch(e){return I(`debug`,`Could not read current complexity score: ${e.message}`),null}}async function hs(e,t,n,r,a=`regular`,o=null){let{projectRoot:s,tag:c,session:l}=n;if(!e.subtasks||!Array.isArray(e.subtasks)||e.subtasks.length===0)return{updatedTask:e,regenerated:!1,preserved:0,generated:0};let u=e.subtasks.filter(e=>us.includes(e.status)),d=e.subtasks.filter(e=>ds.includes(e.status));if(d.length===0)return{updatedTask:e,regenerated:!1,preserved:u.length,generated:0};let f,p=u.length,m=d.length,h=o?Math.max(.5,o/10):1,g=o?` (original complexity: ${o}/10)`:``;if(r===`up`){if(a===`light`){let e=Math.max(5,p+Math.ceil(m*1.1));f=Math.ceil(e*(.8+.4*h))}else if(a===`regular`){let e=Math.max(6,p+Math.ceil(m*1.3));f=Math.ceil(e*(.8+.4*h))}else{let e=Math.max(8,p+Math.ceil(m*1.6));f=Math.ceil(e*(.8+.6*h))}}else{let e=o>=8?.7:o>=6?.85:1;if(a===`light`){let t=Math.max(3,p+Math.ceil(m*.8));f=Math.ceil(t*e)}else if(a===`regular`){let t=Math.max(3,p+Math.ceil(m*.5));f=Math.ceil(t*e)}else{let e=o>=9?.3:o>=7?.5:.7,t=Math.max(2,p+Math.ceil(m*.25));f=Math.max(1,Math.ceil(t*e))}}I(`debug`,`Complexity-aware subtask calculation${g}: ${m} pending -> target ${f} total`),I(`debug`,`Complexity-aware calculation${g}: ${m} pending -> ${f} total subtasks (${a} ${r})`);let _=Math.max(1,f-p);try{let t=`Based on this updated task, generate ${_} NEW subtasks that reflect the ${r===`up`?`increased`:`decreased`} complexity level:
|
|
804
814
|
|
|
805
815
|
**Task Title**: ${e.title}
|
|
806
816
|
**Task Description**: ${e.description}
|
|
@@ -847,7 +857,7 @@ IMPORTANT:
|
|
|
847
857
|
- The 'id' field must be a NUMBER, not a string!
|
|
848
858
|
- Dependencies must be strings, not numbers!
|
|
849
859
|
|
|
850
|
-
Ensure the JSON is valid and properly formatted.`,s=U.object({subtasks:U.array(U.object({id:U.int().positive(),title:U.string().min(5),description:U.string().min(10),dependencies:U.array(U.string()),details:U.string().min(20),status:U.string(),testStrategy:U.string()}))}),c=(await i({role:n.research?`research`:`main`,session:n.session,systemPrompt:`You are an expert project manager who creates task breakdowns that match complexity levels.`,prompt:t,schema:s,objectName:`subtask_regeneration`,commandName:n.commandName||`subtask-regen-${r}`,outputType:n.outputType||`cli`})).mainResult.subtasks||[];
|
|
860
|
+
Ensure the JSON is valid and properly formatted.`,s=U.object({subtasks:U.array(U.object({id:U.int().positive(),title:U.string().min(5),description:U.string().min(10),dependencies:U.array(U.string()),details:U.string().min(20),status:U.string(),testStrategy:U.string()}))}),c=(await i({role:n.research?`research`:`main`,session:n.session,systemPrompt:`You are an expert project manager who creates task breakdowns that match complexity levels.`,prompt:t,schema:s,objectName:`subtask_regeneration`,commandName:n.commandName||`subtask-regen-${r}`,outputType:n.outputType||`cli`})).mainResult.subtasks||[];gs(c);let l=c.map(e=>({...e,status:e.status||`pending`,testStrategy:e.testStrategy||``})),d=u.reduce((e,t)=>Math.max(e,t.id||0),0)+1,f=/* @__PURE__ */ new Map,m=l.map(e=>{let t=e.id,n=d++;return f.set(t,n),{...e,id:n}}).map(t=>({...t,dependencies:(t.dependencies||[]).map(t=>{if(typeof t!=`string`||!t.startsWith(`${e.id}.`))return t;let[,n]=t.split(`.`),r=Number.parseInt(n,10),i=f.get(r);return i?`${e.id}.${i}`:t})}));return e.subtasks=[...u,...m],{updatedTask:e,regenerated:!0,preserved:u.length,generated:m.length}}catch(t){return I(`warn`,`Failed to regenerate subtasks for task ${e.id}: ${t.message}`),{updatedTask:e,regenerated:!1,preserved:u.length,generated:0,error:t.message}}}function gs(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 _s(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.
|
|
851
861
|
|
|
852
862
|
CURRENT TASK:
|
|
853
863
|
Title: ${e.title}
|
|
@@ -876,59 +886,59 @@ Return a JSON object with the updated task containing these fields:
|
|
|
876
886
|
- testStrategy: Updated test strategy
|
|
877
887
|
- priority: Task priority ('low', 'medium', or 'high')
|
|
878
888
|
|
|
879
|
-
Ensure the JSON is valid and properly formatted.`,o}async function
|
|
880
|
-
From: ${V.yellow(n)}\nTo: ${V.green(r)}`,{padding:1,borderColor:`green`,borderStyle:`round`}))}return{success:!0,updatedTasks:u.map(({id:e,oldStatus:t,newStatus:n})=>({id:e,oldStatus:t,newStatus:n}))}}catch(e){if(I(`error`,`Error setting task status: ${e.message}`),!r?.mcpLog)console.error(V.red(`Error: ${e.message}`)),L(r?.session)&&console.error(e),process.exit(1);else throw e}}async function
|
|
889
|
+
Ensure the JSON is valid and properly formatted.`,o}async function vs(e,t,n,r,a){let o=_s(e,t,n,r),s=U.object({title:U.string().min(1).describe(`Updated task title reflecting scope adjustment`),description:U.string().min(1).describe(`Updated task description with adjusted scope`),details:U.string().min(1).describe(`Updated implementation details with adjusted complexity`),testStrategy:U.string().min(1).describe(`Updated testing approach for the adjusted scope`),priority:U.enum([`low`,`medium`,`high`]).describe(`Task priority level`)}),c=await i({role:a.research?`research`:`main`,session:a.session,systemPrompt:`You are an expert software project manager who helps adjust task complexity while maintaining clarity and actionability.`,prompt:o,schema:s,objectName:`updated_task`,commandName:a.commandName||`scope-${t}`,outputType:a.outputType||`cli`}),l=c.mainResult,u={...l,priority:l.priority||e.priority||`medium`};return{updatedTask:{...e,...u},telemetryData:c.telemetryData}}async function ys(e,t,n=`regular`,r=null,i={},a=`text`){if(!fs(n))throw Error(`Invalid strength level: ${n}. Must be one of: ${ls.join(`, `)}`);let{projectRoot:o=`.`,tag:s=`master`}=i,c=P(e,o,s),l=c?.tasks||[];for(let e of t)if(!$o(l,e))throw Error(`Task with ID ${e} not found`);let u=[],d=null;for(let f of t){let t=O(l,f).task;if(!t)throw Error(`Task with ID ${f} not found`);a===`text`&&I(`info`,`Scoping up task ${f}: ${t.title}`);let p=ms(f,i);p&&a===`text`&&I(`info`,`Original complexity: ${p}/10`);let m=await vs(t,`up`,n,r,i),h=await hs(m.updatedTask,e,i,`up`,n,p);a===`text`&&h.regenerated&&I(`info`,`Regenerated ${h.generated} pending subtasks (preserved ${h.preserved} completed)`);let g=c.tasks.findIndex(e=>e.id===f);if(g!==-1&&(c.tasks[g]=h.updatedTask,u.push(h.updatedTask)),i.session&&p)try{F(e,c,o,s);let t=await ps(h.updatedTask,e,i);if(t&&a===`text`){let e=t-p;I(`info`,`New complexity: ${p}/10 ${e>0?`↗️`:e<0?`↘️`:`➡️`} ${t}/10 (${e>0?`+`:``}${e})`)}}catch(e){a===`text`&&I(`warn`,`Could not re-analyze complexity: ${e.message}`)}m.telemetryData&&(d?(d.inputTokens+=m.telemetryData.inputTokens||0,d.outputTokens+=m.telemetryData.outputTokens||0,d.totalTokens+=m.telemetryData.totalTokens||0,d.totalCost+=m.telemetryData.totalCost||0):d={...m.telemetryData})}return F(e,c,o,s),a===`text`&&I(`info`,`Successfully scoped up ${u.length} task(s)`),{updatedTasks:u,telemetryData:d}}async function bs(e,t,n=`regular`,r=null,i={},a=`text`){if(!fs(n))throw Error(`Invalid strength level: ${n}. Must be one of: ${ls.join(`, `)}`);let{projectRoot:o=`.`,tag:s=`master`}=i,c=P(e,o,s),l=c?.tasks||[];for(let e of t)if(!$o(l,e))throw Error(`Task with ID ${e} not found`);let u=[],d=null;for(let f of t){let t=O(l,f).task;if(!t)throw Error(`Task with ID ${f} not found`);a===`text`&&I(`info`,`Scoping down task ${f}: ${t.title}`);let p=ms(f,i);p&&a===`text`&&I(`info`,`Original complexity: ${p}/10`);let m=await vs(t,`down`,n,r,i),h=await hs(m.updatedTask,e,i,`down`,n,p);a===`text`&&h.regenerated&&I(`info`,`Regenerated ${h.generated} pending subtasks (preserved ${h.preserved} completed)`);let g=c.tasks.findIndex(e=>e.id===f);if(g!==-1&&(c.tasks[g]=h.updatedTask,u.push(h.updatedTask)),i.session&&p)try{F(e,c,o,s);let t=await ps(h.updatedTask,e,i);if(t&&a===`text`){let e=t-p;I(`info`,`New complexity: ${p}/10 ${e>0?`↗️`:e<0?`↘️`:`➡️`} ${t}/10 (${e>0?`+`:``}${e})`)}}catch(e){a===`text`&&I(`warn`,`Could not re-analyze complexity: ${e.message}`)}m.telemetryData&&(d?(d.inputTokens+=m.telemetryData.inputTokens||0,d.outputTokens+=m.telemetryData.outputTokens||0,d.totalTokens+=m.telemetryData.totalTokens||0,d.totalCost+=m.telemetryData.totalCost||0):d={...m.telemetryData})}return F(e,c,o,s),a===`text`&&I(`info`,`Successfully scoped down ${u.length} task(s)`),{updatedTasks:u,telemetryData:d}}async function xs(e,t,n,r,i=!0){if(!Qr(n))throw Error(`Error: Invalid status value: ${n}. Use one of: ${TASK_STATUS_OPTIONS.join(`, `)}`);if(t.includes(`.`)){let[e,a]=t.split(`.`).map(e=>parseInt(e,10)),o=r.tasks.find(t=>t.id===e);if(!o)throw Error(`Parent task ${e} not found`);if(!o.subtasks)throw Error(`Parent task ${e} has no subtasks`);let s=o.subtasks.find(e=>e.id===a);if(!s)throw Error(`Subtask ${a} not found in parent task ${e}`);let c=s.status||`pending`;s.status=n,I(`info`,`Updated subtask ${e}.${a} status from '${c}' to '${n}'`),(n.toLowerCase()===`done`||n.toLowerCase()===`completed`)&&o.subtasks.every(e=>e.status===`done`||e.status===`completed`)&&o.status!==`done`&&o.status!==`completed`&&i&&(console.log(V.yellow(`All subtasks of parent task ${e} are now marked as done.`)),console.log(V.yellow(`Consider updating the parent task status with: taskgraph set-status --id=${e} --status=done`)))}else{let e=parseInt(t,10),i=r.tasks.find(t=>t.id===e);if(!i)throw Error(`Task ${e} not found`);let a=i.status||`pending`;if(i.status=n,I(`info`,`Updated task ${e} status from '${a}' to '${n}'`),(n.toLowerCase()===`done`||n.toLowerCase()===`completed`)&&i.subtasks&&i.subtasks.length>0){let e=i.subtasks.filter(e=>e.status!==`done`&&e.status!==`completed`);e.length>0&&(I(`info`,`Also marking ${e.length} subtasks as '${n}'`),e.forEach(e=>{e.status=n}))}}}async function Ss(e,t,n,r={}){let{projectRoot:i,tag:a}=r;try{if(!Qr(n))throw Error(`Error: Invalid status value: ${n}. Use one of: ${Zr.join(`, `)}`);let o=!!r?.mcpLog;o||console.log(G(B.text.bold(`Updating Task Status to: ${n}`),{padding:1,borderColor:N,borderStyle:`round`})),I(`info`,`Reading tasks from ${e}...`);let s=P(e,i,a);if(s&&s._rawTaggedData&&(s=s._rawTaggedData),!s||!s[a]||!Array.isArray(s[a].tasks))throw Error(`Invalid tasks file or tag "${a}" not found at ${e}`);let c={tasks:s[a].tasks,tag:a,_rawTaggedData:s};if(!c||!c.tasks)throw Error(`No valid tasks found in ${e}`);let l=t.split(`,`).map(e=>e.trim()),u=[];for(let t of l){let r=`unknown`;if(t.includes(`.`)){let[e,n]=t.split(`.`).map(e=>parseInt(e,10)),i=c.tasks.find(t=>t.id===e);i?.subtasks&&(r=i.subtasks.find(e=>e.id===n)?.status||`pending`)}else{let e=parseInt(t,10);r=c.tasks.find(t=>t.id===e)?.status||`pending`}await xs(e,t,n,c,!o),u.push({id:t,oldStatus:r,newStatus:n})}if(s[a].tasks=c.tasks,D(s[a],{description:`Tasks for ${a} context`}),F(e,s,i,a),I(`info`,`Validating dependencies after status update...`),ic(c.tasks),!o)for(let e of u){let{id:t,oldStatus:n,newStatus:r}=e;console.log(G(B.text.bold(`Successfully updated task ${t} status:`)+`
|
|
890
|
+
From: ${V.yellow(n)}\nTo: ${V.green(r)}`,{padding:1,borderColor:`green`,borderStyle:`round`}))}return{success:!0,updatedTasks:u.map(({id:e,oldStatus:t,newStatus:n})=>({id:e,oldStatus:t,newStatus:n}))}}catch(e){if(I(`error`,`Error setting task status: ${e.message}`),!r?.mcpLog)console.error(V.red(`Error: ${e.message}`)),L(r?.session)&&console.error(e),process.exit(1);else throw e}}async function Cs(e,t,r,i=!1,a={},o=a.mcpLog?`json`:`text`){let{session:s,mcpLog:c,projectRoot:l,tag:u,metadata:d}=a,f=c||I,p=!!c,m=(e,...t)=>{p?typeof f[e]==`function`?f[e](...t):f.info(...t):z()||f(e,...t)},h=null;try{if(m(`info`,`Updating subtask ${t} with prompt: "${r}"`),!t||typeof t!=`string`)throw Error(`Subtask ID cannot be empty.`);if((!r||typeof r!=`string`||r.trim()===``)&&!d)throw Error(`Prompt cannot be empty unless metadata is provided. Please provide context for the subtask update or metadata to merge.`);let a=l||Se();if(!a)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(!W.existsSync(e))throw Error(`Tasks file not found at path: ${e}`);let c=P(e,a,u);if(!c||!c.tasks)throw Error(`No valid tasks found in ${e}. The file may be corrupted or have an invalid format.`);let[f,g]=t.split(`.`),_=parseInt(f,10),v=parseInt(g,10);if(Number.isNaN(_)||_<=0||Number.isNaN(v)||v<=0)throw Error(`Invalid subtask ID format: ${t}. Both parent ID and subtask ID must be positive integers.`);let y=c.tasks.find(e=>e.id===_);if(!y)throw Error(`Parent task with ID ${_} not found. Please verify the task ID and try again.`);if(!y.subtasks||!Array.isArray(y.subtasks))throw Error(`Parent task ${_} has no subtasks.`);let b=y.subtasks.findIndex(e=>e.id===v);if(b===-1)throw Error(`Subtask with ID ${t} not found. Please verify the subtask ID and try again.`);let x=y.subtasks[b];if(d&&(!r||r.trim()===``))return m(`info`,`Metadata-only update for subtask ${t}`),x.metadata={...x.metadata||{},...d},y.subtasks[b]=x,F(e,c,a,u),m(`success`,`Successfully updated metadata for subtask ${t}`),{updatedSubtask:x,telemetryData:null,tagInfo:{tag:u}};let S=``;try{let e=new Ai(a,u),n=new Ii(ae(c.tasks),`update-subtask`),i=`${y.title} ${x.title} ${r}`,o=n.findRelevantTasks(i,{maxResults:5,includeSelf:!0}),s=n.getTaskIds(o),l=[.../* @__PURE__ */ new Set([t.toString(),...s])];l.length>0&&(S=(await e.gather({tasks:l,format:`research`})).context||``)}catch(e){m(`warn`,`Could not gather context: ${e.message}`)}if(o===`text`){let e=new q({head:[V.cyan.bold(`ID`),V.cyan.bold(`Title`),V.cyan.bold(`Status`)],colWidths:[10,55,10],style:{border:le}});e.push([t,R(x.title,52),Is(x.status)]),console.log(G(B.text.bold(`Updating Subtask #${t}`),{padding:1,borderColor:N,borderStyle:`round`,margin:{top:1,bottom:0}})),console.log(e.toString()),h=Ms(i?`Updating subtask with research...`:`Updating subtask...`)}let C=``,w=``,T=null;try{let e={id:y.id,title:y.title},t=b>0?{id:`${y.id}.${y.subtasks[b-1].id}`,title:y.subtasks[b-1].title,status:y.subtasks[b-1].status}:void 0,c=b<y.subtasks.length-1?{id:`${y.id}.${y.subtasks[b+1].id}`,title:y.subtasks[b+1].title,status:y.subtasks[b+1].status}:void 0,l=Oi(),u={parentTask:e,prevSubtask:t,nextSubtask:c,currentDetails:x.details||`(No existing details)`,updatePrompt:r,useResearch:i,gatheredContext:S||``,hasCodebaseAnalysis:ee(i,a,s),projectRoot:a},d=i?`research`:`default`,{systemPrompt:f,userPrompt:g}=await l.loadPrompt(`update-subtask`,u,d),_=i?`research`:`main`;m(`info`,`Using AI text service with role: ${_}`),T=await n({prompt:g,systemPrompt:f,role:_,session:s,projectRoot:a,maxRetries:2,commandName:`update-subtask`,outputType:p?`mcp`:`cli`}),T&&T.mainResult&&typeof T.mainResult==`string`?C=T.mainResult:(C=``,m(`warn`,`AI service response did not contain expected text string.`)),o===`text`&&h&&($(h),h=null)}catch(e){throw m(`error`,`AI service call failed: ${e.message}`),o===`text`&&h&&($(h),h=null),e}if(C&&C.trim()){let e=(/* @__PURE__ */ new Date()).toISOString(),t=`<info added on ${e}>\n${C.trim()}\n</info added on ${e}>`;w=t,x.details=(x.details?x.details+`
|
|
881
891
|
`:``)+t}else m(`warn`,`AI response was empty or whitespace after trimming. Original details remain unchanged.`),w=`No new details were added by the AI.`;let E=y.subtasks[b];return d&&(E.metadata={...E.metadata||{},...d}),o===`text`&&L(s)&&console.log(`>>> DEBUG: Subtask details AFTER AI update:`,E.details),E.description&&r.length<100&&(o===`text`&&L(s)&&console.log(`>>> DEBUG: Subtask description BEFORE append:`,E.description),E.description+=` [Updated: ${(/* @__PURE__ */ new Date()).toLocaleDateString()}]`,o===`text`&&L(s)&&console.log(`>>> DEBUG: Subtask description AFTER append:`,E.description)),o===`text`&&L(s)&&console.log(`>>> DEBUG: About to call writeJSON with updated data...`),F(e,c,a,u),o===`text`&&L(s)&&console.log(`>>> DEBUG: writeJSON call completed.`),m(`success`,`Successfully updated subtask ${t}`),o===`text`&&(h&&=($(h),null),console.log(G(V.green(`Successfully updated subtask #${t}`)+`
|
|
882
892
|
|
|
883
893
|
`+B.text.bold(`Title:`)+` `+E.title+`
|
|
884
894
|
|
|
885
895
|
`+B.text.bold(`Newly Added Snippet:`)+`
|
|
886
|
-
`+B.text(w),{padding:1,borderColor:`green`,borderStyle:`round`}))),o===`text`&&T.telemetryData&&
|
|
896
|
+
`+B.text(w),{padding:1,borderColor:`green`,borderStyle:`round`}))),o===`text`&&T.telemetryData&&Ks(T.telemetryData,`cli`),{updatedSubtask:E,telemetryData:T.telemetryData,tagInfo:T.tagInfo}}catch(e){if(o===`text`&&h&&($(h),h=null),m(`error`,`Error updating subtask: ${e.message}`),o===`text`)console.error(V.red(`Error: ${e.message}`)),e.message?.includes(`overloaded`)?(console.log(V.yellow(`
|
|
887
897
|
AI model overloaded, and fallback failed or was unavailable:`)),console.log(` 1. Try again in a few minutes.`),console.log(` 2. Check that Claude Code is installed and signed in: claude --version`)):e.message?.includes(`not found`)?(console.log(V.yellow(`
|
|
888
898
|
To fix this issue:`)),console.log(` 1. Run taskgraph list --with-subtasks to see all available subtask IDs`),console.log(` 2. Use a valid subtask ID with the --id parameter in format "parentId.subtaskId"`)):(e.message?.includes(`empty stream response`)||e.message?.includes(`AI did not return a valid text string`))&&console.log(V.yellow(`
|
|
889
|
-
The AI model returned an empty or invalid response. This might be due to the prompt or API issues. Try rephrasing or trying again later.`)),L(s)&&console.error(e);else throw e;return null}}async function
|
|
899
|
+
The AI model returned an empty or invalid response. This might be due to the prompt or API issues. Try rephrasing or trying again later.`)),L(s)&&console.error(e);else throw e;return null}}async function ws(e,t,r,a=!1,o={},s=`text`,c=!1){let{session:l,mcpLog:u,projectRoot:d,tag:f,metadata:p}=o,{report:m,isMCP:h}=zi(u,l);try{if(m(`info`,`Updating single task ${t} with prompt: "${r}"`),t==null||String(t).trim()===``)throw Error(`Task ID cannot be empty.`);if((!r||typeof r!=`string`||r.trim()===``)&&!p)throw Error(`Prompt cannot be empty unless metadata is provided for update.`);let o=d||Se();if(!o)throw Error(`Could not determine project root directory`);if(!W.existsSync(e))throw Error(`Tasks file not found: ${e}`);let u=P(e,o,f);if(!u||!u.tasks)throw Error(`No valid tasks found in ${e}.`);let g=String(t).trim();if(!/^\d+$/.test(g))throw Error(`taskId must be a positive integer. Use update-subtask-by-id for IDs like "1.2".`);let _=Number(g),v=u.tasks.findIndex(e=>e.id===_);if(v===-1)throw m(`error`,`Task with ID ${_} not found`),Error(`Task with ID ${_} not found.`);let y=u.tasks[v];if(y.status===`done`||y.status===`completed`)return m(`warn`,`Task ${t} is already marked as done and cannot be updated`),s===`text`&&console.log(G(V.yellow(`Task ${t} is already marked as ${y.status} and cannot be updated.`)+`
|
|
890
900
|
|
|
891
901
|
`+B.text(`Completed tasks are locked to maintain consistency. To modify a completed task, you must first:`)+`
|
|
892
902
|
`+B.text(`1. Change its status to "pending" or "in-progress"`)+`
|
|
893
|
-
`+B.text(`2. Then run the update-task command`),{padding:1,borderColor:`yellow`,borderStyle:`round`})),null;if(p&&(!r||r.trim()===``))return m(`info`,`Metadata-only update for task ${t}`),y.metadata={...y.metadata||{},...p},u.tasks[v]=y,F(e,u,o,f),m(`success`,`Successfully updated metadata for task ${t}`),{updatedTask:y,telemetryData:null,tagInfo:{tag:f}};let b=``;try{let e=new
|
|
903
|
+
`+B.text(`2. Then run the update-task command`),{padding:1,borderColor:`yellow`,borderStyle:`round`})),null;if(p&&(!r||r.trim()===``))return m(`info`,`Metadata-only update for task ${t}`),y.metadata={...y.metadata||{},...p},u.tasks[v]=y,F(e,u,o,f),m(`success`,`Successfully updated metadata for task ${t}`),{updatedTask:y,telemetryData:null,tagInfo:{tag:f}};let b=``;try{let e=new Ai(o,f),n=new Ii(ae(u.tasks),`update-task`),i=`${y.title} ${y.description} ${r}`,a=n.findRelevantTasks(i,{maxResults:5,includeSelf:!0}),s=n.getTaskIds(a),c=[.../* @__PURE__ */ new Set([t.toString(),...s])];c.length>0&&(b=(await e.gather({tasks:c,format:`research`})).context||``)}catch(e){m(`warn`,`Could not gather context: ${e.message}`)}if(s===`text`){let e=new q({head:[V.cyan.bold(`ID`),V.cyan.bold(`Title`),V.cyan.bold(`Status`)],colWidths:[5,60,10],style:{border:le}});e.push([y.id,R(y.title,57),Is(y.status)]),console.log(G(B.text.bold(`Updating Task #${t}`),{padding:1,borderColor:N,borderStyle:`round`,margin:{top:1,bottom:0}})),console.log(e.toString()),console.log(G(V.cyan.bold(`How Completed Subtasks Are Handled:`)+`
|
|
894
904
|
|
|
895
905
|
`+B.text(`• Subtasks marked as "done" or "completed" will be preserved
|
|
896
906
|
`)+B.text(`• New subtasks will build upon what has already been completed
|
|
897
907
|
`)+B.text(`• If completed work needs revision, a new subtask will be created instead of modifying done items
|
|
898
|
-
`)+B.text(`• This approach maintains a clear record of completed work and new requirements`),{padding:1,borderColor:N,borderStyle:`round`,margin:{top:1,bottom:1}}))}let x=
|
|
908
|
+
`)+B.text(`• This approach maintains a clear record of completed work and new requirements`),{padding:1,borderColor:N,borderStyle:`round`,margin:{top:1,bottom:1}}))}let x=Oi(),S={task:y,taskJson:JSON.stringify(y,null,2),updatePrompt:r,appendMode:c,useResearch:a,currentDetails:y.details||`(No existing details)`,gatheredContext:b||``,hasCodebaseAnalysis:ee(a,o,l),projectRoot:o},C=c?`append`:a?`research`:`default`;m(`info`,`Loading prompt template with variant: ${C}, appendMode: ${c}, useResearch: ${a}`);let w,T;try{let e=x.loadPrompt(`update-task`,S,C);m(`info`,`Prompt result type: ${typeof e}, keys: ${e?Object.keys(e).join(`, `):`null`}`),w=e.systemPrompt,T=e.userPrompt,m(`info`,`Loaded prompts - systemPrompt length: ${w?.length}, userPrompt length: ${T?.length}`)}catch(e){throw m(`error`,`Failed to load prompt template: ${e.message}`),Error(`Failed to load prompt template: ${e.message}`)}if(!w||!T)throw Error(`Failed to load prompts: systemPrompt=${!!w}, userPrompt=${!!T}`);let E=null,D=null;!h&&s===`text`&&(E=Ms(a?`Updating task with research...
|
|
899
909
|
`:`Updating task...
|
|
900
|
-
`));try{let d=a?`research`:`main`;if(D=c?await n({role:d,session:l,projectRoot:o,systemPrompt:w,prompt:T,commandName:`update-task`,outputType:h?`mcp`:`cli`}):await i({role:d,session:l,projectRoot:o,systemPrompt:w,prompt:T,schema:
|
|
910
|
+
`));try{let d=a?`research`:`main`;if(D=c?await n({role:d,session:l,projectRoot:o,systemPrompt:w,prompt:T,commandName:`update-task`,outputType:h?`mcp`:`cli`}):await i({role:d,session:l,projectRoot:o,systemPrompt:w,prompt:T,schema:gi[`update-task-by-id`],objectName:`task`,commandName:`update-task`,outputType:h?`mcp`:`cli`}),E&&$(E,`AI update complete.`),c){let n=D.mainResult,i=``;if(n&&n.trim()){let e=(/* @__PURE__ */ new Date()).toISOString(),t=`<info added on ${e}>\n${n.trim()}\n</info added on ${e}>`;i=t,y.details=(y.details?y.details+`
|
|
901
911
|
`:``)+t}else m(`warn`,`AI response was empty or whitespace after trimming. Original details remain unchanged.`),i=`No new details were added by the AI.`;return r.length<100&&y.description&&(y.description+=` [Updated: ${(/* @__PURE__ */ new Date()).toLocaleDateString()}]`),p&&(y.metadata={...y.metadata||{},...p}),u.tasks[v]=y,F(e,u,o,f),m(`success`,`Successfully appended to task ${t}`),s===`text`&&console.log(G(V.green(`Successfully appended to task #${t}`)+`
|
|
902
912
|
|
|
903
913
|
`+B.text.bold(`Title:`)+` `+y.title+`
|
|
904
914
|
|
|
905
915
|
`+B.text.bold(`Newly Added Content:`)+`
|
|
906
|
-
`+B.text(i),{padding:1,borderColor:`green`,borderStyle:`round`})),s===`text`&&D.telemetryData&&
|
|
916
|
+
`+B.text(i),{padding:1,borderColor:`green`,borderStyle:`round`})),s===`text`&&D.telemetryData&&Ks(D.telemetryData,`cli`),{updatedTask:y,telemetryData:D.telemetryData,tagInfo:D.tagInfo}}let g=D.mainResult?.task;if(!g||typeof g!=`object`)throw Error(`Received invalid task object from AI.`);let _={...g,dependencies:g.dependencies??[],priority:g.priority??null,details:g.details??null,testStrategy:g.testStrategy??null};if(!_.title||!_.description)throw Error(`Updated task missing required fields.`);if(_.id!==t&&(m(`warn`,`AI changed task ID. Restoring original ID ${t}.`),_.id=t),_.status!==y.status&&!r.toLowerCase().includes(`status`)&&(m(`warn`,`AI changed task status. Restoring original status '${y.status}'.`),_.status=y.status),_.subtasks&&Array.isArray(_.subtasks)){let e=1;_.subtasks=_.subtasks.map(t=>{let n=y.subtasks?.find(e=>String(e.id)===String(t.id)||t.title&&e.title===t.title),r={...t,id:e,dependencies:Array.isArray(t.dependencies)?t.dependencies.map(e=>typeof e==`string`?parseInt(e,10):e).filter(t=>!Number.isNaN(t)&&t>=1&&t<e):[],status:t.status||`pending`,testStrategy:t.testStrategy??null,...n?.metadata&&{metadata:n.metadata}};return e++,r}),m(`info`,`Fixed ${_.subtasks.length} subtask IDs to be sequential numeric IDs.`)}if(y.subtasks?.length>0){if(!_.subtasks)m(`warn`,`Subtasks removed by AI. Restoring original subtasks.`),_.subtasks=y.subtasks;else{y.subtasks.filter(e=>e.status===`done`||e.status===`completed`).forEach(e=>{let t=_.subtasks.find(t=>t.id===e.id);(!t||JSON.stringify(t)!==JSON.stringify(e))&&(m(`warn`,`Completed subtask ${e.id} was modified or removed. Restoring.`),_.subtasks=_.subtasks.filter(t=>t.id!==e.id),_.subtasks.push(e))});let e=/* @__PURE__ */ new Set;_.subtasks=_.subtasks.filter(t=>e.has(t.id)?(m(`warn`,`Duplicate subtask ID ${t.id} removed.`),!1):(e.add(t.id),!0))}}return(y.metadata||p)&&(_.metadata={...y.metadata||{},...p||{}}),u.tasks[v]=_,F(e,u,o,f),m(`success`,`Successfully updated task ${t}`),s===`text`&&D.telemetryData&&Ks(D.telemetryData,`cli`),{updatedTask:_,telemetryData:D.telemetryData,tagInfo:D.tagInfo}}catch(e){throw E&&$(E),m(`error`,`Error during AI service call: ${e.message}`),e.message.includes(`API key`)&&m(`error`,`Please ensure API keys are configured correctly.`),e}}catch(e){throw m(`error`,`Error updating task: ${e.message}`),s===`text`&&(console.error(V.red(`Error: ${e.message}`)),L(l)&&console.error(e),process.exit(1)),e}}async function Ts(e,t,n,r=!1,a={},o=`text`){let{session:s,mcpLog:c,projectRoot:l,tag:u}=a,d=c||I,f=!!c;f?d.info(`updateTasks called with context: session=${!!s}`):d(`info`,`updateTasks called`);try{f?d.info(`Updating tasks from ID ${t}`):d(`info`,`Updating tasks from ID ${t} with prompt: "${n}"`);let a=l||Se();if(!a)throw Error(`Could not determine project root directory`);let c=P(e,a,u);if(!c||!c.tasks)throw Error(`No valid tasks found in ${e}`);let p=c.tasks.filter(e=>e.id>=t&&e.status!==`done`);if(p.length===0){f?d.info(`No tasks to update (ID >= ${t} and not 'done').`):d(`info`,`No tasks to update (ID >= ${t} and not 'done').`),o===`text`&&console.log();return}let m=``;try{let e=new Ai(a,u),t=new Ii(ae(c.tasks),`update`),r=t.findRelevantTasks(n,{maxResults:5,includeSelf:!0}),i=t.getTaskIds(r),o=p.map(e=>e.id.toString()),s=[.../* @__PURE__ */ new Set([...o,...i])];s.length>0&&(m=(await e.gather({tasks:s,format:`research`})).context||``)}catch(e){d(`warn`,`Could not gather additional context: ${e.message}`)}if(o===`text`){let e=new q({head:[V.cyan.bold(`ID`),V.cyan.bold(`Title`),V.cyan.bold(`Status`)],colWidths:[5,70,20],style:{border:le}});p.forEach(t=>{e.push([t.id,R(t.title,57),Is(t.status)])}),console.log(G(B.text.bold(`Updating ${p.length} tasks`),{padding:1,borderColor:N,borderStyle:`round`,margin:{top:1,bottom:0}})),console.log(e.toString()),console.log(G(V.cyan.bold(`How Completed Subtasks Are Handled:`)+`
|
|
907
917
|
|
|
908
918
|
`+B.text(`• Subtasks marked as "done" or "completed" will be preserved
|
|
909
919
|
`)+B.text(`• New subtasks will build upon what has already been completed
|
|
910
920
|
`)+B.text(`• If completed work needs revision, a new subtask will be created instead of modifying done items
|
|
911
|
-
`)+B.text(`• This approach maintains a clear record of completed work and new requirements`),{padding:1,borderColor:N,borderStyle:`round`,margin:{top:1,bottom:1}}))}let{systemPrompt:h,userPrompt:g}=await
|
|
912
|
-
`));try{v=await i({role:r?`research`:`main`,session:s,projectRoot:a,systemPrompt:h,prompt:g,schema:ai[`update-tasks`],objectName:`tasks`,commandName:`update-tasks`,outputType:f?`mcp`:`cli`}),_&&$(_,`AI update complete.`);let t=v.mainResult.tasks.map(e=>({...e,dependencies:e.dependencies??[],priority:e.priority??null,details:e.details??null,testStrategy:e.testStrategy??null,subtasks:e.subtasks?e.subtasks.map(e=>({...e,dependencies:e.dependencies??[],status:e.status??`pending`,testStrategy:e.testStrategy??null})):null}));if(!Array.isArray(t))throw Error(`Parsed AI response for updated tasks was not an array.`);f?d.info(`Received ${t.length} updated tasks from AI.`):d(`info`,`Received ${t.length} updated tasks from AI.`);let n=new Map(t.map(e=>[e.id,e])),l=0;return c.tasks.forEach((e,t)=>{if(n.has(e.id)){let r=n.get(e.id);c.tasks[t]={...e,...r,subtasks:r.subtasks===void 0?e.subtasks:r.subtasks},l++}}),f?d.info(`Applied updates to ${l} tasks in the dataset.`):d(`info`,`Applied updates to ${l} tasks in the dataset.`),F(e,c,a,u),f?d.info(`Successfully updated ${l} tasks in ${e}`):d(`success`,`Successfully updated ${l} tasks in ${e}`),o===`text`&&v.telemetryData&&Ps(v.telemetryData,`cli`),{success:!0,updatedTasks:t,telemetryData:v.telemetryData,tagInfo:v.tagInfo}}catch(e){throw _&&$(_),f?d.error(`Error during AI service call: ${e.message}`):d(`error`,`Error during AI service call: ${e.message}`),e.message.includes(`API key`)&&(f?d.error(`Please ensure API keys are configured correctly in .env or mcp.json.`):d(`error`,`Please ensure API keys are configured correctly in .env or mcp.json.`)),e}finally{_&&$(_)}}catch(e){if(f?d.error(`Error updating tasks: ${e.message}`):d(`error`,`Error updating tasks: ${e.message}`),o===`text`)console.error(V.red(`Error: ${e.message}`)),L(s)&&console.error(e),process.exit(1);else throw e}}const{theme:Q,BORDER_COLOR:ms,TABLE_BORDER:hs}=yn,gs=Ie(he);function _s(e){!z()&&e&&e._migrationHappened&&console.log(G(V.bold(`FYI: `)+Q.muted(`TaskGraph now supports separate task lists per tag. `)+V.cyan(`Use the --tag flag to create/read/update/filter tasks by tag.`),{padding:{top:0,bottom:0,left:2,right:2},borderColor:`cyan`,borderStyle:`round`,margin:{top:1,bottom:1}}))}async function vs(e,t={}){if(z())return;let{skipIfMaster:n=!1,dim:r=!1}=t;if(n&&e===`master`)return;let i=r?Q.muted(`[tag] ${e}`):V.dim(`[tag] `)+V.cyan(e);console.log(i)}function ys(){z()||st({version:Hr(),projectName:me(null)})}function bs(e){return z()?null:un(e).start()}function $(e){e&&typeof e.stop==`function`&&e.stop()}function xs(e,t=null){e&&typeof e.succeed==`function`&&(t?e.succeed(t):e.succeed())}function Ss(e,t=null){e&&typeof e.fail==`function`&&(t?e.fail(t):e.fail())}function Cs(e,t=30,n=null){let r=n?Math.min(100,e+(n.deferred||0)+(n.cancelled||0)):e,i=Math.round(e*t/100),a=Math.round(r*t/100),o=a-i,s=t-a,c;c=e<25?V.red:e<50||e<75?V.yellow:V.green;let l=c(`█`.repeat(i)),u=Q.muted(`─`.repeat(o)),d=``;if(n&&s>0){let e={pending:e=>V.yellow(`░`.repeat(e)),"in-progress":e=>Q.active(`▓`.repeat(e)),blocked:e=>V.red(`!`.repeat(e)),review:e=>V.magenta(`▒`.repeat(e))},t=Object.entries(n).filter(([e])=>![`deferred`,`cancelled`,`done`,`completed`].includes(e)).reduce((e,[t,n])=>e+n,0);if(t<=0)d=Q.muted(`░`.repeat(s));else{let r=0;for(let[i,a]of Object.entries(n)){if([`deferred`,`cancelled`,`done`,`completed`].includes(i))continue;let n=Math.round(a/t*s),o=Math.min(n,s-r),c=e[i]||(e=>Q.muted(`░`.repeat(e)));d+=c(o),r+=o}r<s&&(d+=Q.muted(`░`.repeat(s-r)))}}else d=Q.muted(`░`.repeat(s));let f=e===100?V.green:r===100?Q.muted:c;return`${l}${u}${d} ${f(`${r.toFixed(0)}%`)}`}function ws(e,t=!1){if(!e)return Q.muted(`? unknown`);let n={done:{color:V.green,icon:`✓`,tableIcon:`✓`},completed:{color:V.green,icon:`✓`,tableIcon:`✓`},pending:{color:V.yellow,icon:`○`,tableIcon:`⏱`},"in-progress":{color:Q.active,icon:`▶`,tableIcon:`▶`},deferred:{color:Q.muted,icon:`x`,tableIcon:`⏱`},blocked:{color:V.red,icon:`!`,tableIcon:`✗`},review:{color:V.magenta,icon:`?`,tableIcon:`?`},cancelled:{color:Q.muted,icon:`x`,tableIcon:`x`}}[e.toLowerCase()]||{color:V.red,icon:`✗`,tableIcon:`✗`};if(t){let t={done:`✓`,completed:`✓`,pending:`○`,"in-progress":`►`,deferred:`x`,blocked:`!`,review:`?`}[e.toLowerCase()]||`x`;return n.color(`${t} ${e}`)}return n.color(`${n.icon} ${e}`)}function Ts(e,t,n=!1,r=null){return!e||!Array.isArray(e)||e.length===0?n?Q.muted(`None`):`None`:e.map(e=>{let i=e.toString();if(i.includes(`.`)){let a=i.split(`.`);if(a.length!==2||!a[0]||!a[1]){let a=O(t,typeof e==`string`?parseInt(e,10):e,r).task;if(!a)return n?V.red(`${i} (Not found)`):`${i} (Not found)`;let o=a.status||`pending`,s=o.toLowerCase()===`done`||o.toLowerCase()===`completed`,c=o.toLowerCase()===`in-progress`;return n?s?V.green.bold(i):c?V.yellow.bold(i):V.red.bold(i):i}let[o,s]=a.map(e=>parseInt(e,10)),c=t.find(e=>e.id===o);if(!c||!c.subtasks)return n?V.red(`${i} (Not found)`):`${i} (Not found)`;let l=c.subtasks.find(e=>e.id===s);if(!l)return n?V.red(`${i} (Not found)`):`${i} (Not found)`;let u=l.status||`pending`,d=u.toLowerCase()===`done`||u.toLowerCase()===`completed`,f=u.toLowerCase()===`in-progress`;return n?d?V.green.bold(i):f?Q.active.bold(i):V.red.bold(i):i}let a=O(t,typeof e==`string`?parseInt(e,10):e,r).task;if(!a)return n?V.red(`${i} (Not found)`):`${i} (Not found)`;let o=a.status||`pending`,s=o.toLowerCase()===`done`||o.toLowerCase()===`completed`,c=o.toLowerCase()===`in-progress`;return n?s?V.green.bold(i):c?V.yellow.bold(i):V.red.bold(i):i}).join(`, `)}function Es(){let e=process.stdout.columns||100;console.log(G(V.bold(`TaskGraph CLI`),{padding:1,borderColor:ms,borderStyle:`round`,margin:{top:1,bottom:1}})),[{title:`Project Setup & Configuration`,color:`blue`,commands:[{name:`init`,args:`[--name=<name>] [--description=<desc>] [-y]`,desc:`Initialize a new project with TaskGraph structure`},{name:`models`,args:``,desc:`View current AI model configuration and available models`},{name:`models --setup`,args:``,desc:`Run interactive setup to configure AI models`},{name:`models --set-main`,args:`<model_id>`,desc:`Set the primary model for task generation`},{name:`models --set-research`,args:`<model_id>`,desc:`Set the model for research operations`},{name:`models --set-fallback`,args:`<model_id>`,desc:`Set the fallback model (optional)`}]},{title:`Task Generation`,color:`cyan`,commands:[{name:`parse-prd`,args:`--input=<file.txt> [--num-tasks=10]`,desc:`Generate tasks from a PRD document`},{name:`generate`,args:``,desc:`Create individual task files from tasks.json`}]},{title:`Task Management`,color:`green`,commands:[{name:`list`,args:`[<status>|all] [-s <status>] [-t <tag>]`,desc:`List all tasks - use "all" to show with subtasks`},{name:`list`,args:`[--with-subtasks] [-f <format>] [--json] [-c]`,desc:`Options: format (text/json/compact), subtasks`},{name:`list`,args:`[-w] [--ready] [--blocking] [--all-tags]`,desc:`Options: watch mode, ready/blocking filters, all tags`},{name:`set-status`,args:`<id> <status>`,desc:`Update task status (${Br.join(`, `)})`},{name:`sync-readme`,args:`[--with-subtasks] [--status=<status>]`,desc:`Export tasks to README.md with professional formatting`},{name:`update`,args:`--from=<id> --prompt="<context>"`,desc:`Update multiple tasks based on new requirements`},{name:`update-task`,args:`<id> <prompt...>`,desc:`Update a single task (no quotes needed for multi-word prompts)`},{name:`update-subtask`,args:`--id=<parentId.subtaskId> --prompt="<context>"`,desc:`Append additional information to a subtask`},{name:`add-task`,args:`--prompt="<text>" [--dependencies=<ids>] [--priority=<priority>]`,desc:`Add a new task using AI`},{name:`remove-task`,args:`--id=<id> [-y]`,desc:`Permanently remove a task or subtask`}]},{title:`Subtask Management`,color:`yellow`,commands:[{name:`add-subtask`,args:`--parent=<id> --title="<title>" [--description="<desc>"]`,desc:`Add a new subtask to a parent task`},{name:`add-subtask`,args:`--parent=<id> --task-id=<id>`,desc:`Convert an existing task into a subtask`},{name:`remove-subtask`,args:`--id=<parentId.subtaskId> [--convert]`,desc:`Remove a subtask (optionally convert to standalone task)`},{name:`clear-subtasks`,args:`--id=<id>`,desc:`Remove all subtasks from specified tasks`},{name:`clear-subtasks --all`,args:``,desc:`Remove subtasks from all tasks`}]},{title:`Task Analysis & Breakdown`,color:`magenta`,commands:[{name:`analyze-complexity`,args:`[--research] [--threshold=5]`,desc:`Analyze tasks and generate expansion recommendations`},{name:`complexity-report`,args:`[--file=<path>]`,desc:`Display the complexity analysis report`},{name:`expand`,args:`--id=<id> [--num=5] [--research] [--prompt="<context>"]`,desc:`Break down tasks into detailed subtasks`},{name:`expand --all`,args:`[--force] [--research]`,desc:`Expand all pending tasks with subtasks`},{name:`research`,args:`"<prompt>" [-i=<task_ids>] [-f=<file_paths>] [-c="<context>"] [--tree] [-s=<save_file>] [-d=<detail_level>]`,desc:`Perform AI-powered research queries with project context`}]},{title:`Task Navigation & Viewing`,color:`cyan`,commands:[{name:`next`,args:``,desc:`Show the next task to work on based on dependencies`},{name:`show`,args:`<id>`,desc:`Display detailed information about a specific task`}]},{title:`Tag Management`,color:`magenta`,commands:[{name:`tags`,args:`[list] [--show-metadata] [--ready]`,desc:`List all available tags with task counts`},{name:`tags add`,args:`<name> [--description <desc>] [--copy-from <tag>]`,desc:`Create a new tag (--from-branch for git branch name)`},{name:`tags use`,args:`<name>`,desc:`Switch to a different tag context`},{name:`tags remove`,args:`<name> [-y]`,desc:`Delete an existing tag and all its tasks`},{name:`tags rename`,args:`<oldName> <newName>`,desc:`Rename an existing tag`},{name:`tags copy`,args:`<source> <target> [--description <desc>]`,desc:`Copy a tag with all its tasks`}]},{title:`Dependency Management`,color:`blue`,commands:[{name:`add-dependency`,args:`--id=<id> --depends-on=<id>`,desc:`Add a dependency to a task`},{name:`remove-dependency`,args:`--id=<id> --depends-on=<id>`,desc:`Remove a dependency from a task`},{name:`validate-dependencies`,args:``,desc:`Identify invalid dependencies without fixing them`},{name:`fix-dependencies`,args:``,desc:`Fix invalid dependencies automatically`}]}].forEach(t=>{console.log(G(V[t.color].bold(t.title),{padding:{left:2,right:2,top:0,bottom:0},margin:{top:1,bottom:0},borderColor:t.color,borderStyle:`round`}));let n=Math.max(25,Math.floor(e*.2)),r=Math.max(40,Math.floor(e*.35)),i=Math.max(45,Math.floor(e*.45)-10),a=new q({colWidths:[n,r,i],chars:{top:``,"top-mid":``,"top-left":``,"top-right":``,bottom:``,"bottom-mid":``,"bottom-left":``,"bottom-right":``,left:``,"left-mid":``,mid:``,"mid-mid":``,right:``,"right-mid":``,middle:` `},style:{border:[],"padding-left":4},wordWrap:!0});t.commands.forEach((e,t)=>{a.push([`${V.yellow.bold(e.name)}${V.reset(``)}`,`${V.reset(e.args)}${V.reset(``)}`,`${V.dim(e.desc)}${V.reset(``)}`])}),console.log(a.toString()),console.log(``)}),console.log(G(V.cyan.bold(`Configuration`),{padding:{left:2,right:2,top:0,bottom:0},margin:{top:1,bottom:0},borderColor:`cyan`,borderStyle:`round`}));let t=e||process.stdout.columns||100,n=Math.max(30,Math.floor(t*.25)),r=Math.max(50,Math.floor(t*.45)),i=Math.max(30,Math.floor(t*.3)-10),a=new q({colWidths:[n,r,i],chars:{top:``,"top-mid":``,"top-left":``,"top-right":``,bottom:``,"bottom-mid":``,"bottom-left":``,"bottom-right":``,left:``,"left-mid":``,mid:``,"mid-mid":``,right:``,"right-mid":``,middle:` `},style:{border:[],"padding-left":4},wordWrap:!0});a.push([`${V.yellow(E)}${V.reset(``)}`,`${V.reset(`AI model configuration file (project root)`)}${V.reset(``)}`,`${V.dim(`Managed by models cmd`)}${V.reset(``)}`],[`${V.yellow(`Claude Code`)}${V.reset(``)}`,`${V.reset(`Install and sign in to Claude Code (no API keys needed)`)}${V.reset(``)}`,`${V.dim(`Required on PATH`)}${V.reset(``)}`]),console.log(a.toString()),console.log(``),console.log(G(V.bold(`Quick Start:`)+`
|
|
921
|
+
`)+B.text(`• This approach maintains a clear record of completed work and new requirements`),{padding:1,borderColor:N,borderStyle:`round`,margin:{top:1,bottom:1}}))}let{systemPrompt:h,userPrompt:g}=await Oi().loadPrompt(`update-tasks`,{tasks:p,updatePrompt:n,useResearch:r,projectContext:m,hasCodebaseAnalysis:ee(r,a,s),projectRoot:a}),_=null,v=null;!f&&o===`text`&&(_=Ms(`Updating tasks with AI...
|
|
922
|
+
`));try{v=await i({role:r?`research`:`main`,session:s,projectRoot:a,systemPrompt:h,prompt:g,schema:gi[`update-tasks`],objectName:`tasks`,commandName:`update-tasks`,outputType:f?`mcp`:`cli`}),_&&$(_,`AI update complete.`);let t=v.mainResult.tasks.map(e=>({...e,dependencies:e.dependencies??[],priority:e.priority??null,details:e.details??null,testStrategy:e.testStrategy??null,subtasks:e.subtasks?e.subtasks.map(e=>({...e,dependencies:e.dependencies??[],status:e.status??`pending`,testStrategy:e.testStrategy??null})):null}));if(!Array.isArray(t))throw Error(`Parsed AI response for updated tasks was not an array.`);f?d.info(`Received ${t.length} updated tasks from AI.`):d(`info`,`Received ${t.length} updated tasks from AI.`);let n=new Map(t.map(e=>[e.id,e])),l=0;return c.tasks.forEach((e,t)=>{if(n.has(e.id)){let r=n.get(e.id);c.tasks[t]={...e,...r,subtasks:r.subtasks===void 0?e.subtasks:r.subtasks},l++}}),f?d.info(`Applied updates to ${l} tasks in the dataset.`):d(`info`,`Applied updates to ${l} tasks in the dataset.`),F(e,c,a,u),f?d.info(`Successfully updated ${l} tasks in ${e}`):d(`success`,`Successfully updated ${l} tasks in ${e}`),o===`text`&&v.telemetryData&&Ks(v.telemetryData,`cli`),{success:!0,updatedTasks:t,telemetryData:v.telemetryData,tagInfo:v.tagInfo}}catch(e){throw _&&$(_),f?d.error(`Error during AI service call: ${e.message}`):d(`error`,`Error during AI service call: ${e.message}`),e.message.includes(`API key`)&&(f?d.error(`Please ensure API keys are configured correctly in .env or mcp.json.`):d(`error`,`Please ensure API keys are configured correctly in .env or mcp.json.`)),e}finally{_&&$(_)}}catch(e){if(f?d.error(`Error updating tasks: ${e.message}`):d(`error`,`Error updating tasks: ${e.message}`),o===`text`)console.error(V.red(`Error: ${e.message}`)),L(s)&&console.error(e),process.exit(1);else throw e}}const{theme:Q,BORDER_COLOR:Es,TABLE_BORDER:Ds}=Cn,Os=Ie(he);function ks(e){!z()&&e&&e._migrationHappened&&console.log(G(V.bold(`FYI: `)+Q.muted(`TaskGraph now supports separate task lists per tag. `)+V.cyan(`Use the --tag flag to create/read/update/filter tasks by tag.`),{padding:{top:0,bottom:0,left:2,right:2},borderColor:`cyan`,borderStyle:`round`,margin:{top:1,bottom:1}}))}async function As(e,t={}){if(z())return;let{skipIfMaster:n=!1,dim:r=!1}=t;if(n&&e===`master`)return;let i=r?Q.muted(`[tag] ${e}`):V.dim(`[tag] `)+V.cyan(e);console.log(i)}function js(){z()||st({version:$r(),projectName:me(null)})}function Ms(e){return z()?null:mn(e).start()}function $(e){e&&typeof e.stop==`function`&&e.stop()}function Ns(e,t=null){e&&typeof e.succeed==`function`&&(t?e.succeed(t):e.succeed())}function Ps(e,t=null){e&&typeof e.fail==`function`&&(t?e.fail(t):e.fail())}function Fs(e,t=30,n=null){let r=n?Math.min(100,e+(n.deferred||0)+(n.cancelled||0)):e,i=Math.round(e*t/100),a=Math.round(r*t/100),o=a-i,s=t-a,c;c=e<25?V.red:e<50||e<75?V.yellow:V.green;let l=c(`█`.repeat(i)),u=Q.muted(`─`.repeat(o)),d=``;if(n&&s>0){let e={pending:e=>V.yellow(`░`.repeat(e)),"in-progress":e=>Q.active(`▓`.repeat(e)),blocked:e=>V.red(`!`.repeat(e)),review:e=>V.magenta(`▒`.repeat(e))},t=Object.entries(n).filter(([e])=>![`deferred`,`cancelled`,`done`,`completed`].includes(e)).reduce((e,[t,n])=>e+n,0);if(t<=0)d=Q.muted(`░`.repeat(s));else{let r=0;for(let[i,a]of Object.entries(n)){if([`deferred`,`cancelled`,`done`,`completed`].includes(i))continue;let n=Math.round(a/t*s),o=Math.min(n,s-r),c=e[i]||(e=>Q.muted(`░`.repeat(e)));d+=c(o),r+=o}r<s&&(d+=Q.muted(`░`.repeat(s-r)))}}else d=Q.muted(`░`.repeat(s));let f=e===100?V.green:r===100?Q.muted:c;return`${l}${u}${d} ${f(`${r.toFixed(0)}%`)}`}function Is(e,t=!1){if(!e)return Q.muted(`? unknown`);let n={done:{color:V.green,icon:`✓`,tableIcon:`✓`},completed:{color:V.green,icon:`✓`,tableIcon:`✓`},pending:{color:V.yellow,icon:`○`,tableIcon:`⏱`},"in-progress":{color:Q.active,icon:`▶`,tableIcon:`▶`},deferred:{color:Q.muted,icon:`x`,tableIcon:`⏱`},blocked:{color:V.red,icon:`!`,tableIcon:`✗`},review:{color:V.magenta,icon:`?`,tableIcon:`?`},cancelled:{color:Q.muted,icon:`x`,tableIcon:`x`}}[e.toLowerCase()]||{color:V.red,icon:`✗`,tableIcon:`✗`};if(t){let t={done:`✓`,completed:`✓`,pending:`○`,"in-progress":`►`,deferred:`x`,blocked:`!`,review:`?`}[e.toLowerCase()]||`x`;return n.color(`${t} ${e}`)}return n.color(`${n.icon} ${e}`)}function Ls(e,t,n=!1,r=null){return!e||!Array.isArray(e)||e.length===0?n?Q.muted(`None`):`None`:e.map(e=>{let i=e.toString();if(i.includes(`.`)){let a=i.split(`.`);if(a.length!==2||!a[0]||!a[1]){let a=O(t,typeof e==`string`?parseInt(e,10):e,r).task;if(!a)return n?V.red(`${i} (Not found)`):`${i} (Not found)`;let o=a.status||`pending`,s=o.toLowerCase()===`done`||o.toLowerCase()===`completed`,c=o.toLowerCase()===`in-progress`;return n?s?V.green.bold(i):c?V.yellow.bold(i):V.red.bold(i):i}let[o,s]=a.map(e=>parseInt(e,10)),c=t.find(e=>e.id===o);if(!c||!c.subtasks)return n?V.red(`${i} (Not found)`):`${i} (Not found)`;let l=c.subtasks.find(e=>e.id===s);if(!l)return n?V.red(`${i} (Not found)`):`${i} (Not found)`;let u=l.status||`pending`,d=u.toLowerCase()===`done`||u.toLowerCase()===`completed`,f=u.toLowerCase()===`in-progress`;return n?d?V.green.bold(i):f?Q.active.bold(i):V.red.bold(i):i}let a=O(t,typeof e==`string`?parseInt(e,10):e,r).task;if(!a)return n?V.red(`${i} (Not found)`):`${i} (Not found)`;let o=a.status||`pending`,s=o.toLowerCase()===`done`||o.toLowerCase()===`completed`,c=o.toLowerCase()===`in-progress`;return n?s?V.green.bold(i):c?V.yellow.bold(i):V.red.bold(i):i}).join(`, `)}function Rs(){let e=process.stdout.columns||100;console.log(G(V.bold(`TaskGraph CLI`),{padding:1,borderColor:Es,borderStyle:`round`,margin:{top:1,bottom:1}})),[{title:`Project Setup & Configuration`,color:`blue`,commands:[{name:`init`,args:`[--name=<name>] [--description=<desc>] [-y]`,desc:`Initialize a new project with TaskGraph structure`},{name:`models`,args:``,desc:`View current AI model configuration and available models`},{name:`models --setup`,args:``,desc:`Run interactive setup to configure AI models`},{name:`models --set-main`,args:`<model_id>`,desc:`Set the primary model for task generation`},{name:`models --set-research`,args:`<model_id>`,desc:`Set the model for research operations`},{name:`models --set-fallback`,args:`<model_id>`,desc:`Set the fallback model (optional)`}]},{title:`Task Generation`,color:`cyan`,commands:[{name:`parse-prd`,args:`--input=<file.txt> [--num-tasks=10]`,desc:`Generate tasks from a PRD document`},{name:`generate`,args:``,desc:`Create individual task files from tasks.json`}]},{title:`Task Management`,color:`green`,commands:[{name:`list`,args:`[<status>|all] [-s <status>] [-t <tag>]`,desc:`List all tasks - use "all" to show with subtasks`},{name:`list`,args:`[--with-subtasks] [-f <format>] [--json] [-c]`,desc:`Options: format (text/json/compact), subtasks`},{name:`list`,args:`[-w] [--ready] [--blocking] [--all-tags]`,desc:`Options: watch mode, ready/blocking filters, all tags`},{name:`set-status`,args:`<id> <status>`,desc:`Update task status (${Zr.join(`, `)})`},{name:`sync-readme`,args:`[--with-subtasks] [--status=<status>]`,desc:`Export tasks to README.md with professional formatting`},{name:`update`,args:`--from=<id> --prompt="<context>"`,desc:`Update multiple tasks based on new requirements`},{name:`update-task`,args:`<id> <prompt...>`,desc:`Update a single task (no quotes needed for multi-word prompts)`},{name:`update-subtask`,args:`--id=<parentId.subtaskId> --prompt="<context>"`,desc:`Append additional information to a subtask`},{name:`add-task`,args:`--prompt="<text>" [--dependencies=<ids>] [--priority=<priority>]`,desc:`Add a new task using AI`},{name:`remove-task`,args:`--id=<id> [-y]`,desc:`Permanently remove a task or subtask`}]},{title:`Subtask Management`,color:`yellow`,commands:[{name:`add-subtask`,args:`--parent=<id> --title="<title>" [--description="<desc>"]`,desc:`Add a new subtask to a parent task`},{name:`add-subtask`,args:`--parent=<id> --task-id=<id>`,desc:`Convert an existing task into a subtask`},{name:`remove-subtask`,args:`--id=<parentId.subtaskId> [--convert]`,desc:`Remove a subtask (optionally convert to standalone task)`},{name:`clear-subtasks`,args:`--id=<id>`,desc:`Remove all subtasks from specified tasks`},{name:`clear-subtasks --all`,args:``,desc:`Remove subtasks from all tasks`}]},{title:`Task Analysis & Breakdown`,color:`magenta`,commands:[{name:`analyze-complexity`,args:`[--research] [--threshold=5]`,desc:`Analyze tasks and generate expansion recommendations`},{name:`complexity-report`,args:`[--file=<path>]`,desc:`Display the complexity analysis report`},{name:`expand`,args:`--id=<id> [--num=5] [--research] [--prompt="<context>"]`,desc:`Break down tasks into detailed subtasks`},{name:`expand --all`,args:`[--force] [--research]`,desc:`Expand all pending tasks with subtasks`},{name:`research`,args:`"<prompt>" [-i=<task_ids>] [-f=<file_paths>] [-c="<context>"] [--tree] [-s=<save_file>] [-d=<detail_level>]`,desc:`Perform AI-powered research queries with project context`}]},{title:`Task Navigation & Viewing`,color:`cyan`,commands:[{name:`next`,args:``,desc:`Show the next task to work on based on dependencies`},{name:`graph`,args:`[--id=<id>]`,desc:`Show tasks as a dependency tree, with the next task marked`},{name:`show`,args:`<id>`,desc:`Display detailed information about a specific task`}]},{title:`Tag Management`,color:`magenta`,commands:[{name:`tags`,args:`[list] [--show-metadata] [--ready]`,desc:`List all available tags with task counts`},{name:`tags add`,args:`<name> [--description <desc>] [--copy-from <tag>]`,desc:`Create a new tag (--from-branch for git branch name)`},{name:`tags use`,args:`<name>`,desc:`Switch to a different tag context`},{name:`tags remove`,args:`<name> [-y]`,desc:`Delete an existing tag and all its tasks`},{name:`tags rename`,args:`<oldName> <newName>`,desc:`Rename an existing tag`},{name:`tags copy`,args:`<source> <target> [--description <desc>]`,desc:`Copy a tag with all its tasks`}]},{title:`Dependency Management`,color:`blue`,commands:[{name:`add-dependency`,args:`--id=<id> --depends-on=<id>`,desc:`Add a dependency to a task`},{name:`remove-dependency`,args:`--id=<id> --depends-on=<id>`,desc:`Remove a dependency from a task`},{name:`validate-dependencies`,args:``,desc:`Identify invalid dependencies without fixing them`},{name:`fix-dependencies`,args:``,desc:`Fix invalid dependencies automatically`}]}].forEach(t=>{console.log(G(V[t.color].bold(t.title),{padding:{left:2,right:2,top:0,bottom:0},margin:{top:1,bottom:0},borderColor:t.color,borderStyle:`round`}));let n=Math.max(25,Math.floor(e*.2)),r=Math.max(40,Math.floor(e*.35)),i=Math.max(45,Math.floor(e*.45)-10),a=new q({colWidths:[n,r,i],chars:{top:``,"top-mid":``,"top-left":``,"top-right":``,bottom:``,"bottom-mid":``,"bottom-left":``,"bottom-right":``,left:``,"left-mid":``,mid:``,"mid-mid":``,right:``,"right-mid":``,middle:` `},style:{border:[],"padding-left":4},wordWrap:!0});t.commands.forEach((e,t)=>{a.push([`${V.yellow.bold(e.name)}${V.reset(``)}`,`${V.reset(e.args)}${V.reset(``)}`,`${V.dim(e.desc)}${V.reset(``)}`])}),console.log(a.toString()),console.log(``)}),console.log(G(V.cyan.bold(`Configuration`),{padding:{left:2,right:2,top:0,bottom:0},margin:{top:1,bottom:0},borderColor:`cyan`,borderStyle:`round`}));let t=e||process.stdout.columns||100,n=Math.max(30,Math.floor(t*.25)),r=Math.max(50,Math.floor(t*.45)),i=Math.max(30,Math.floor(t*.3)-10),a=new q({colWidths:[n,r,i],chars:{top:``,"top-mid":``,"top-left":``,"top-right":``,bottom:``,"bottom-mid":``,"bottom-left":``,"bottom-right":``,left:``,"left-mid":``,mid:``,"mid-mid":``,right:``,"right-mid":``,middle:` `},style:{border:[],"padding-left":4},wordWrap:!0});a.push([`${V.yellow(E)}${V.reset(``)}`,`${V.reset(`AI model configuration file (project root)`)}${V.reset(``)}`,`${V.dim(`Managed by models cmd`)}${V.reset(``)}`],[`${V.yellow(`Claude Code`)}${V.reset(``)}`,`${V.reset(`Install and sign in to Claude Code (no API keys needed)`)}${V.reset(``)}`,`${V.dim(`Required on PATH`)}${V.reset(``)}`]),console.log(a.toString()),console.log(``),console.log(G(V.bold(`Quick Start:`)+`
|
|
913
923
|
|
|
914
924
|
`+V.cyan(`1. Create Project: `)+V.reset(`taskgraph init`)+`
|
|
915
925
|
`+V.cyan(`2. Setup Models: `)+V.reset(`taskgraph models --setup`)+`
|
|
916
926
|
`+V.cyan(`3. Parse PRD: `)+V.reset(`taskgraph parse-prd --input=<prd-file>`)+`
|
|
917
927
|
`+V.cyan(`4. List Tasks: `)+V.reset(`taskgraph list`)+`
|
|
918
|
-
`+V.cyan(`5. Find Next Task: `)+V.reset(`taskgraph next`),{padding:1,borderColor:`yellow`,borderStyle:`round`,margin:{top:1},width:Math.min(t-10,100)}))}function
|
|
928
|
+
`+V.cyan(`5. Find Next Task: `)+V.reset(`taskgraph next`),{padding:1,borderColor:`yellow`,borderStyle:`round`,margin:{top:1},width:Math.min(t-10,100)}))}function zs(e){return e<=3?V.green(`● ${e}`):e<=6?V.yellow(`● ${e}`):V.red(`● ${e}`)}async function Bs(e){if(!W.existsSync(e)){console.log(G(V.yellow(`No complexity report found at ${e}\n\n`)+`Would you like to generate one now?`,{padding:1,borderColor:`yellow`,borderStyle:`round`,margin:{top:1}}));let t=Pe.createInterface({input:process.stdin,output:process.stdout}),n=await new Promise(e=>{t.question(V.cyan(`Generate complexity report? (y/n): `),e)});if(t.close(),n.toLowerCase()===`y`||n.toLowerCase()===`yes`){console.log(V.cyan(`Generating complexity report...`));let t=j;return W.existsSync(t)?(await Li({output:e,research:!1,file:t}),Bs(e)):(console.error(`✗ No tasks.json file found. Please run "taskgraph init" or create a tasks.json file.`),null)}console.log(V.yellow(`Report generation cancelled.`));return}let t;try{t=JSON.parse(W.readFileSync(e,`utf8`))}catch(e){I(`error`,`Error reading complexity report: ${e.message}`);return}console.log(G(V.bold(`Task Complexity Analysis Report`),{padding:1,borderColor:Es,borderStyle:`round`,margin:{top:1,bottom:1}}));let n=new q({style:{head:[],border:[],"padding-top":0,"padding-bottom":0,compact:!0},chars:{mid:``,"left-mid":``,"mid-mid":``,"right-mid":``},colWidths:[20,50]});n.push([V.cyan.bold(`Generated:`),new Date(t.meta.generatedAt).toLocaleString()],[V.cyan.bold(`Tasks Analyzed:`),t.meta.tasksAnalyzed],[V.cyan.bold(`Threshold Score:`),t.meta.thresholdScore],[V.cyan.bold(`Project:`),t.meta.projectName],[V.cyan.bold(`Research-backed:`),t.meta.usedResearch?`Yes`:`No`]),console.log(n.toString());let r=[...t.complexityAnalysis].sort((e,t)=>t.complexityScore-e.complexityScore),i=r.filter(e=>e.complexityScore>=t.meta.thresholdScore),a=r.filter(e=>e.complexityScore<t.meta.thresholdScore),o=[0,0,0];r.forEach(e=>{e.complexityScore<5?o[0]++:e.complexityScore<8?o[1]++:o[2]++});let s=Math.round(o[0]/r.length*100),c=Math.round(o[1]/r.length*100),l=Math.round(o[2]/r.length*100);console.log(G(V.bold(`Complexity Distribution
|
|
919
929
|
|
|
920
|
-
`)+`${V.green.bold(`Low (1-4):`)} ${o[0]} tasks (${s}%)\n${V.yellow.bold(`Medium (5-7):`)} ${o[1]} tasks (${c}%)\n${V.red.bold(`High (8-10):`)} ${o[2]} tasks (${l}%)`,{padding:1,borderColor:`cyan`,borderStyle:`round`,margin:{top:1,bottom:1}}));let u=process.stdout.columns||100,d=Math.floor(u*.25),f=u-12-d-8-8-10,p=new q({head:[V.yellow.bold(`ID`),V.yellow.bold(`Title`),V.yellow.bold(`Score`),V.yellow.bold(`Subtasks`),V.yellow.bold(`Expansion Command`)],colWidths:[12,d,8,8,f],style:{head:[],border:[]},wordWrap:!0,wrapOnWordBoundary:!0});if(i.forEach(e=>{let t=`taskgraph expand --id=${e.taskId} --num=${e.recommendedSubtasks}${e.expansionPrompt?` --prompt="${e.expansionPrompt}"`:``}`;p.push([e.taskId,R(e.taskTitle,d-3),
|
|
930
|
+
`)+`${V.green.bold(`Low (1-4):`)} ${o[0]} tasks (${s}%)\n${V.yellow.bold(`Medium (5-7):`)} ${o[1]} tasks (${c}%)\n${V.red.bold(`High (8-10):`)} ${o[2]} tasks (${l}%)`,{padding:1,borderColor:`cyan`,borderStyle:`round`,margin:{top:1,bottom:1}}));let u=process.stdout.columns||100,d=Math.floor(u*.25),f=u-12-d-8-8-10,p=new q({head:[V.yellow.bold(`ID`),V.yellow.bold(`Title`),V.yellow.bold(`Score`),V.yellow.bold(`Subtasks`),V.yellow.bold(`Expansion Command`)],colWidths:[12,d,8,8,f],style:{head:[],border:[]},wordWrap:!0,wrapOnWordBoundary:!0});if(i.forEach(e=>{let t=`taskgraph expand --id=${e.taskId} --num=${e.recommendedSubtasks}${e.expansionPrompt?` --prompt="${e.expansionPrompt}"`:``}`;p.push([e.taskId,R(e.taskTitle,d-3),zs(e.complexityScore),e.recommendedSubtasks,V.cyan(t)])}),console.log(p.toString()),a.length>0){console.log(G(V.green.bold(`Simple Tasks (${a.length})`),{padding:{left:2,right:2,top:0,bottom:0},margin:{top:1,bottom:0},borderColor:`green`,borderStyle:`round`}));let e=new q({head:[V.green.bold(`ID`),V.green.bold(`Title`),V.green.bold(`Score`),V.green.bold(`Reasoning`)],colWidths:[5,40,8,50],style:{head:[],border:[]}});a.forEach(t=>{e.push([t.taskId,R(t.taskTitle,37),zs(t.complexityScore),R(t.reasoning,47)])}),console.log(e.toString())}console.log(G(V.bold(`Suggested Actions:`)+`
|
|
921
931
|
|
|
922
|
-
${V.cyan(`1.`)} Expand all complex tasks: ${V.yellow(`taskgraph expand --all`)}\n${V.cyan(`2.`)} Expand a specific task: ${V.yellow(`taskgraph expand --id=<id>`)}\n${V.cyan(`3.`)} Regenerate with research: ${V.yellow(`taskgraph analyze-complexity --research`)}`,{padding:1,borderColor:`cyan`,borderStyle:`round`,margin:{top:1}}))}async function
|
|
923
|
-
`)+V.yellow(`Executing this command will overwrite any existing tasks.`),{padding:1,borderColor:`yellow`,borderStyle:`round`,margin:{top:1}}));let t=Pe.createInterface({input:process.stdin,output:process.stdout}),n=await new Promise(e=>{t.question(V.cyan(`Are you sure you wish to continue? (y/N): `),e)});return t.close(),n.toLowerCase()===`y`||n.toLowerCase()===`yes`}const
|
|
924
|
-
Active Model Configuration:`));let n=e.activeModels,r=new q({head:[`Role`,`Provider`,`Model ID`,`SWE Score`,`Cost ($/1M tkns)`].map(e=>V.cyan.bold(e)),colWidths:[10,14,30,18,20],style:{head:[`cyan`,`bold`],border:
|
|
932
|
+
${V.cyan(`1.`)} Expand all complex tasks: ${V.yellow(`taskgraph expand --all`)}\n${V.cyan(`2.`)} Expand a specific task: ${V.yellow(`taskgraph expand --id=<id>`)}\n${V.cyan(`3.`)} Regenerate with research: ${V.yellow(`taskgraph analyze-complexity --research`)}`,{padding:1,borderColor:`cyan`,borderStyle:`round`,margin:{top:1}}))}async function Vs(e){console.log(G(V.yellow(`It looks like you've already generated tasks for this project.
|
|
933
|
+
`)+V.yellow(`Executing this command will overwrite any existing tasks.`),{padding:1,borderColor:`yellow`,borderStyle:`round`,margin:{top:1}}));let t=Pe.createInterface({input:process.stdin,output:process.stdout}),n=await new Promise(e=>{t.question(V.cyan(`Are you sure you wish to continue? (y/N): `),e)});return t.close(),n.toLowerCase()===`y`||n.toLowerCase()===`yes`}const Hs=(e,t)=>{if(e==null||e<=0)return`N/A`;let n=`${(e*100).toFixed(1)}%`,r=[...t.map(e=>e.sweScore).filter(e=>e!=null&&e>0)].sort((e,t)=>t-e),i=r.length,a=Q.muted(`☆☆☆`);if(i>0){let t=Math.max(0,Math.floor(i/3)-1),n=Math.max(0,Math.floor(2*i/3)-1);a=e>=r[t]?V.yellow(`★★★`):e>=r[n]?V.yellow(`★★`)+Q.muted(`☆`):V.yellow(`★`)+Q.muted(`☆☆`)}return`${n} ${a}`},Us=e=>{if(!e)return`N/A`;if(e.input===0&&e.output===0)return V.green(`Free`);let t=e=>{if(e==null)return`N/A`;let t=Number.isInteger(e);return`$${e.toFixed(t?0:2)}`};return`${t(e.input)} in, ${t(e.output)} out`};function Ws(e,t=[]){console.log(V.cyan.bold(`
|
|
934
|
+
Active Model Configuration:`));let n=e.activeModels,r=new q({head:[`Role`,`Provider`,`Model ID`,`SWE Score`,`Cost ($/1M tkns)`].map(e=>V.cyan.bold(e)),colWidths:[10,14,30,18,20],style:{head:[`cyan`,`bold`],border:Ds}});r.push([V.reset(`Main`),n.main.provider,n.main.modelId,Hs(n.main.sweScore,t),Us(n.main.cost)]),r.push([V.reset(`Research`),n.research.provider,n.research.modelId,Hs(n.research.sweScore,t),Us(n.research.cost)]),n.fallback&&n.fallback.provider&&n.fallback.modelId?r.push([V.reset(`Fallback`),n.fallback.provider,n.fallback.modelId,Hs(n.fallback.sweScore,t),Us(n.fallback.cost)]):r.push([V.reset(`Fallback`),Q.muted(`-`),Q.muted(`(Not Set)`),Q.muted(`-`),Q.muted(`-`)]),console.log(r.toString())}function Gs(e){if(!e||e.length===0){console.log(Q.muted(`
|
|
925
935
|
(No other models available or all are configured)`));return}console.log(V.cyan.bold(`
|
|
926
|
-
Other Available Models:`));let t=new q({head:[`Provider`,`Model ID`,`SWE Score`,`Cost ($/1M tkns)`].map(e=>V.cyan.bold(e)),colWidths:[15,40,18,25],style:{head:[`cyan`,`bold`],border:
|
|
936
|
+
Other Available Models:`));let t=new q({head:[`Provider`,`Model ID`,`SWE Score`,`Cost ($/1M tkns)`].map(e=>V.cyan.bold(e)),colWidths:[15,40,18,25],style:{head:[`cyan`,`bold`],border:Ds}});e.forEach(n=>{t.push([n.provider,n.modelId,Hs(n.sweScore,e),Us(n.cost)])}),console.log(t.toString()),console.log(G(V.bold(`Next Steps:`)+`
|
|
927
937
|
`+V.cyan(`1. Set main model: ${V.yellow(`taskgraph models --set-main <model_id>`)}`)+`
|
|
928
938
|
`+V.cyan(`2. Set research model: ${V.yellow(`taskgraph models --set-research <model_id>`)}`)+`
|
|
929
939
|
`+V.cyan(`3. Set fallback model: ${V.yellow(`taskgraph models --set-fallback <model_id>`)}`)+`
|
|
930
|
-
`+V.cyan(`4. Run interactive setup: ${V.yellow(`taskgraph models --setup`)}`),{padding:1,borderColor:`yellow`,borderStyle:`round`,margin:{top:1}}))}function
|
|
931
|
-
`;u+=Q.muted(` Command: ${c}\n`),u+=Q.muted(` Provider: ${r}\n`),u+=Q.muted(` Model: ${n}\n`),u+=Q.muted(` Tokens: ${o} (Input: ${i}, Output: ${a})\n`);let d=l?`Unknown`:`$${s.toFixed(6)}`;u+=Q.muted(` Est. Cost: ${d}`),console.log(G(u,{padding:1,margin:{top:1},borderColor:
|
|
940
|
+
`+V.cyan(`4. Run interactive setup: ${V.yellow(`taskgraph models --setup`)}`),{padding:1,borderColor:`yellow`,borderStyle:`round`,margin:{top:1}}))}function Ks(e,t=`cli`){if(t!==`cli`&&t!==`text`||!e||z())return;let{modelUsed:n,providerName:r,inputTokens:i,outputTokens:a,totalTokens:o,totalCost:s,commandName:c,isUnknownCost:l}=e,u=Q.brand.bold(`AI Usage Summary:`)+`
|
|
941
|
+
`;u+=Q.muted(` Command: ${c}\n`),u+=Q.muted(` Provider: ${r}\n`),u+=Q.muted(` Model: ${n}\n`),u+=Q.muted(` Tokens: ${o} (Input: ${i}, Output: ${a})\n`);let d=l?`Unknown`:`$${s.toFixed(6)}`;u+=Q.muted(` Est. Cost: ${d}`),console.log(G(u,{padding:1,margin:{top:1},borderColor:Es,borderStyle:`round`,title:`Telemetry`,titleAlignment:`center`}))}function qs(e,t,n){if(z()||!e)return;let{highRelevance:r,mediumRelevance:i,recentTasks:a,allRelevantTasks:o}=e,s=V.bold(`Context Analysis`)+`
|
|
932
942
|
|
|
933
943
|
`;s+=Q.muted(`Query: `)+V.reset(`"${t}"`)+`
|
|
934
944
|
`,s+=Q.muted(`Context size: `)+V.cyan(`${n.toLocaleString()} characters`)+`
|
|
@@ -945,27 +955,27 @@ Other Available Models:`));let t=new q({head:[`Provider`,`Model ID`,`SWE Score`,
|
|
|
945
955
|
`);let c=a.filter(e=>!r.some(t=>t.id===e.id)&&!i.some(t=>t.id===e.id));c.length>0&&(s+=V.cyan.bold(`Recent tasks (for context):`)+`
|
|
946
956
|
`,c.slice(0,2).forEach(e=>{s+=V.cyan(` • Task ${e.id}: ${R(e.title,50)}`)+`
|
|
947
957
|
`}),c.length>2&&(s+=V.cyan(` • ... and ${c.length-2} more recent tasks`)+`
|
|
948
|
-
`)),console.log(G(s,{padding:{top:1,bottom:1,left:2,right:2},margin:{top:1,bottom:0},borderStyle:`round`,borderColor:
|
|
958
|
+
`)),console.log(G(s,{padding:{top:1,bottom:1,left:2,right:2},margin:{top:1,bottom:0},borderStyle:`round`,borderColor:Es,title:V.cyan(`Context gathering`),titleAlignment:`center`}))}function Js(e,t,n,r){console.log(V.red(`\n✗ Cannot move tasks from "${t}" to "${n}"`)),console.log(V.yellow(`
|
|
949
959
|
Cross-tag dependency conflicts detected:`)),e.length>0&&e.forEach(e=>{console.log(` • ${e.message}`)}),console.log(V.cyan(`
|
|
950
|
-
Resolution options:`)),console.log(` 1. Move with dependencies: taskgraph move --from=${r} --from-tag=${t} --to-tag=${n} --with-dependencies`),console.log(` 2. Break dependencies: taskgraph move --from=${r} --from-tag=${t} --to-tag=${n} --ignore-dependencies`),console.log(` 3. Validate and fix dependencies: taskgraph validate-dependencies && taskgraph fix-dependencies`),e.length>0&&console.log(` 4. Move dependencies first: taskgraph move --from=${e.map(e=>e.dependencyId).join(`,`)} --from-tag=${e[0].dependencyTag} --to-tag=${n}`)}function
|
|
960
|
+
Resolution options:`)),console.log(` 1. Move with dependencies: taskgraph move --from=${r} --from-tag=${t} --to-tag=${n} --with-dependencies`),console.log(` 2. Break dependencies: taskgraph move --from=${r} --from-tag=${t} --to-tag=${n} --ignore-dependencies`),console.log(` 3. Validate and fix dependencies: taskgraph validate-dependencies && taskgraph fix-dependencies`),e.length>0&&console.log(` 4. Move dependencies first: taskgraph move --from=${e.map(e=>e.dependencyId).join(`,`)} --from-tag=${e[0].dependencyTag} --to-tag=${n}`)}function Ys(e){return e===null?`null`:e===void 0?`undefined`:e===``?`(empty)`:se(e)||`unknown`}function Xs(e,t,n){let r=Ys(e),i=e||`unknown`,a=i;if(i.includes(`.`)){let e=i.split(`.`);e.length===2&&e[0]&&e[1]?a=e[0]:(console.log(V.yellow(`\n⚠ Warning: Unexpected taskId format "${i}". Using as-is for command suggestions.`)),a=i)}console.log(V.red(`\n✗ Cannot move subtask ${r} directly between tags`)),console.log(V.yellow(`
|
|
951
961
|
Subtask movement restriction:`)),console.log(` • Subtasks cannot be moved directly between tags`),console.log(` • They must be promoted to full tasks first`),console.log(` • Source tag: "${t}"`),console.log(` • Target tag: "${n}"`),console.log(V.cyan(`
|
|
952
|
-
Resolution options:`)),console.log(` 1. Promote subtask to full task: taskgraph remove-subtask --id=${r} --convert`),console.log(` 2. Then move the promoted task: taskgraph move --from=${a} --from-tag=${t} --to-tag=${n}`),console.log(` 3. Or move the parent task with all subtasks: taskgraph move --from=${a} --from-tag=${t} --to-tag=${n} --with-dependencies`)}function
|
|
962
|
+
Resolution options:`)),console.log(` 1. Promote subtask to full task: taskgraph remove-subtask --id=${r} --convert`),console.log(` 2. Then move the promoted task: taskgraph move --from=${a} --from-tag=${t} --to-tag=${n}`),console.log(` 3. Or move the parent task with all subtasks: taskgraph move --from=${a} --from-tag=${t} --to-tag=${n} --with-dependencies`)}function Zs(e,t,n){console.log(V.red(`
|
|
953
963
|
✗ Invalid tag combination`)),console.log(V.yellow(`
|
|
954
964
|
Error details:`)),console.log(` • Source tag: "${e}"`),console.log(` • Target tag: "${t}"`),console.log(` • Reason: ${n}`),console.log(V.cyan(`
|
|
955
|
-
Resolution options:`)),console.log(` 1. Use different tags for cross-tag moves`),console.log(` 2. Use within-tag move: taskgraph move --from=<id> --to=<id> --tag=${e}`),console.log(` 3. Check available tags: taskgraph tags`)}function
|
|
956
|
-
Helpful hints:`)),new Set(n).forEach(e=>{console.log(` ${e}`)})}var
|
|
965
|
+
Resolution options:`)),console.log(` 1. Use different tags for cross-tag moves`),console.log(` 2. Use within-tag move: taskgraph move --from=<id> --to=<id> --tag=${e}`),console.log(` 3. Check available tags: taskgraph tags`)}function Qs(e=`general`){let t={"before-move":[`Tip: Run "taskgraph validate-dependencies" to check for dependency issues before moving tasks`,`Tip: Use "taskgraph fix-dependencies" to automatically resolve common dependency problems`,`Tip: Consider using --with-dependencies flag to move dependent tasks together`],"after-error":[`Quick fix: Run "taskgraph validate-dependencies" to identify specific issues`,`Quick fix: Use "taskgraph fix-dependencies" to automatically resolve problems`,`Quick fix: Check "taskgraph show <id>" to see task dependencies before moving`],general:[`Tip: Use "taskgraph validate-dependencies" to check for dependency issues`,`Tip: Use "taskgraph fix-dependencies" to automatically resolve problems`,`Tip: Use "taskgraph show <id>" to view task dependencies`,`Tip: Use --with-dependencies flag to move dependent tasks together`]},n=t[e]||t.general;console.log(V.cyan(`
|
|
966
|
+
Helpful hints:`)),new Set(n).forEach(e=>{console.log(` ${e}`)})}var $s=class extends Error{constructor(e,t,n={}){super(t),this.name=`DependencyError`,this.code=e,this.data=n}};const ec={CANNOT_MOVE_SUBTASK:`CANNOT_MOVE_SUBTASK`,INVALID_TASK_ID:`INVALID_TASK_ID`,INVALID_SOURCE_TAG:`INVALID_SOURCE_TAG`,INVALID_TARGET_TAG:`INVALID_TARGET_TAG`};async function tc(e,t,n,r={}){I(`info`,`Adding dependency ${n} to task ${t}...`);let i=P(e,r.projectRoot,r.tag);(!i||!i.tasks)&&(I(`error`,`No valid tasks found in tasks.json`),process.exit(1));let a=typeof t==`string`&&t.includes(`.`)?t:parseInt(t,10),o=se(n);fe(i.tasks,o)||(I(`error`,`Dependency target ${o} does not exist in tasks.json`),process.exit(1));let s=null;if(typeof a==`string`&&a.includes(`.`)){let[e,t]=a.split(`.`).map(e=>parseInt(e,10)),n=i.tasks.find(t=>t.id===e);n||(I(`error`,`Parent task ${e} not found.`),process.exit(1)),n.subtasks||(I(`error`,`Parent task ${e} has no subtasks.`),process.exit(1)),s=n.subtasks.find(e=>e.id===t),s||(I(`error`,`Subtask ${a} not found.`),process.exit(1))}else s=i.tasks.find(e=>e.id===a),s||(I(`error`,`Task ${a} not found.`),process.exit(1));if(s.dependencies||(s.dependencies=[]),s.dependencies.some(e=>String(e)===String(o))){I(`warn`,`Dependency ${o} already exists in task ${a}.`);return}String(a)===String(o)&&(I(`error`,`Task ${a} cannot depend on itself.`),process.exit(1));let c=!1;if(typeof a==`string`&&typeof o==`string`&&a.includes(`.`)&&o.includes(`.`)){let[e]=a.split(`.`),[t]=o.split(`.`);c=a===o,I(`debug`,`Adding dependency between subtasks: ${a} depends on ${o}`),I(`debug`,`Parent IDs: ${e} and ${t}, Self-dependency check: ${c}`)}c&&(I(`error`,`Subtask ${a} cannot depend on itself.`),process.exit(1));let l=[a];rc(i.tasks,o,l)?(I(`error`,`Cannot add dependency ${o} to task ${a} as it would create a circular dependency.`),process.exit(1)):(s.dependencies.push(o),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}),F(e,i,r.projectRoot,r.tag),I(`success`,`Added dependency ${o} to task ${a}`),z()||console.log(G(V.green(`Successfully added dependency:
|
|
957
967
|
|
|
958
|
-
`)+`Task ${V.bold(a)} now depends on ${V.bold(o)}`,{padding:1,borderColor:`green`,borderStyle:`round`,margin:{top:1}})),I(`info`,`Task files regenerated with updated dependencies.`))}async function
|
|
968
|
+
`)+`Task ${V.bold(a)} now depends on ${V.bold(o)}`,{padding:1,borderColor:`green`,borderStyle:`round`,margin:{top:1}})),I(`info`,`Task files regenerated with updated dependencies.`))}async function nc(e,t,n,r={}){I(`info`,`Removing dependency ${n} from task ${t}...`);let i=P(e,r.projectRoot,r.tag);(!i||!i.tasks)&&(I(`error`,`No valid tasks found.`),process.exit(1));let a=typeof t==`string`&&t.includes(`.`)?t:parseInt(t,10),o=se(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);n||(I(`error`,`Parent task ${e} not found.`),process.exit(1)),n.subtasks||(I(`error`,`Parent task ${e} has no subtasks.`),process.exit(1)),s=n.subtasks.find(e=>e.id===t),c=!0,s||(I(`error`,`Subtask ${a} not found.`),process.exit(1))}else s=i.tasks.find(e=>e.id===a),s||(I(`error`,`Task ${a} not found.`),process.exit(1));if(!s.dependencies||s.dependencies.length===0){I(`info`,`Task ${a} has no dependencies, nothing to remove.`);return}let l=String(o),u=s.dependencies.findIndex(e=>{if(String(e)===l)return!0;if(typeof e==`number`&&e<100&&c){let[t]=a.split(`.`);if(`${t}.${e}`===l)return!0}return!1});u===-1?I(`info`,`Task ${a} does not depend on ${o}, no changes made.`):(s.dependencies.splice(u,1),F(e,i,r.projectRoot,r.tag),I(`success`,`Removed dependency: Task ${a} no longer depends on ${o}`),z()||console.log(G(V.green(`Successfully removed dependency:
|
|
959
969
|
|
|
960
|
-
`)+`Task ${V.bold(a)} no longer depends on ${V.bold(o)}`,{padding:1,borderColor:`green`,borderStyle:`round`,margin:{top:1}})))}function
|
|
970
|
+
`)+`Task ${V.bold(a)} no longer depends on ${V.bold(o)}`,{padding:1,borderColor:`green`,borderStyle:`round`,margin:{top:1}})))}function rc(e,t,n=[]){let r=String(t);if(n.some(e=>String(e)===r))return!0;let i=null,a=null;if(r.includes(`.`)){let[t,n]=r.split(`.`).map(Number),o=e.find(e=>e.id===t);a=t,o&&o.subtasks&&(i=o.subtasks.find(e=>e.id===n))}else{let t=parseInt(r,10);i=e.find(e=>e.id===t||String(e.id)===r)}if(!i||!i.dependencies||i.dependencies.length===0)return!1;let o=[...n,r];return i.dependencies.some(t=>{let n=String(t);return typeof t==`number`&&a!==null&&(n=`${a}.${t}`),rc(e,n,o)})}function ic(e){let t=[];return e.forEach(n=>{n.dependencies&&(n.dependencies.forEach(r=>{String(r)===String(n.id)?t.push({type:`self`,taskId:n.id,message:`Task ${n.id} depends on itself`}):fe(e,r)||t.push({type:`missing`,taskId:n.id,dependencyId:r,message:`Task ${n.id} depends on non-existent task ${r}`})}),rc(e,n.id)&&t.push({type:`circular`,taskId:n.id,message:`Task ${n.id} is part of a circular dependency chain`}),n.subtasks&&n.subtasks.length>0&&n.subtasks.forEach(r=>{if(!r.dependencies)return;let i=`${n.id}.${r.id}`;r.dependencies.forEach(n=>{String(n)===String(i)||typeof n==`number`&&n===r.id?t.push({type:`self`,taskId:i,message:`Subtask ${i} depends on itself`}):fe(e,n)||t.push({type:`missing`,taskId:i,dependencyId:n,message:`Subtask ${i} depends on non-existent task/subtask ${n}`})}),rc(e,i)&&t.push({type:`circular`,taskId:i,message:`Subtask ${i} is part of a circular dependency chain`})}))}),{valid:t.length===0,issues:t}}async function ac(e,t={}){let{context:n={}}=t;I(`info`,`Checking for invalid dependencies in task files...`);let r=P(e,n.projectRoot,n.tag);(!r||!r.tasks)&&(I(`error`,`No valid tasks found in tasks.json`),process.exit(1));let i=r.tasks.length,a=0;r.tasks.forEach(e=>{e.subtasks&&Array.isArray(e.subtasks)&&(a+=e.subtasks.length)}),I(`info`,`Analyzing dependencies for ${i} tasks and ${a} subtasks...`);try{let e=ic(r.tasks);e.valid?(I(`success`,`No invalid dependencies found - all dependencies are valid`),z()||console.log(G(V.green(`All Dependencies Are Valid
|
|
961
971
|
|
|
962
|
-
`)+`${V.cyan(`Tasks checked:`)} ${i}\n${V.cyan(`Subtasks checked:`)} ${a}\n${V.cyan(`Total dependencies verified:`)} ${
|
|
972
|
+
`)+`${V.cyan(`Tasks checked:`)} ${i}\n${V.cyan(`Subtasks checked:`)} ${a}\n${V.cyan(`Total dependencies verified:`)} ${oc(r.tasks)}`,{padding:1,borderColor:`green`,borderStyle:`round`,margin:{top:1,bottom:1}}))):(I(`error`,`Dependency validation failed. Found ${e.issues.length} issue(s):`),e.issues.forEach(e=>{let t=` [${e.type.toUpperCase()}] Task ${e.taskId}: ${e.message}`;e.dependencyId&&(t+=` (Dependency: ${e.dependencyId})`),I(`error`,t)}),z()||console.log(G(V.red(`Dependency Validation FAILED
|
|
963
973
|
|
|
964
|
-
`)+`${V.cyan(`Tasks checked:`)} ${i}\n${V.cyan(`Subtasks checked:`)} ${a}\n${V.red(`Issues found:`)} ${e.issues.length}`,{padding:1,borderColor:`red`,borderStyle:`round`,margin:{top:1,bottom:1}})))}catch(e){I(`error`,`Error validating dependencies:`,e),process.exit(1)}}function
|
|
974
|
+
`)+`${V.cyan(`Tasks checked:`)} ${i}\n${V.cyan(`Subtasks checked:`)} ${a}\n${V.red(`Issues found:`)} ${e.issues.length}`,{padding:1,borderColor:`red`,borderStyle:`round`,margin:{top:1,bottom:1}})))}catch(e){I(`error`,`Error validating dependencies:`,e),process.exit(1)}}function oc(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 sc(e,t={}){let{context:n={}}=t;I(`info`,`Checking for and fixing invalid dependencies in tasks.json...`);try{let t=P(e,n.projectRoot,n.tag);(!t||!t.tasks)&&(I(`error`,`No valid tasks found in tasks.json`),process.exit(1));let r=JSON.parse(JSON.stringify(t)),i={nonExistentDependenciesRemoved:0,selfDependenciesRemoved:0,duplicateDependenciesRemoved:0,circularDependenciesFixed:0,tasksFixed:0,subtasksFixed:0};t.tasks.forEach(e=>{if(e.dependencies&&Array.isArray(e.dependencies)){let t=/* @__PURE__ */ new Set,n=e.dependencies.length;e.dependencies=e.dependencies.filter(n=>{let r=String(n);return t.has(r)?(I(`info`,`Removing duplicate dependency from task ${e.id}: ${n}`),i.duplicateDependenciesRemoved++,!1):(t.add(r),!0)}),e.dependencies.length<n&&i.tasksFixed++}e.subtasks&&Array.isArray(e.subtasks)&&e.subtasks.forEach(t=>{if(t.dependencies&&Array.isArray(t.dependencies)){let n=/* @__PURE__ */ new Set,r=t.dependencies.length;t.dependencies=t.dependencies.filter(r=>{let a=String(r);return typeof r==`number`&&r<100&&(a=`${e.id}.${r}`),n.has(a)?(I(`info`,`Removing duplicate dependency from subtask ${e.id}.${t.id}: ${r}`),i.duplicateDependenciesRemoved++,!1):(n.add(a),!0)}),t.dependencies.length<r&&i.subtasksFixed++}})});let a=new Set(t.tasks.map(e=>e.id)),o=/* @__PURE__ */ new Set;t.tasks.forEach(e=>{e.subtasks&&Array.isArray(e.subtasks)&&e.subtasks.forEach(t=>{o.add(`${e.id}.${t.id}`)})}),t.tasks.forEach(e=>{if(e.dependencies&&Array.isArray(e.dependencies)){let t=e.dependencies.length;e.dependencies=e.dependencies.filter(t=>{if(typeof t==`string`&&t.includes(`.`))return o.has(t)?!0:(I(`info`,`Removing invalid subtask dependency from task ${e.id}: ${t} (subtask does not exist)`),i.nonExistentDependenciesRemoved++,!1);{let n=typeof t==`string`?parseInt(t,10):t;return a.has(n)?!0:(I(`info`,`Removing invalid task dependency from task ${e.id}: ${t} (task does not exist)`),i.nonExistentDependenciesRemoved++,!1)}}),e.dependencies.length<t&&i.tasksFixed++}e.subtasks&&Array.isArray(e.subtasks)&&e.subtasks.forEach(t=>{if(t.dependencies&&Array.isArray(t.dependencies)){let n=t.dependencies.length,r=`${e.id}.${t.id}`;t.dependencies.some(e=>typeof e==`string`&&e.includes(`.`)?e===r:typeof e==`number`&&e<100&&e===t.id)&&(t.dependencies=t.dependencies.filter(t=>(typeof t==`number`&&t<100?`${e.id}.${t}`:String(t))!==r||(I(`info`,`Removing self-dependency from subtask ${r}`),i.selfDependenciesRemoved++,!1))),t.dependencies=t.dependencies.filter(t=>{if(typeof t==`string`&&t.includes(`.`))return o.has(t)?!0:(I(`info`,`Removing invalid subtask dependency from subtask ${r}: ${t} (subtask does not exist)`),i.nonExistentDependenciesRemoved++,!1);let n=typeof t==`number`?t:parseInt(t,10);if(n<100){let t=`${e.id}.${n}`;return o.has(t)?!0:(I(`info`,`Removing invalid subtask dependency from subtask ${r}: ${n}`),i.nonExistentDependenciesRemoved++,!1)}return a.has(n)?!0:(I(`info`,`Removing invalid task dependency from subtask ${r}: ${n}`),i.nonExistentDependenciesRemoved++,!1)}),t.dependencies.length<n&&i.subtasksFixed++}})}),I(`info`,`Checking for circular dependencies...`);let s=/* @__PURE__ */ new Map;t.tasks.forEach(e=>{e.subtasks&&Array.isArray(e.subtasks)&&e.subtasks.forEach(t=>{let n=`${e.id}.${t.id}`;if(t.dependencies&&Array.isArray(t.dependencies)){let r=t.dependencies.map(t=>typeof t==`string`&&t.includes(`.`)?t:typeof t==`number`&&t<100?`${e.id}.${t}`:String(t));s.set(n,r)}else s.set(n,[])})});for(let[e,n]of s.entries()){let n=k(e,s,/* @__PURE__ */ new Set,/* @__PURE__ */ new Set);if(n.length>0){let[r,a]=e.split(`.`).map(e=>Number(e)),o=t.tasks.find(e=>e.id===r);if(o&&o.subtasks){let t=o.subtasks.find(e=>e.id===a);if(t&&t.dependencies){let a=t.dependencies.length,o=n.map(e=>{if(e.includes(`.`)){let[t,n]=e.split(`.`).map(e=>Number(e));return t===r?n:e}return Number(e)});t.dependencies=t.dependencies.filter(t=>{let n=typeof t==`number`&&t<100?`${r}.${t}`:String(t);return o.includes(t)||o.includes(n)?(I(`info`,`Breaking circular dependency: Removing ${n} from subtask ${e}`),i.circularDependenciesFixed++,!1):!0}),t.dependencies.length<a&&i.subtasksFixed++}}}}JSON.stringify(t)===JSON.stringify(r)?I(`info`,`No changes needed to fix dependencies`):(F(e,t,n.projectRoot,n.tag),I(`success`,`Fixed dependency issues in tasks.json`),I(`info`,`Regenerating task files to reflect dependency changes...`));let c=i.nonExistentDependenciesRemoved+i.selfDependenciesRemoved+i.duplicateDependenciesRemoved+i.circularDependenciesFixed;z()||(c>0?(I(`success`,`Fixed ${c} dependency issues in total!`),console.log(G(V.green(`Dependency Fixes Summary:
|
|
965
975
|
|
|
966
976
|
`)+`${V.cyan(`Invalid dependencies removed:`)} ${i.nonExistentDependenciesRemoved}\n${V.cyan(`Self-dependencies removed:`)} ${i.selfDependenciesRemoved}\n${V.cyan(`Duplicate dependencies removed:`)} ${i.duplicateDependenciesRemoved}\n${V.cyan(`Circular dependencies fixed:`)} ${i.circularDependenciesFixed}\n\n${V.cyan(`Tasks fixed:`)} ${i.tasksFixed}\n${V.cyan(`Subtasks fixed:`)} ${i.subtasksFixed}\n`,{padding:1,borderColor:`green`,borderStyle:`round`,margin:{top:1,bottom:1}}))):(I(`success`,`No dependency issues found - all dependencies are valid`),console.log(G(V.green(`All Dependencies Are Valid
|
|
967
977
|
|
|
968
|
-
`)+`${V.cyan(`Tasks checked:`)} ${t.tasks.length}\n${V.cyan(`Total dependencies verified:`)} ${
|
|
978
|
+
`)+`${V.cyan(`Tasks checked:`)} ${t.tasks.length}\n${V.cyan(`Total dependencies verified:`)} ${oc(t.tasks)}`,{padding:1,borderColor:`green`,borderStyle:`round`,margin:{top:1,bottom:1}}))))}catch(e){I(`error`,`Error in fix-dependencies command:`,e),process.exit(1)}}function cc(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 lc(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=cc(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=cc(e,r,n,!1)}}return i}function uc(e,t,n){let r=[];return!Array.isArray(e.dependencies)||e.dependencies.length===0||e.dependencies.filter(e=>e!=null).forEach(i=>{let a=lc(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 dc(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=uc(e,n,r);i.push(...t)}),i}function fc(e,t,n){if(!e||typeof e!=`string`)throw new $s(ec.INVALID_TASK_ID,`Task ID must be a valid string`);if(!t||typeof t!=`string`)throw new $s(ec.INVALID_SOURCE_TAG,`Source tag must be a valid string`);if(!n||typeof n!=`string`)throw new $s(ec.INVALID_TARGET_TAG,`Target tag must be a valid string`);if(e.includes(`.`))throw new $s(ec.CANNOT_MOVE_SUBTASK,`Cannot move subtask ${e} directly between tags.
|
|
969
979
|
|
|
970
980
|
First promote it to a full task using:
|
|
971
|
-
taskgraph remove-subtask --id=${e} --convert`,{taskId:e,sourceTag:t,targetTag:n})}export{
|
|
981
|
+
taskgraph remove-subtask --id=${e} --convert`,{taskId:e,sourceTag:t,targetTag:n})}export{Xn as $,es as A,Ri as B,Cs as C,ys as D,bs as E,fa as F,Xr as G,Mi as H,Ui as I,Vr as J,Br as K,Hi as L,Qo as M,Zo as N,fs as O,$i as P,ir as Q,Vi as R,ws as S,xs as T,ei as U,Li as V,$r as W,tr as X,Fr as Y,Yn as Z,ks as _,Os as a,Jn as at,$ as b,Gs as c,In as ct,As as d,Y as dt,er as et,Qs as f,ct as ft,Xs as g,Ws as h,ac as i,$n as it,$o as j,ts as k,Bs as l,Pn as lt,Zs as m,sc as n,Qn as nt,Vs as o,qn as ot,Rs as p,zr as q,nc as r,rr as rt,js as s,Kn as st,tc as t,nr as tt,Js as u,Fn as ut,Is as v,Ss as w,Ts as x,Ms as y,Bi as z};
|