taskgraph-ai 0.50.1 → 0.51.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/{ai-services-unified-DbjBfAvG.js → ai-services-unified-DwHuNUlO.js} +1 -1
- package/dist/ai-services-unified-aOUSTEmw.js +1 -0
- package/dist/{commands-2aOf3ERj.js → commands-D_VapbAQ.js} +7 -7
- package/dist/{config-manager-Da0wEujO.js → config-manager-DG87FsDF.js} +1 -1
- package/dist/{config-manager-C8-BTReQ.js → config-manager-ej5JKm18.js} +1 -1
- package/dist/{dependency-manager-DIbDdrUV.js → dependency-manager-CjxVGmuC.js} +19 -19
- package/dist/{init-CNSqtmPC.js → init-DUzgqJZ7.js} +2 -2
- package/dist/mcp-server.js +3 -3
- package/dist/research-7xW4ZUMs.js +1 -0
- package/dist/response-language-Bod1H20U.js +1 -0
- package/dist/{response-language-Cc70IGmg.js → response-language-Brlt_SY8.js} +1 -1
- package/dist/{src-lvp18X-h.js → src-BBxi6qOe.js} +9 -9
- package/dist/tag-management-Dv9RZPW1.js +1 -0
- package/dist/{task-manager-BKqm9QPb.js → task-manager-BdNvu6jr.js} +1 -1
- package/dist/taskgraph.js +1 -1
- package/dist/update-subtask-by-id-Etpq966C.js +1 -0
- package/dist/update-task-by-id-CDNLHmUN.js +1 -0
- package/dist/{utils-D1-Eo-6k.js → utils-CS74XlwU.js} +1 -1
- package/package.json +1 -1
- package/dist/ai-services-unified-TeIK2DoX.js +0 -1
- package/dist/research-CUiuqEKk.js +0 -1
- package/dist/response-language-CGnha79j.js +0 -1
- package/dist/tag-management-B5XoFcUP.js +0 -1
- package/dist/update-subtask-by-id-Ct9TTTgG.js +0 -1
- package/dist/update-task-by-id-BvdEKXsG.js +0 -1
|
@@ -1,7 +1,7 @@
|
|
|
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-DwHuNUlO.js";import{C as a,S as o,_ as s,a as c,b as l,c as u,f as d,g as f,h as p,i as m,l as h,m as g,n as _,p as v,r as y,t as b,u as x,x as S}from"./src-BBxi6qOe.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-DG87FsDF.js";import V from"chalk";import Ae,{resolve as je}from"node:path";import H from"path";import Me from"node:fs";import{spawn as Ne}from"child_process";import Pe from"node:os";import{z as U}from"zod";import*as Fe from"fs";import W from"fs";import G from"boxen";import Ie from"readline";import{Command as K}from"commander";import Le from"figlet";import Re from"gradient-string";import ze from"terminal-link";import{marked as Be}from"marked";import{markedTerminal as Ve}from"marked-terminal";import He from"turndown";import q from"cli-table3";import Ue from"ora";import We from"process";import Ge from"https";import Ke from"os";import qe from"cli-progress";import Je from"inquirer";import Ye,{Separator as Xe}from"@inquirer/search";import Ze from"fuse.js";import{smoothStream as Qe}from"ai";import $e from"ajv";import et from"ajv-formats";import tt from"gpt-tokens";import"@streamparser/json";function nt(e,t,n){return(n?.color?V[n.color]:V.cyan)(ze(e,t,{fallback:(e,t)=>n?.textOnlyFallback?e:`${e} (${t})`}))}function rt(e,t){return nt(e,e,t)}function it(e,t){return nt(e,t,{color:`cyan`})}function at(e,t){return nt(e,t,{color:`cyan`})}function ot(){return ze.isSupported}const st=Re(he);function ct(){return process.env.TM_HIDE_BANNER===`true`}function lt(){return process.stdout.columns||80}function ut(e={}){if(ct())return;let{version:t}=e;try{let e=Le.textSync(`TaskGraph`,{font:`Standard`,horizontalLayout:`default`,verticalLayout:`default`});console.log(st(e))}catch{console.log(st(`=== TaskGraph ===`))}let n=`x.com/stephennmiller_`,r=nt(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?nt(`v${a}`,o,{color:`dim`,textOnlyFallback:!0}):``;if(s){let e=`by ${n}`.length,t=a.length+1,r=lt()-e-t-1;r>=2?console.log(i+` `.repeat(r)+s):(console.log(i),console.log(s))}else console.log(i);console.log(``)}function dt(){if(ct())return;try{let e=Le.textSync(`TaskGraph`,{font:`Standard`,horizontalLayout:`default`,verticalLayout:`default`});console.log(st(e))}catch{console.log(st(`=== TaskGraph ===`))}let e=nt(`x.com/stephennmiller_`,`https://x.com/stephennmiller_`,{textOnlyFallback:!0});console.log(V.dim(`by `)+V.cyan(e)),console.log(``)}function ft(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))];return r&&r.label&&r.action&&c.push(V.cyan(r.label)+`
|
|
2
2
|
`+B.brand.underline(r.action)),i&&c.push(B.muted(i)),G(c.join(`
|
|
3
3
|
|
|
4
|
-
`),{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 pt(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 mt(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;break}}),t.completedCount=e.filter(e=>
|
|
4
|
+
`),{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 pt(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 mt(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;break}}),t.completedCount=e.filter(e=>f(e.status)).length,t.completionPercentage=t.total>0?Math.round(t.completedCount/t.total*100):0,t}function ht(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;break}})}),t.completedCount=n.filter(e=>f(e.status)).length,t.completionPercentage=t.total>0?Math.round(t.completedCount/t.total*100):0,t}function gt(e){let t=new Set(e.filter(e=>f(e.status)).map(e=>e.id)),n=e.filter(e=>!f(e.status)&&(!e.dependencies||e.dependencies.length===0)).length,r=e.filter(e=>!f(e.status)&&e.dependencies&&e.dependencies.length>0&&e.dependencies.every(e=>t.has(e))).length,i=e.filter(e=>!f(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 _t(e){let t={critical:0,high:0,medium:0,low:0};return e.forEach(e=>{let n=e.priority||`medium`;t[n]++}),t}function vt(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 yt(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?`
|
|
5
5
|
`+e.slice(2).join(` `):``):e.join(` `),a=i(r);return r.length=0,r.push(`${J.inProgress} In Progress: ${B.active(e.inProgress)}`),r.push(`${J.review} Review: ${V.magenta(e.review||0)}`),r.push(`${J.pending} Pending: ${V.yellow(e.pending)}`),r.push(`${J.blocked} Blocked: ${V.red(e.blocked)}`),a+`
|
|
6
6
|
`+i(r)}function bt(e,t,n,r=!1){let i=vt(e),a=vt(t),o=r?16:30,s=pt(e.completionPercentage,o,i),c=pt(t.completionPercentage,o,a),l=`${e.completionPercentage}% ${e.completedCount}/${e.total}`,u=`${t.completionPercentage}% ${t.completedCount}/${t.total}`;return V.bold(`Project Dashboard`)+`
|
|
7
7
|
Tasks Progress: ${s} ${V.yellow(l)}\n`+yt(e,!1,r)+`
|
|
@@ -58,14 +58,14 @@ ID: ${t?V.cyan(String(t.id)):B.muted(`N/A`)} - ${t?V.bold(t.title):V.yellow(`No
|
|
|
58
58
|
`)[0].split(`.`)[0]}function Qt(){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:Et(.97)}))}const $t=`tasks.json`;function en(e){let t=
|
|
61
|
+
`),{padding:1,margin:{top:0,bottom:1},borderStyle:`round`,...ke,width:Et(.97)}))}const $t=`tasks.json`;function en(e){let t=u(e);console.log(V.dim(`\nWatching ${$t} for changes...`)),console.log(B.muted(`Last synced: ${t}`)),console.log(V.dim(`Press Ctrl+C to exit`))}function tn(e){let t=u(e);console.log(B.brand(`\nℹ ${$t} updated at ${t}`))}const nn={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 rn(e,t=!1){let n=nn[e]||{color:V.red,icon:`X`,tableIcon:`X`},r=t?n.tableIcon:n.icon;return n.color(`${r} ${e}`)}const an={draft:{color:B.muted,icon:`○`,tableIcon:`○`},refining:{color:V.yellow,icon:`◐`,tableIcon:`◐`},aligned:{color:V.cyan,icon:`◎`,tableIcon:`◎`},delivering:{color:B.active,icon:`▶`,tableIcon:`▶`},delivered:{color:B.brand,icon:`◆`,tableIcon:`◆`},done:{color:V.green,icon:`✓`,tableIcon:`✓`},archived:{color:B.muted,icon:`■`,tableIcon:`■`}};function on(e){return an[e.toLowerCase()]||{color:V.red,icon:`?`,tableIcon:`?`}}function sn(e,t=!1){if(!e)return`○`;let n=on(e);return t?n.tableIcon:n.icon}function cn(e){return e?on(e).color:B.muted}function ln(e){return e.charAt(0).toUpperCase()+e.slice(1).toLowerCase()}function un(e,t=!1){if(!e)return B.muted(`○ Unknown`);let n=on(e),r=t?n.tableIcon:n.icon,i=ln(e);return n.color(`${r} ${i}`)}const dn={critical:V.red.bold,high:V.red,medium:V.yellow,low:B.muted};function fn(e){return(dn[e]||B.text)(e)}function pn(e){return e>=7?{color:V.red,label:`High`}:e>=4?{color:V.yellow,label:`Medium`}:{color:V.green,label:`Low`}}function mn(e){let t=typeof e==`string`?Number(e.trim()):e;if(isNaN(t))return B.muted(`N/A`);let{color:n}=pn(t);return n(`● ${t}`)}function hn(e){if(typeof e!=`number`)return B.muted(`N/A`);let{color:t,label:n}=pn(e);return t(`${e}/10 (${n})`)}function gn(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(`, `)}function _n(e=`TaskGraph`){console.log(G(V.bold(e),{padding:1,margin:{top:1,bottom:1},borderStyle:`round`,borderColor:N,textAlignment:`center`}))}function vn(e,t){let n=Et();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 yn=vn;function bn(e){let t=Et();console.log(G(V.green.bold(`√ `)+B.text(e),{padding:1,borderStyle:`round`,borderColor:`green`,width:t}))}function xn(e){let t=Et();console.log(G(V.yellow.bold(`⚠ `)+B.text(e),{padding:1,borderStyle:`round`,borderColor:`yellow`,width:t}))}function Sn(e){let t=Et();console.log(G(B.brand.bold(`i `)+B.text(e),{padding:1,borderStyle:`round`,borderColor:N,width:t}))}const Cn=[{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 wn(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=Cn.filter(e=>s[e.key]??!0),l=Ot(Dt(),c),u=e=>l.widths[l.keys.indexOf(e)],d=new q({head:l.keys.map(e=>B.brand.bold(Cn.find(t=>t.key===e)?.header??e)),style:{head:[],border:[]},colWidths:l.widths,wordWrap:!0}),
|
|
64
|
-
`+B.muted(`Hidden to fit width: ${l.hidden.map(e=>Cn.find(t=>t.key===e)?.header).join(`, `)}`):``;return d.toString()+
|
|
63
|
+
`+B.muted(t):``),{padding:1,borderStyle:`round`,borderColor:`red`,width:n}))}const yn=vn;function bn(e){let t=Et();console.log(G(V.green.bold(`√ `)+B.text(e),{padding:1,borderStyle:`round`,borderColor:`green`,width:t}))}function xn(e){let t=Et();console.log(G(V.yellow.bold(`⚠ `)+B.text(e),{padding:1,borderStyle:`round`,borderColor:`yellow`,width:t}))}function Sn(e){let t=Et();console.log(G(B.brand.bold(`i `)+B.text(e),{padding:1,borderStyle:`round`,borderColor:N,width:t}))}const Cn=[{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 wn(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=Cn.filter(e=>s[e.key]??!0),l=Ot(Dt(),c),u=e=>l.widths[l.keys.indexOf(e)],d=new q({head:l.keys.map(e=>B.brand.bold(Cn.find(t=>t.key===e)?.header??e)),style:{head:[],border:[]},colWidths:l.widths,wordWrap:!0}),p=e=>l.keys.map(t=>e[t]??``);e.forEach(e=>{let t=e.blocks?.join(`, `)??``;d.push(p({tag:B.accent(e.tagName||`-`),id:V.cyan(e.id.toString()),title:kt(e.title,u(`title`)-3),status:rn(e.status,!0),priority:fn(e.priority),dependencies:!e.dependencies||e.dependencies.length===0?B.muted(`-`):V.cyan(e.dependencies.map(e=>String(e)).join(`, `)),blocks:t?f(e.status)?B.muted(t):V.yellow(t):B.muted(`-`),complexity:typeof e.complexity==`number`?mn(e.complexity):B.muted(`N/A`)})),n&&e.subtasks&&e.subtasks.length>0&&e.subtasks.forEach(e=>{d.push(p({tag:B.muted(`-`),id:B.muted(` └─ ${e.id}`),title:B.muted(kt(e.title,u(`title`)-6)),status:B.muted(rn(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`?mn(e.complexity):`--`)}))})});let m=l.hidden.length>0?`
|
|
64
|
+
`+B.muted(`Hidden to fit width: ${l.hidden.map(e=>Cn.find(t=>t.key===e)?.header).join(`, `)}`):``;return d.toString()+m}var Tn=r({BANNER_GRADIENT:()=>he,BORDER_COLOR:()=>N,BRAND_COLORS:()=>De,MUTED_BOX_BORDER:()=>ke,TABLE_BORDER:()=>le,calculateDependencyStatistics:()=>gt,calculateSubtaskStatistics:()=>ht,calculateTaskStatistics:()=>mt,capitalizeStatus:()=>ln,createBriefLink:()=>it,createLink:()=>nt,createProgressBar:()=>At,createTaskLink:()=>at,createTaskTable:()=>wn,createUrlLink:()=>rt,displayAcceptanceCriteria:()=>Vt,displayAsciiBanner:()=>ut,displayBanner:()=>_n,displayCardBox:()=>ft,displayCodebasePatterns:()=>Wt,displayDashboards:()=>St,displayDependencyDashboard:()=>xt,displayError:()=>yn,displayErrorBox:()=>vn,displayExistingInfrastructure:()=>zt,displayHeader:()=>Ct,displayImplementationApproach:()=>Ut,displayImplementationDetails:()=>Ft,displayImplementationMetadata:()=>Kt,displayInfo:()=>Sn,displayInitBanner:()=>dt,displayProjectDashboard:()=>bt,displayRecommendedNextTask:()=>Xt,displayRelevantFiles:()=>Rt,displayScopeBoundaries:()=>Bt,displaySkillsAndCategory:()=>Gt,displaySubtasks:()=>Lt,displaySuccess:()=>bn,displaySuggestedActions:()=>Jt,displaySuggestedNextSteps:()=>Qt,displaySyncMessage:()=>tn,displayTaskDetails:()=>Yt,displayTaskHeader:()=>Nt,displayTaskProperties:()=>Pt,displayTechnicalConstraints:()=>Ht,displayTestStrategy:()=>It,displayWarning:()=>xn,displayWatchFooter:()=>en,formatDependenciesWithStatus:()=>gn,formatStatusLine:()=>yt,getBoxWidth:()=>Et,getBriefStatusColor:()=>cn,getBriefStatusIcon:()=>sn,getBriefStatusWithColor:()=>un,getComplexityWithColor:()=>mn,getComplexityWithScore:()=>hn,getPriorityBreakdown:()=>_t,getPriorityWithColor:()=>fn,getStatusWithColor:()=>rn,getSuggestedActions:()=>qt,getTaskDescription:()=>Zt,supportsLinks:()=>ot,theme:()=>B,truncate:()=>kt});const En=Ae.join(`.taskgraph`,`tasks`,`tasks.json`);function Dn(e){Ct({tag:e.tag||`master`,filePath:En})}function On(){return process.env.DEBUG===`true`||process.env.DEBUG===`1`}function kn(e,t={}){if(e?.getSanitizedDetails){let n=e.getSanitizedDetails();console.error(V.red(`\n${n.message}`)),(On()||t.forceStack)&&e.stack&&(console.error(B.muted(`
|
|
65
65
|
Stack trace:`)),console.error(B.muted(e.stack)))}else{let n=e?.message??String(e);console.error(V.red(`\nError: ${n}`)),(On()||t.forceStack)&&e?.stack&&(console.error(B.muted(`
|
|
66
|
-
Stack trace:`)),console.error(B.muted(e.stack)))}t.skipExit||process.exit(1)}function An(e){return e?je(e):_()}var jn=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(An(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){kn(e)}}async watchTasks(e){if(!this.tmCore)throw Error(`TmCore not initialized`);let t=await this.getTasks(e),n=new Date;console.clear(),this.displayResults(t,e),en(n);let r;try{r=await this.tmCore.tasks.watch(async r=>{if(r.type===`change`)try{t=await this.getTasks(e),n=new Date,console.clear(),this.displayResults(t,e),tn(n),en(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&&!p.includes(e.format))return console.error(V.red(`Invalid format: ${e.format}`)),console.error(B.muted(`Valid formats: ${p.join(`, `)}`)),!1;if(e.status){let t=e.status.split(`,`).map(e=>e.trim());for(let e of t)if(e!==`all`&&!b.includes(e))return console.error(V.red(`Invalid status: ${e}`)),console.error(B.muted(`Valid statuses: ${b.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 m({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=v(s)),e.blocking&&(s=h(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?v(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;case`text`:default:this.displayText(e,t);break}}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&&Dn({tag:i?`all tags`:r||`master`});for(let e of n){let n=c[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=c[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&&Dn({tag:i?`all tags`:r||`master`}),n.length===0){xn(`No tasks found matching the criteria.`);return}let a=mt(n),o=ht(n),s=gt(n),c=_t(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||St(a,o,c,s,u),console.log(wn(n,{showSubtasks:t.withSubtasks,showDependencies:!0,showBlocks:!0,showComplexity:!0,showTag:i})),!d){if(u){let e=Zt(u);Xt({id:u.id,title:u.title,priority:u.priority,status:u.status,dependencies:u.dependencies,description:e,complexity:u.complexity})}Qt()}}setLastResult(e){this.lastResult=e}findNextTask(e){let t={critical:4,high:3,medium:2,low:1},n=new Set;e.forEach(e=>{S(e.status)&&n.add(String(e.id)),e.subtasks&&e.subtasks.forEach(t=>{S(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}},Mn=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(An(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=u.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){kn(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 m({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;case`text`:default:`task`in e?this.displaySingleTask(e,t):this.displayMultipleTasks(e,t);break}}displayJson(e){console.log(JSON.stringify(e,null,2))}displaySingleTask(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}Dn({tag:this.tmCore?.config.getActiveTag()||`master`}),console.log(),Yt(e.task,{statusFilter:t.status,showSuggestedActions:!0,originalTaskId:e.originalTaskId})}displayMultipleTasks(e,t){if(Dn({tag:this.tmCore?.config.getActiveTag()||`master`}),e.notFound.length>0&&console.log(V.yellow(`\n⚠ Not found: ${e.notFound.join(`, `)}`)),e.tasks.length===0){xn(`No tasks found matching the criteria.`);return}console.log(B.brand.bold(`
|
|
66
|
+
Stack trace:`)),console.error(B.muted(e.stack)))}t.skipExit||process.exit(1)}function An(e){return e?je(e):x()}var jn=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(An(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){kn(e)}}async watchTasks(e){if(!this.tmCore)throw Error(`TmCore not initialized`);let t=await this.getTasks(e),n=new Date;console.clear(),this.displayResults(t,e),en(n);let r;try{r=await this.tmCore.tasks.watch(async r=>{if(r.type===`change`)try{t=await this.getTasks(e),n=new Date,console.clear(),this.displayResults(t,e),tn(n),en(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&&!v.includes(e.format))return console.error(V.red(`Invalid format: ${e.format}`)),console.error(B.muted(`Valid formats: ${v.join(`, `)}`)),!1;if(e.status){let t=e.status.split(`,`).map(e=>e.trim());for(let e of t)if(e!==`all`&&!p.includes(e))return console.error(V.red(`Invalid status: ${e}`)),console.error(B.muted(`Valid statuses: ${p.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 d({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}=b(i.tasks);this.displayInvalidDependencyWarnings(o);let s=i.tasks.map(e=>({...e,blocks:a.get(String(e.id))||[]}));return e.ready&&(s=y(s)),e.blocking&&(s=_(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}=b(i.tasks);this.displayInvalidDependencyWarnings(o,t);let s=i.tasks.map(e=>({...e,blocks:a.get(String(e.id))||[],tagName:t})),c=e.ready?y(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;case`text`:default:this.displayText(e,t);break}}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&&Dn({tag:i?`all tags`:r||`master`});for(let e of n){let n=g[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=g[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&&Dn({tag:i?`all tags`:r||`master`}),n.length===0){xn(`No tasks found matching the criteria.`);return}let a=mt(n),o=ht(n),s=gt(n),c=_t(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||St(a,o,c,s,u),console.log(wn(n,{showSubtasks:t.withSubtasks,showDependencies:!0,showBlocks:!0,showComplexity:!0,showTag:i})),!d){if(u){let e=Zt(u);Xt({id:u.id,title:u.title,priority:u.priority,status:u.status,dependencies:u.dependencies,description:e,complexity:u.complexity})}Qt()}}setLastResult(e){this.lastResult=e}findNextTask(e){let t={critical:4,high:3,medium:2,low:1},n=new Set;e.forEach(e=>{f(e.status)&&n.add(String(e.id)),e.subtasks&&e.subtasks.forEach(t=>{f(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}},Mn=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(An(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=c.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){kn(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 d({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;case`text`:default:`task`in e?this.displaySingleTask(e,t):this.displayMultipleTasks(e,t);break}}displayJson(e){console.log(JSON.stringify(e,null,2))}displaySingleTask(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}Dn({tag:this.tmCore?.config.getActiveTag()||`master`}),console.log(),Yt(e.task,{statusFilter:t.status,showSuggestedActions:!0,originalTaskId:e.originalTaskId})}displayMultipleTasks(e,t){if(Dn({tag:this.tmCore?.config.getActiveTag()||`master`}),e.notFound.length>0&&console.log(V.yellow(`\n⚠ Not found: ${e.notFound.join(`, `)}`)),e.tasks.length===0){xn(`No tasks found matching the criteria.`);return}console.log(B.brand.bold(`
|
|
67
67
|
Tasks:
|
|
68
|
-
`)),console.log(wn(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}},Nn=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(An(e.project));let t=await this.getNextTask(e);this.setLastResult(t),e.silent||this.displayResults(t,e)}catch(e){t=!0,kn(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){this.tmCore||=await
|
|
68
|
+
`)),console.log(wn(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}},Nn=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(An(e.project));let t=await this.getNextTask(e);this.setLastResult(t),e.silent||this.displayResults(t,e)}catch(e){t=!0,kn(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){this.tmCore||=await d({projectPath:Ae.resolve(e)})}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;case`text`:default:this.displayText(e);break}}displayJson(e){console.log(JSON.stringify(e,null,2))}displayText(e){if(Dn({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;Yt(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}},Pn=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=Ue(`Initializing TaskGraph...`).start(),await this.initializeCore(An(t.project)),n.succeed(`TaskGraph initialized`);let r=e||t.id||null;r||(n=Ue(`Finding next available task...`).start(),r=await this.performGetNextTask(),r?n.succeed(`Found next task: #${r}`):n.fail(`No available tasks found`)),r||(yn(`No task ID provided and no available tasks found`),process.exit(1)),t.dryRun||await this.showPreLaunchMessage(r),n=Ue(`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`),kn(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 d({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=Ue(`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=Ne(e.executable,e.args,{cwd:e.cwd,stdio:`inherit`,shell:!1});r.on(`close`,e=>{e===0?t():n(Error(`Process exited with code ${e}`))}),r.on(`error`,e=>{n(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;case`text`:default:this.displayTextResult(e,t);break}}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}`),Yt(n,{customHeader:t,headerColor:`yellow`}),e.executionOutput&&(console.log(),console.log(G(V.bold(`Claude-Code Prompt:`)+`
|
|
69
69
|
|
|
70
70
|
`+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
71
|
|
|
@@ -78,7 +78,7 @@ Tasks:
|
|
|
78
78
|
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
79
|
tm set-status 1 done
|
|
80
80
|
tm set-status 1,1.1 in-progress
|
|
81
|
-
tm set-status --id=1 --status=done`)),process.exit(1)),Fn.includes(e.status)||(console.error(V.red(`Error: Invalid status "${e.status}". Valid options: ${Fn.join(`, `)}`)),process.exit(1)),this.tmCore=await
|
|
81
|
+
tm set-status --id=1 --status=done`)),process.exit(1)),Fn.includes(e.status)||(console.error(V.red(`Error: Invalid status "${e.status}". Valid options: ${Fn.join(`, `)}`)),process.exit(1)),this.tmCore=await d({projectPath:An(e.project)});let n=e.id.split(`,`).map(e=>e.trim()),r=[];for(let e of n){let t=c.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:new Date().toISOString()}))}else e.silent||(console.error(V.red(`\nFailed to update task ${n}:`)),kn(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||kn(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;case`text`:default:t.silent||this.displayTextResults(e);break}}displayTextResults(e){if(e.updatedTasks.length===1){let t=e.updatedTasks[0];console.log(G(V.bold(`✓ Updated task ${t.taskId}`)+`
|
|
82
82
|
|
|
83
83
|
${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
84
|
|
|
@@ -96,7 +96,7 @@ Auto-updating to the latest version with new features and bug fixes...`;let i=G(
|
|
|
96
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 rr(e){let t=Ue({text:B.brand(`Updating ${zn} to version ${V.green(e)}`),spinner:`dots`,color:`blue`}).start();return new Promise(n=>{let r=Ne(`npm`,[`install`,`-g`,`${zn}@${e}`,`--no-fund`,`--no-audit`,`--loglevel=warn`],{stdio:[`ignore`,`pipe`,`pipe`]}),i=``;r.stdout.on(`data`,()=>{t.text=B.brand(`Installing ${zn}@${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 ${zn}@${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 ${zn}@${e}`)),n(!1)})})}async function ir(e){if(We.env.TASKGRAPH_SKIP_AUTO_UPDATE===`1`||We.env.CI||We.env.NODE_ENV===`test`){let e=We.env.TASKGRAPH_SKIP_AUTO_UPDATE===`1`?`TASKGRAPH_SKIP_AUTO_UPDATE=1`:We.env.CI?`CI environment`:`NODE_ENV=test`;return console.log(V.dim(`Skipping auto-update (${e})`)),!1}let t=await Xn(e);if(!t)return rr(e);let n=Ke.tmpdir(),r=H.join(n,`${zn}-${e}.tgz`);return await Zn(t.url,r,e)?await nr(r)?(console.log(V.green(`Successfully updated to version ${V.bold(e)}`)),!0):(console.log(V.cyan(`Please run manually: npm install -g ${zn}@${e}`)),!1):(console.log(V.dim(`Falling back to npm install...`)),rr(e))}function ar(e){let t=e.slice(2);console.log(V.dim(`Restarting with updated version...
|
|
97
97
|
`));let n=Ne(`taskgraph`,t,{stdio:`inherit`,detached:!1,shell:We.platform===`win32`});n.on(`exit`,(e,t)=>{if(t){We.kill(We.pid,t);return}We.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.`)),We.exit(1)})}function or(e,t=null){let n={high:3,medium:2,low:1},r=(e,t)=>typeof t==`string`&&t.includes(`.`)?t:`${e}.${t}`,i=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}var sr=or;async function cr(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:new Date().toISOString(),updated: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:new Date().toISOString(),updated:new Date().toISOString(),description:l||`Tag created on ${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 ${new Date().toLocaleDateString()}`}}catch(e){throw u.error(`Error creating tag: ${e.message}`),e}}async function lr(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:new Date().toISOString(),updated: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
|
|
98
98
|
|
|
99
|
-
This action cannot be undone!`,{padding:1,borderColor:`yellow`,borderStyle:`round`,margin:{top:1,bottom:1}})),!(await Je.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 Je.prompt([{type:`input`,name:`tagNameConfirm`,message:`To confirm deletion, please type the tag name "${t}":`,validate:e=>e===t?!0:`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 hr(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 ur(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=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 dr(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 ur(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=v(n.map(e=>({...e,blocks:[]})));d.push({name:e,isCurrent:e===i,completedTasks:n.filter(e=>S(e.status)).length,readyTasks:a.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 fr(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 hr(o,t);let a=P(e,o,t),c=a&&a.tasks||[],l=c.length,u=sr(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 pr(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:new Date().toISOString()}),delete i[t],o&&(await hr(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 mr(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:new Date().toISOString(),updated:new Date().toISOString(),description:c||`Copy of "${t}" created on ${new Date().toLocaleDateString()}`,copiedFrom:{tag:t,date: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 ${new Date().toLocaleDateString()}`}}catch(e){throw l.error(`Error copying tag: ${e.message}`),e}}async function hr(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=new Date().toISOString(),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 gr(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[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 _r(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-BFUgMf2g.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 cr(e,n,{copyFromCurrent:s,copyFromTag:c,description:l||`Tag created from git branch "${t}"`},r,i);return await gr(o,t,n),p.info(`Updated branch-tag mapping: ${t} -> ${n}`),u&&(await hr(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 vr=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 Je.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 Je.prompt([{type:`input`,name:`tagNameConfirm`,message:`To confirm deletion, please type the tag name "${t}":`,validate:e=>e===t?!0:`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 hr(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 ur(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=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 dr(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 ur(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=y(n.map(e=>({...e,blocks:[]})));d.push({name:e,isCurrent:e===i,completedTasks:n.filter(e=>f(e.status)).length,readyTasks:a.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 p=d;if(c&&(p=d.filter(e=>e.readyTasks>0),l.info(`Filtered to ${p.length} tags with ready tasks`)),l.success(`Found ${p.length} tags`),r===`json`)return{tags:p,currentTag:i,totalTags:p.length};if(r===`text`){if(p.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}});p.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:p,currentTag:i,totalTags:p.length}}catch(e){throw l.error(`Error listing tags: ${e.message}`),e}}async function fr(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 hr(o,t);let a=P(e,o,t),c=a&&a.tasks||[],l=c.length,u=sr(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 pr(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:new Date().toISOString()}),delete i[t],o&&(await hr(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 mr(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:new Date().toISOString(),updated:new Date().toISOString(),description:c||`Copy of "${t}" created on ${new Date().toLocaleDateString()}`,copiedFrom:{tag:t,date: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 ${new Date().toLocaleDateString()}`}}catch(e){throw l.error(`Error copying tag: ${e.message}`),e}}async function hr(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=new Date().toISOString(),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 gr(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[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 _r(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-BFUgMf2g.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 cr(e,n,{copyFromCurrent:s,copyFromTag:c,description:l||`Tag created from git branch "${t}"`},r,i);return await gr(o,t,n),p.info(`Updated branch-tag mapping: ${t} -> ${n}`),u&&(await hr(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 vr=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`,`
|
|
100
100
|
Examples:
|
|
101
101
|
$ tm tags # List all tags (default)
|
|
102
102
|
$ tm tags list # List all tags (explicit)
|
|
@@ -128,17 +128,17 @@ Examples:
|
|
|
128
128
|
Examples:
|
|
129
129
|
$ tm tags copy sprint-1 sprint-2
|
|
130
130
|
$ tm tags copy sprint-1 sprint-2 --description "Next sprint tasks"
|
|
131
|
-
`).action(async(e,t,n)=>{await this.executeCopy(e,t,n)})}async initTmCore(){this.tmCore||=await
|
|
131
|
+
`).action(async(e,t,n)=>{await this.executeCopy(e,t,n)})}async initTmCore(){this.tmCore||=await d({projectPath:process.cwd()})}async executeList(e){try{await this.initTmCore();let{projectRoot:t,tasksPath:n}=h(),r=await dr(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){kn(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}=h();await cr(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){kn(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}=h(),r=await fr(n,e,{},{projectRoot:t},`text`);this.setLastResult({success:!0,action:`use`,currentTag:r.currentTag,message:`Switched to tag: ${e}`})}catch(e){kn(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}=h();await lr(r,e,{yes:t?.yes||!1},{projectRoot:n},`text`),this.setLastResult({success:!0,action:`remove`,message:`Removed tag: ${e}`})}catch(e){kn(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}=h();await pr(r,e,t,{},{projectRoot:n},`text`),this.setLastResult({success:!0,action:`rename`,message:`Renamed tag from "${e}" to "${t}"`})}catch(e){kn(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}=h();await mr(i,e,t,{description:n?.description},{projectRoot:r},`text`),this.setLastResult({success:!0,action:`copy`,message:`Copied tag from "${e}" to "${t}"`})}catch(e){kn(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}},yr=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{this.tmCore=await d({projectPath:Ae.resolve(An(e.project))});let r=t===`default`?await this.tmCore.tasks.getCount(`pending`,e.tag):void 0,i=this.tmCore.loop.resolveIterations({userIterations:e.iterations?parseInt(e.iterations,10):void 0,preset:t,pendingTaskCount:r});if(this.validateIterations(String(i)),Dn({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: ${i}`)),console.log(V.dim(`Mode: ${e.sandbox?`Docker sandbox`:`Claude CLI`}`)),t===`default`){let t=await this.tmCore.tasks.getNext(e.tag);t?console.log(B.text(`Next task to work on: ${B.text(t.id)} - ${t.title}`)):console.log(V.yellow(`No pending tasks found`))}console.log();let a={iterations:i,prompt:t,progressFile:n,tag:e.tag,sandbox:e.sandbox,includeOutput:e.output??!0,verbose:e.verbose??!1,callbacks:this.createOutputCallbacks()},o=await this.tmCore.loop.run(a);this.displayResult(o)}catch(e){kn(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.
|
|
132
132
|
`));let t=this.tmCore.loop.runInteractiveAuth();if(!t.success)throw Error(t.error||`Interactive authentication failed`);console.log(V.green(`✓ Auth complete
|
|
133
|
-
`))}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)=>{t===`warning`?console.error(V.yellow(`[Loop Warning] ${e}`)):console.error(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}},br=class{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}`))}},xr=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 br(e.json||t?.json||!1);try{let i=An(e.projectRoot||t?.projectRoot);n={...n,projectRoot:i};let a=await
|
|
134
|
-
`)[0],subtask:{id:i.currentSubtask.id,title:i.currentSubtask.title},progress:g.progress,nextAction:_?`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)}}},Cr=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:An(e.projectRoot||t?.projectRoot)},r=new br(n.json||!1);try{let e=n.projectRoot,t=await m({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)}}},wr=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 br(e.json||t?.json||!1);try{let i=An(e.projectRoot||t?.projectRoot);n={...n,projectRoot:i};let a=await m({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)}}},Tr=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 br(e.json||t?.json||!1);try{let i=An(e.projectRoot||t?.projectRoot);n={...n,projectRoot:i};let a=await m({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)}}},Er=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:An(e.projectRoot||t?.projectRoot)},r=new br(n.json||!1);try{let e=n.projectRoot,t=await m({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)}}},Dr=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:An(t.projectRoot||n?.projectRoot)},i=new br(r.json||!1);try{let t=g.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 m({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)}}},Or=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:An(e.projectRoot||t?.projectRoot)},r=new br(n.json||!1);try{let e=n.projectRoot,t=await m({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)}}},kr=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 Dr),this.addCommand(new Er),this.addCommand(new Tr),this.addCommand(new Cr),this.addCommand(new Sr),this.addCommand(new Or),this.addCommand(new wr),this.addCommand(new xr)}static register(t){let n=new e;return t.addCommand(n),n}},Ar=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=An(e.project);await this.initializeCore(t);let n=await this.generateFiles(t,e);this.lastResult=n,this.displayResults(n,e)}catch(e){t=!0,kn(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){this.tmCore||=await m({projectPath:Ae.resolve(e)})}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;case`text`:default:this.displayText(e,t);break}}displayJson(e){console.log(JSON.stringify(e,null,2))}displayText(e,t){if(this.tmCore&&Dn({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}},jr=class{static commands=[{name:`list`,description:`List all tasks with filtering and status overview`,commandClass:jn,category:`task`},{name:`show`,description:`Display detailed information about a specific task`,commandClass:Mn,category:`task`},{name:`next`,description:`Find the next available task to work on`,commandClass:Nn,category:`task`},{name:`start`,description:`Start working on a task with claude-code`,commandClass:Pn,category:`task`},{name:`set-status`,description:`Update the status of one or more tasks`,commandClass:In,category:`task`},{name:`autopilot`,description:`AI agent orchestration for TDD workflow (start, resume, next, complete, commit, status, abort)`,commandClass:kr,category:`development`},{name:`loop`,description:`Run Claude Code in a loop, one task per iteration`,commandClass:yr,category:`development`},{name:`tags`,description:`Manage tags for task organization`,commandClass:vr,category:`task`},{name:`generate`,description:`Generate individual task files from tasks.json`,commandClass:Ar,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):!1}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 Mr(e){jr.registerAll(e)}const Nr=[`main`,`research`,`fallback`];function Pr(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 Fr(e){return(t,...n)=>{e&&typeof e[t]==`function`&&e[t](...n)}}async function Ir(e={}){let{mcpLog:t,projectRoot:n}=e,r=Fr(t);Pr(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 Lr(e={}){let{mcpLog:t,projectRoot:n}=e,r=Fr(t);Pr(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 Rr(e,t,n={}){let{mcpLog:r,projectRoot:i}=n,a=Fr(r);if(Pr(i),!Nr.includes(e))return{success:!1,error:{code:`INVALID_ROLE`,message:`Invalid role: ${e}. Must be one of: ${Nr.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=l.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 zr(e){return Ir(e)}async function Br(e,t,n){return Rr(e,t,n)}function Vr(){return ye()}function Hr(e,t,n=!1){let r=t[e],i=Vr().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 Xe(`
|
|
133
|
+
`))}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)=>{t===`warning`?console.error(V.yellow(`[Loop Warning] ${e}`)):console.error(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}},br=class{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}`))}},xr=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 br(e.json||t?.json||!1);try{let i=An(e.projectRoot||t?.projectRoot);n={...n,projectRoot:i};let a=await d({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 Je.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)}}},Sr=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:An(e.projectRoot||t?.projectRoot)},r=new br(n.json||!1);try{let e=n.projectRoot,t=await d({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],f=new o,p=s.lastTestResults,m=f.generateMessage({type:`feat`,description:i.currentSubtask.title,changedFiles:u,taskId:i.taskId,phase:i.tddPhase,tag:s.metadata.tag||void 0,testsPassing:p?.passed,testsFailing:p?.failed,coveragePercent:void 0});await c.createCommit(m,{metadata:{taskId:i.taskId,subtaskId:i.currentSubtask.id,phase:`COMMIT`,tddCycle:`complete`}});let h=await c.getLastCommit(),g=await t.workflow.commit(),_=g.phase===`COMPLETE`;r.success(`Commit created`,{commitHash:h.hash.substring(0,7),message:m.split(`
|
|
134
|
+
`)[0],subtask:{id:i.currentSubtask.id,title:i.currentSubtask.title},progress:g.progress,nextAction:_?`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)}}},Cr=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:An(e.projectRoot||t?.projectRoot)},r=new br(n.json||!1);try{let e=n.projectRoot,t=await d({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)}}},wr=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 br(e.json||t?.json||!1);try{let i=An(e.projectRoot||t?.projectRoot);n={...n,projectRoot:i};let a=await d({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)}}},Tr=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 br(e.json||t?.json||!1);try{let i=An(e.projectRoot||t?.projectRoot);n={...n,projectRoot:i};let a=await d({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,f=o.currentSubtask;if(l===`COMPLETE`){r.success(`Workflow complete`,{message:`All subtasks have been completed`,taskId:o.taskId});return}let p={action:s.action,description:s.description,phase:l,tddPhase:u,taskId:o.taskId,branchName:o.branchName,subtask:f?{id:f.id,title:f.title,attempts:f.attempts}:null,nextSteps:s.nextSteps,lastTestResults:c.lastTestResults};n.json?r.output(p):r.success(`Next action`,p)}catch(e){r.error(e.message),n.verbose&&console.error(e.stack),process.exit(1)}}},Er=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:An(e.projectRoot||t?.projectRoot)},r=new br(n.json||!1);try{let e=n.projectRoot,t=await d({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)}}},Dr=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:An(t.projectRoot||n?.projectRoot)},i=new br(r.json||!1);try{let t=m.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 d({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)}}},Or=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:An(e.projectRoot||t?.projectRoot)},r=new br(n.json||!1);try{let e=n.projectRoot,t=await d({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)}}},kr=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 Dr),this.addCommand(new Er),this.addCommand(new Tr),this.addCommand(new Cr),this.addCommand(new Sr),this.addCommand(new Or),this.addCommand(new wr),this.addCommand(new xr)}static register(t){let n=new e;return t.addCommand(n),n}},Ar=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=An(e.project);await this.initializeCore(t);let n=await this.generateFiles(t,e);this.lastResult=n,this.displayResults(n,e)}catch(e){t=!0,kn(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){this.tmCore||=await d({projectPath:Ae.resolve(e)})}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;case`text`:default:this.displayText(e,t);break}}displayJson(e){console.log(JSON.stringify(e,null,2))}displayText(e,t){if(this.tmCore&&Dn({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}},jr=class{static commands=[{name:`list`,description:`List all tasks with filtering and status overview`,commandClass:jn,category:`task`},{name:`show`,description:`Display detailed information about a specific task`,commandClass:Mn,category:`task`},{name:`next`,description:`Find the next available task to work on`,commandClass:Nn,category:`task`},{name:`start`,description:`Start working on a task with claude-code`,commandClass:Pn,category:`task`},{name:`set-status`,description:`Update the status of one or more tasks`,commandClass:In,category:`task`},{name:`autopilot`,description:`AI agent orchestration for TDD workflow (start, resume, next, complete, commit, status, abort)`,commandClass:kr,category:`development`},{name:`loop`,description:`Run Claude Code in a loop, one task per iteration`,commandClass:yr,category:`development`},{name:`tags`,description:`Manage tags for task organization`,commandClass:vr,category:`task`},{name:`generate`,description:`Generate individual task files from tasks.json`,commandClass:Ar,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):!1}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 Mr(e){jr.registerAll(e)}const Nr=[`main`,`research`,`fallback`];function Pr(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 Fr(e){return(t,...n)=>{e&&typeof e[t]==`function`&&e[t](...n)}}async function Ir(e={}){let{mcpLog:t,projectRoot:n}=e,r=Fr(t);Pr(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 Lr(e={}){let{mcpLog:t,projectRoot:n}=e,r=Fr(t);Pr(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 Rr(e,t,n={}){let{mcpLog:r,projectRoot:i}=n,a=Fr(r);if(Pr(i),!Nr.includes(e))return{success:!1,error:{code:`INVALID_ROLE`,message:`Invalid role: ${e}. Must be one of: ${Nr.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=s.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 c=ce(i);if(c.models[e]={...c.models[e],provider:n,modelId:t},delete c.models[e].baseURL,o.max_tokens&&(c.models[e].maxTokens=o.max_tokens),!w(c,i))return{success:!1,error:{code:`CONFIG_WRITE_ERROR`,message:`Error writing updated configuration to configuration file`}};let l=`Successfully set ${e} model to ${t} (Provider: ${n})`;return a(`info`,l),{success:!0,data:{role:e,provider:n,modelId:t,message:l}}}catch(t){return a(`error`,`Error setting ${e} model: ${t.message}`),{success:!1,error:{code:`SET_MODEL_ERROR`,message:t.message}}}}async function zr(e){return Ir(e)}async function Br(e,t,n){return Rr(e,t,n)}function Vr(){return ye()}function Hr(e,t,n=!1){let r=t[e],i=Vr().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 Xe(`
|
|
135
135
|
── 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 Xe(`
|
|
136
136
|
── Claude Code Models ──`),...c],f=l===-1?s?1:0: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 Ur(e,t){return(t=``)=>{let n=e.filter(e=>{if(e instanceof Xe)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 Xe)return e;let t=e;return{name:t.name,value:t.value,short:t.short}}))}}function Wr(){console.log(V.cyan(`
|
|
137
137
|
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
|
|
138
138
|
`))}async function Gr(e,t){return await Ye({message:`Select the ${{main:`main model for generation/updates`,research:`research model`,fallback:`fallback model (optional)`}[e]}:`,source:Ur(t.choices,t.default),pageSize:15})}async function Kr(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 Br(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 qr(e){e||(console.error(V.red(`Error: Could not determine project root for interactive setup.`)),process.exit(1));let t=await zr({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=Hr(`main`,n),i=Hr(`research`,n),a=Hr(`fallback`,n);Wr();let o=await Gr(`main`,r);if(o===`__CANCEL__`)return!1;let s=await Gr(`research`,i);if(s===`__CANCEL__`)return!1;let c=await Gr(`fallback`,a);if(c===`__CANCEL__`)return!1;let l=!0,u=!1,d=await Kr(`main`,o,n.main,e);d.success||(l=!1),d.modified&&(u=!0);let f=await Kr(`research`,s,n.research,e);f.success||(l=!1),f.modified&&(u=!0);let p=await Kr(`fallback`,c,n.fallback,e);return p.success||(l=!1),p.modified&&(u=!0),l&&u?console.log(V.green.bold(`
|
|
139
139
|
Model setup complete!`)):l&&!u?console.log(V.yellow(`
|
|
140
140
|
No changes made to model configuration.`)):console.error(V.red(`
|
|
141
|
-
Errors occurred during model selection. Please review and try again.`)),l}const Jr=[`pending`,`done`,`in-progress`,`review`,`deferred`,`cancelled`];function Yr(e){return Jr.includes(e)}function Xr(){return
|
|
141
|
+
Errors occurred during model selection. Please review and try again.`)),l}const Jr=[`pending`,`done`,`in-progress`,`review`,`deferred`,`cancelled`];function Yr(e){return Jr.includes(e)}function Xr(){return l||`unknown`}async function Zr(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(Yi(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}}var Qr=Zr;const $r=[`high`,`medium`,`low`],ei=`medium`;function ti(e){return $r.includes(e?.toLowerCase())}function ni(e){if(!e)return null;let t=e.toLowerCase();return ti(t)?t:null}const ri=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(),ii=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(),ai=U.object({complexityAnalysis:U.array(ii)}).strict(),oi=U.enum([`pending`,`in-progress`,`blocked`,`done`,`cancelled`,`deferred`]),si=U.object({id:U.number().int().positive(),title:U.string().min(1).max(200),description:U.string().min(1),status:oi,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(),ci=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(),li=U.object({subtasks:U.array(ci)}).strict(),ui=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(),di=U.object({tasks:U.array(ui)}).strict(),fi=U.object({subtask:ci}).strict(),pi=si.extend({subtasks:U.array(ci).nullable()}).strict(),mi=U.object({tasks:U.array(pi)}).strict(),hi=U.object({task:pi}),gi={"update-tasks":mi,"expand-task":li,"analyze-complexity":ai,"update-subtask-by-id":fi,"update-task-by-id":hi,"add-task":ri,"parse-prd":di};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.
|
|
142
142
|
|
|
143
143
|
IMPORTANT: Your response MUST be a JSON object with the following structure (no wrapper property, just these fields directly):
|
|
144
144
|
{
|
|
@@ -710,8 +710,8 @@ Updated Report Summary:`),console.log(`----------------------------`),console.lo
|
|
|
710
710
|
${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&&cc(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(`
|
|
711
711
|
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}}var Bi=zi;function Vi(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:`)+`
|
|
712
712
|
|
|
713
|
-
${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}}))}var Hi=Vi;function Ui(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 Wi(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:_}=Ui(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 Ri(ae(o.tasks),`expand-task`),r=`${u.title} ${u.description}`,i=n.findRelevantTasks(r,{maxResults:5,includeSelf:!0}),a=n.getTaskIds(i),s=[...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=Js(`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&&cc(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}}var Gi=Wi;async function Ki(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=Js(`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=Js(`Expanding task ${l.id}...`));try{let o=await Gi(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&&cc(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}}var qi=Ki;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}var Yi=Ji;async function Xi(e,t,n=null,r=!1,i=`text`,a={}){let{projectRoot:o,tag:s}=a;try{let a;try{let e=await(await m({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,h=a.tasks.filter(e=>e.status===`in-progress`).length,g=a.tasks.filter(e=>e.status===`pending`).length,_=a.tasks.filter(e=>e.status===`blocked`).length,v=a.tasks.filter(e=>e.status===`deferred`).length,y=a.tasks.filter(e=>e.status===`cancelled`).length,b=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=sr(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:h,pending:g,blocked:_,deferred:v,cancelled:y,review:b,completionPercentage:f,subtasks:{total:x,completed:S,inProgress:C,pending:w,blocked:ee,deferred:E,cancelled:D,completionPercentage:k}}};if(i===`markdown-readme`)return Qi(a,l,{totalTasks:u,completedTasks:d,completionPercentage:f,doneCount:p,inProgressCount:h,pendingCount:g,blockedCount:_,deferredCount:v,cancelledCount:y,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 na(l,r);let ce={"in-progress":u>0?h/u*100:0,pending:u>0?g/u*100:0,blocked:u>0?_/u*100:0,deferred:u>0?v/u*100:0,cancelled:u>0?y/u*100:0,review:u>0?b/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=Zs(f,30,ce),de=Zs(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`)+`
|
|
714
|
-
Tasks Progress: ${V.greenBright(ue)} ${
|
|
713
|
+
${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}}))}var Hi=Vi;function Ui(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 Wi(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:_}=Ui(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 Ri(ae(o.tasks),`expand-task`),r=`${u.title} ${u.description}`,i=n.findRelevantTasks(r,{maxResults:5,includeSelf:!0}),a=n.getTaskIds(i),s=[...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=Js(`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&&cc(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}}var Gi=Wi;async function Ki(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=Js(`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=Js(`Expanding task ${l.id}...`));try{let o=await Gi(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&&cc(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}}var qi=Ki;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}var Yi=Ji;async function Xi(e,t,n=null,r=!1,i=`text`,a={}){let{projectRoot:o,tag:s}=a;try{let a;try{let e=await(await d({projectPath:o||process.cwd()})).tasks.list({tag:s});a={tasks:e.tasks},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,f=a.tasks.filter(e=>e.status===`done`||e.status===`completed`).length,p=u>0?f/u*100:0,m=f,h=a.tasks.filter(e=>e.status===`in-progress`).length,g=a.tasks.filter(e=>e.status===`pending`).length,_=a.tasks.filter(e=>e.status===`blocked`).length,v=a.tasks.filter(e=>e.status===`deferred`).length,y=a.tasks.filter(e=>e.status===`cancelled`).length,b=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=sr(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:m,inProgress:h,pending:g,blocked:_,deferred:v,cancelled:y,review:b,completionPercentage:p,subtasks:{total:x,completed:S,inProgress:C,pending:w,blocked:ee,deferred:E,cancelled:D,completionPercentage:k}}};if(i===`markdown-readme`)return Qi(a,l,{totalTasks:u,completedTasks:f,completionPercentage:p,doneCount:m,inProgressCount:h,pendingCount:g,blockedCount:_,deferredCount:v,cancelledCount:y,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 na(l,r);let ce={"in-progress":u>0?h/u*100:0,pending:u>0?g/u*100:0,blocked:u>0?_/u*100:0,deferred:u>0?v/u*100:0,cancelled:u>0?y/u*100:0,review:u>0?b/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=Zs(p,30,ce),de=Zs(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`)+`
|
|
714
|
+
Tasks Progress: ${V.greenBright(ue)} ${p.toFixed(0)}%\n${V.green(`█`)} Done: ${V.green(m)} ${V.cyan(`▓`)} In Progress: ${V.cyan(h)} ${V.yellow(`░`)} Pending: ${V.yellow(g)} ${V.red(`!`)} Blocked: ${V.red(_)} ${Q.muted(`─`)} Deferred: ${Q.muted(v)} ${Q.muted(`─`)} Cancelled: ${Q.muted(y)}\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:`)+`
|
|
715
715
|
${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`)+`
|
|
716
716
|
`+V.cyan.bold(`Dependency Metrics:`)+`
|
|
717
717
|
${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:`)+`
|
|
@@ -757,7 +757,7 @@ ${V.cyan(`1.`)} Run ${V.yellow(`taskgraph next`)} to see what to work on next\n$
|
|
|
757
757
|
${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,Na.nextSteps))}function Ka(e){return Math.ceil(e.length/4)}function qa(e){let t=W.readFileSync(e,`utf8`);if(!t)throw Error(`Input file ${e} is empty or could not be read.`);return t}function Ja(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 Ya({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`);return}if(n){a.report(`Append mode enabled. Found ${e.length} existing tasks in tag '${t}'.`,`info`);return}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 Xa(e,t,n,r){Za(e,t);let i=t,a=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 Za(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 Qa(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||new Date().toISOString(),updated: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 $a(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 eo({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 to({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`})();Ua({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 wa.withSoftTimeout(o.mainResult.usage,1e3,void 0),cc(o.telemetryData,`cli`))}function no({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:`)+`
|
|
758
758
|
|
|
759
759
|
${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&&cc(i.telemetryData,`cli`)}async function ro(e,t){let n=new ka(e.mcpLog,e.reportProgress),{systemPrompt:r,userPrompt:a}=t,o=Ka(r+a),s=null;e.outputFormat===`text`&&!e.isMCP&&(s=Ue(`Parsing PRD and generating tasks...
|
|
760
|
-
`).start());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:Da,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&&s.succeed(`Tasks generated successfully!`),{parsedTasks:c.tasks,aiServiceResponse:t,estimatedInputTokens:o}}catch(e){throw s&&s.fail(`Error parsing PRD: ${e.message}`),e}}const[io,ao,oo]=$r,so=new Map;var co=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 lo={cli:{filled:`●`,empty:`○`},statusBar:{high:`⋮`,medium:`:`,low:`.`},mcp:{high:`🔴`,medium:`🟠`,low:`🟢`}},uo=new co(`priority`,[io,ao,oo],{[io]:V.red,[ao]:V.yellow,[oo]:B.muted});function fo(e,t){let n=lo.cli.filled,r=lo.cli.empty,i=``;for(let a=0;a<3;a++)a<e?i+=t(n):i+=B.text(r);return i}function po(e,t){return 3-t.indexOf(e)}function mo(e,t){if(so.has(e))return so.get(e);let n=t();return so.set(e,n),n}function ho(){return mo(`mcp-priority-all`,()=>({[io]:lo.mcp.high,[ao]:lo.mcp.medium,[oo]:lo.mcp.low}))}function go(){return mo(`cli-priority-all`,()=>{let e={};return uo.levels.forEach(t=>{e[t]=fo(po(t,uo.levels),uo.getColor(t))}),e})}function _o(){return mo(`statusbar-priority-all`,()=>{let e={};return uo.levels.forEach((t,n)=>{let r=n===0?lo.statusBar.high:n===1?lo.statusBar.medium:lo.statusBar.low;e[t]=uo.getColor(t)(r)}),e})}function vo(){return{[io]:uo.colors[io],[ao]:uo.colors[ao],[oo]:uo.colors[oo]}}function yo(e=!1){return e?ho():go()}function bo(e,t=!1){let n=yo(t);return n[e]||n[ao]}new co(`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 xo={clearOnComplete:!1,stopOnComplete:!0,hideCursor:!0,barsize:40},So={shades_classic:qe.Presets.shades_classic,shades_grey:qe.Presets.shades_grey,rect:qe.Presets.rect,legacy:qe.Presets.legacy},Co=new class{constructor(e={},t=So.shades_classic){this.defaultOptions={...xo,...e},this.defaultPreset=t}createSingleBar(e={},t=null){let n=this._mergeConfig(e),r=t||this.defaultPreset;return new qe.SingleBar(n,r)}createMultiBar(e={},t=null){let n=this._mergeConfig(e),r=t||this.defaultPreset;return new qe.MultiBar(n,r)}_mergeConfig(e){return{...this.defaultOptions,...e}}setDefaultOptions(e){this.defaultOptions={...this.defaultOptions,...e}}setDefaultPreset(e){this.defaultPreset=e}};function wo(e={}){return Co.createMultiBar(e)}var To=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=wo(),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(){}},Eo=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 Do(e,t,n){new Eo(e).createHeader(t,n)}function Oo(e,t,n){new Eo(e).createRow(t,n)}function ko(e,t){new Eo(e).createBorder(t)}go();const Ao=_o();vo();const jo={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 Mo=class{constructor(e=jo.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}},No=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():jo.DEFAULT_PRIORITY;return jo.VALID_PRIORITIES.includes(t)?t:jo.DEFAULT_PRIORITY}getCounts(){return{...this.priorities}}},Po=class{static formatTitle(e,t){return e?e.length>jo.MAX_TITLE_LENGTH?e.substring(0,jo.TRUNCATED_LENGTH)+`...`:e:`Task ${t}`}static formatPriority(e){return bo(e,!1).padEnd(jo.PRIORITY_PAD_END,` `)}static formatTaskId(e){return e.toString().padStart(jo.TASK_ID_PAD_START,` `).padEnd(jo.TASK_ID_PAD_END,` `)}},Fo=class extends To{_initializeCustomProperties(e){this.append=e.append,this.priorityManager=new No,this.debouncer=new Mo,this.headerShown=!1}_getTimeTokensBarFormat(){return`{clock} {elapsed} | ${Ao.high} {high} ${Ao.medium} {medium} ${Ao.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,Do(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=Po.formatTitle(t,e),i=Po.formatPriority(n),a=Po.formatTaskId(e);Oo(this.multibar,` ${a} | ${i} | {title}`,{title:r}),ko(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 Io(e={}){return new Fo(e)}async function Lo(e,t,n){let r=Ro(e,t,n);await Bo(e,n,r.estimatedInputTokens);let i=await Vo(e,t,e.streamingTimeout),{progressTracker:a,priorityMap:o}=await Ho(e,n),s=await Uo(i.mainResult,e,t,n,a,o,r.defaultPriority,r.estimatedInputTokens,r.logger);if(zo(s),s.usage&&e.projectRoot){let{logAiUsage:t}=await import(`./ai-services-unified-TeIK2DoX.js`),{getUserId:n}=await import(`./config-manager-C8-BTReQ.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 $o(s,i,r.estimatedInputTokens,a)}function Ro(e,t,n){let{systemPrompt:r,userPrompt:i}=t;return{logger:new ka(e.mcpLog,e.reportProgress),estimatedInputTokens:Ka(r+i),defaultPriority:ue(e.projectRoot)||`medium`}}function zo(e){if(e.parsedTasks.length===0)throw Error(`No tasks were generated from the PRD`)}async function Bo(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 Vo(e,n,r){let{systemPrompt:i,userPrompt:a}=n;return await wa.withTimeout(t({role:e.research?`research`:`main`,session:e.session,projectRoot:e.projectRoot,schema:Da,systemPrompt:i,prompt:a,commandName:`parse-prd`,outputType:e.isMCP?`mcp`:`cli`}),r,`Streaming operation`)}async function Ho(e,t){let n=yo(e.isMCP),r=null;if(e.outputFormat===`text`&&!e.isMCP){r=Io({numUnits:t,unitName:`task`,append:e.append});let n=e.research?Ee():xe(),i=ge(e.research?`research`:`main`);Ra({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 Uo(e,t,n,r,i,a,o,s,c){let{systemPrompt:l,userPrompt:u}=n,d={config:{...t,schema:Da},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 Wo(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 Jo(t,d)}catch(e){return c.report(`StreamObject processing failed: ${e.message}. Falling back to generateObject.`,`debug`),await Qo(d,c)}}async function Wo(e,t,n){for await(let r of e)t.lastPartialObject=r,r&&(t.estimatedOutputTokens=Ka(JSON.stringify(r))),await Go(r,t,n)}async function Go(e,t,n){if(!e?.tasks||!Array.isArray(e.tasks))return;let r=e.tasks.length;r>t.taskCount?(await Ko(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 Ko(e,t,n,r,i){for(let a=t;a<n;a++){let t=e[a]||{};t.title?await eo({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 qo(a+1,r,i)}}async function qo(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 Jo(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 Yo(n.tasks,i,a?o:r,t,a?s:null),{parsedTasks:n.tasks,estimatedOutputTokens:o,actualInputTokens:s,usage:a,usedFallback:!1}}async function Yo(e,t,n,r,i=null){let{progressTracker:a,defaultPriority:o,estimatedInputTokens:s}=r;t>0?Xo(e,a,o):await Zo(e,n,r),a.updateTokens(i||s,n,!1),a.stop()}function Xo(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 Zo(e,t,n){for(let r=0;r<e.length;r++){let i=e[r];i?.title&&await eo({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 Qo(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||Ka(JSON.stringify(r)),i=n.telemetryData?.inputTokens||e.estimatedInputTokens;e.progressTracker.updateTokens(i,t,!1)}return{parsedTasks:r.tasks,estimatedOutputTokens:n.telemetryData?.outputTokens||Ka(JSON.stringify(r)),actualInputTokens:n.telemetryData?.inputTokens,telemetryData:n.telemetryData,usedFallback:!0}}throw Error(`Failed to generate tasks using generateObject fallback`)}function $o(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 es(e,t,n){let r=new ka(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}=Ja(e.tasksPath,e.targetTag);Ya({existingTasks:i,targetTag:e.targetTag,append:e.append,force:e.force,isMCP:e.isMCP,logger:r});let o=await t(e,await $a(e,qa(e.prdPath),a),e.numTasks),s=ue(e.projectRoot)||`medium`,c=Xa(o.parsedTasks,a,i,s),l=e.append?[...i,...c]:c;return Qa(e.tasksPath,l,e.targetTag,r),await ts(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 ts(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 to({processedTasks:n,nextId:i,summary:t.summary,prdPath:e.prdPath,tasksPath:e.tasksPath,usedFallback:t.usedFallback,aiServiceResponse:o}):a||no({processedTasks:n,research:e.research,finalTasks:r,tasksPath:e.tasksPath,aiServiceResponse:o}))}async function ns(e,t,n,r={}){return es(new Oa(e,t,n,r),Lo,!0)}async function rs(e,t,n,r={}){return es(new Oa(e,t,n,r),ro,!1)}async function is(e,t,n,r={}){let i=new Oa(e,t,n,r);if(i.useStreaming)try{return await ns(e,t,n,r)}catch(a){if(a instanceof Sa||a.code===Ca.NOT_ASYNC_ITERABLE||a.code===Ca.STREAM_PROCESSING_FAILED||a.code===Ca.STREAM_NOT_ITERABLE||wa.isTimeoutError(a)){let o=new ka(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 rs(e,t,n,r)}else throw a}else return await rs(e,t,n,r)}var as=is;async function os(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}}var ss=os;function cs(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)}var ls=cs;async function us(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(!ls(s,e)){let t=`Task with ID ${e} in tag '${i}' not found or already removed.`;a.errors.push(t),a.success=!1;continue}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)}}if(a.removedTasks.length>0){let t=new Set(o.map(e=>typeof e==`string`&&e.includes(`.`)?e:parseInt(e,10)));for(let e in n[i].tasks=s,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(Fe.existsSync(n))try{Fe.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(`
|
|
760
|
+
`).start());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:Da,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&&s.succeed(`Tasks generated successfully!`),{parsedTasks:c.tasks,aiServiceResponse:t,estimatedInputTokens:o}}catch(e){throw s&&s.fail(`Error parsing PRD: ${e.message}`),e}}const[io,ao,oo]=$r,so=new Map;var co=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 lo={cli:{filled:`●`,empty:`○`},statusBar:{high:`⋮`,medium:`:`,low:`.`},mcp:{high:`🔴`,medium:`🟠`,low:`🟢`}},uo=new co(`priority`,[io,ao,oo],{[io]:V.red,[ao]:V.yellow,[oo]:B.muted});function fo(e,t){let n=lo.cli.filled,r=lo.cli.empty,i=``;for(let a=0;a<3;a++)a<e?i+=t(n):i+=B.text(r);return i}function po(e,t){return 3-t.indexOf(e)}function mo(e,t){if(so.has(e))return so.get(e);let n=t();return so.set(e,n),n}function ho(){return mo(`mcp-priority-all`,()=>({[io]:lo.mcp.high,[ao]:lo.mcp.medium,[oo]:lo.mcp.low}))}function go(){return mo(`cli-priority-all`,()=>{let e={};return uo.levels.forEach(t=>{e[t]=fo(po(t,uo.levels),uo.getColor(t))}),e})}function _o(){return mo(`statusbar-priority-all`,()=>{let e={};return uo.levels.forEach((t,n)=>{let r=n===0?lo.statusBar.high:n===1?lo.statusBar.medium:lo.statusBar.low;e[t]=uo.getColor(t)(r)}),e})}function vo(){return{[io]:uo.colors[io],[ao]:uo.colors[ao],[oo]:uo.colors[oo]}}function yo(e=!1){return e?ho():go()}function bo(e,t=!1){let n=yo(t);return n[e]||n[ao]}new co(`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 xo={clearOnComplete:!1,stopOnComplete:!0,hideCursor:!0,barsize:40},So={shades_classic:qe.Presets.shades_classic,shades_grey:qe.Presets.shades_grey,rect:qe.Presets.rect,legacy:qe.Presets.legacy},Co=new class{constructor(e={},t=So.shades_classic){this.defaultOptions={...xo,...e},this.defaultPreset=t}createSingleBar(e={},t=null){let n=this._mergeConfig(e),r=t||this.defaultPreset;return new qe.SingleBar(n,r)}createMultiBar(e={},t=null){let n=this._mergeConfig(e),r=t||this.defaultPreset;return new qe.MultiBar(n,r)}_mergeConfig(e){return{...this.defaultOptions,...e}}setDefaultOptions(e){this.defaultOptions={...this.defaultOptions,...e}}setDefaultPreset(e){this.defaultPreset=e}};function wo(e={}){return Co.createMultiBar(e)}var To=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=wo(),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(){}},Eo=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 Do(e,t,n){new Eo(e).createHeader(t,n)}function Oo(e,t,n){new Eo(e).createRow(t,n)}function ko(e,t){new Eo(e).createBorder(t)}go();const Ao=_o();vo();const jo={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 Mo=class{constructor(e=jo.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}},No=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():jo.DEFAULT_PRIORITY;return jo.VALID_PRIORITIES.includes(t)?t:jo.DEFAULT_PRIORITY}getCounts(){return{...this.priorities}}},Po=class{static formatTitle(e,t){return e?e.length>jo.MAX_TITLE_LENGTH?e.substring(0,jo.TRUNCATED_LENGTH)+`...`:e:`Task ${t}`}static formatPriority(e){return bo(e,!1).padEnd(jo.PRIORITY_PAD_END,` `)}static formatTaskId(e){return e.toString().padStart(jo.TASK_ID_PAD_START,` `).padEnd(jo.TASK_ID_PAD_END,` `)}},Fo=class extends To{_initializeCustomProperties(e){this.append=e.append,this.priorityManager=new No,this.debouncer=new Mo,this.headerShown=!1}_getTimeTokensBarFormat(){return`{clock} {elapsed} | ${Ao.high} {high} ${Ao.medium} {medium} ${Ao.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,Do(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=Po.formatTitle(t,e),i=Po.formatPriority(n),a=Po.formatTaskId(e);Oo(this.multibar,` ${a} | ${i} | {title}`,{title:r}),ko(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 Io(e={}){return new Fo(e)}async function Lo(e,t,n){let r=Ro(e,t,n);await Bo(e,n,r.estimatedInputTokens);let i=await Vo(e,t,e.streamingTimeout),{progressTracker:a,priorityMap:o}=await Ho(e,n),s=await Uo(i.mainResult,e,t,n,a,o,r.defaultPriority,r.estimatedInputTokens,r.logger);if(zo(s),s.usage&&e.projectRoot){let{logAiUsage:t}=await import(`./ai-services-unified-aOUSTEmw.js`),{getUserId:n}=await import(`./config-manager-ej5JKm18.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 $o(s,i,r.estimatedInputTokens,a)}function Ro(e,t,n){let{systemPrompt:r,userPrompt:i}=t;return{logger:new ka(e.mcpLog,e.reportProgress),estimatedInputTokens:Ka(r+i),defaultPriority:ue(e.projectRoot)||`medium`}}function zo(e){if(e.parsedTasks.length===0)throw Error(`No tasks were generated from the PRD`)}async function Bo(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 Vo(e,n,r){let{systemPrompt:i,userPrompt:a}=n;return await wa.withTimeout(t({role:e.research?`research`:`main`,session:e.session,projectRoot:e.projectRoot,schema:Da,systemPrompt:i,prompt:a,commandName:`parse-prd`,outputType:e.isMCP?`mcp`:`cli`}),r,`Streaming operation`)}async function Ho(e,t){let n=yo(e.isMCP),r=null;if(e.outputFormat===`text`&&!e.isMCP){r=Io({numUnits:t,unitName:`task`,append:e.append});let n=e.research?Ee():xe(),i=ge(e.research?`research`:`main`);Ra({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 Uo(e,t,n,r,i,a,o,s,c){let{systemPrompt:l,userPrompt:u}=n,d={config:{...t,schema:Da},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 Wo(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 Jo(t,d)}catch(e){return c.report(`StreamObject processing failed: ${e.message}. Falling back to generateObject.`,`debug`),await Qo(d,c)}}async function Wo(e,t,n){for await(let r of e)t.lastPartialObject=r,r&&(t.estimatedOutputTokens=Ka(JSON.stringify(r))),await Go(r,t,n)}async function Go(e,t,n){if(!e?.tasks||!Array.isArray(e.tasks))return;let r=e.tasks.length;r>t.taskCount?(await Ko(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 Ko(e,t,n,r,i){for(let a=t;a<n;a++){let t=e[a]||{};t.title?await eo({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 qo(a+1,r,i)}}async function qo(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 Jo(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 Yo(n.tasks,i,a?o:r,t,a?s:null),{parsedTasks:n.tasks,estimatedOutputTokens:o,actualInputTokens:s,usage:a,usedFallback:!1}}async function Yo(e,t,n,r,i=null){let{progressTracker:a,defaultPriority:o,estimatedInputTokens:s}=r;t>0?Xo(e,a,o):await Zo(e,n,r),a.updateTokens(i||s,n,!1),a.stop()}function Xo(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 Zo(e,t,n){for(let r=0;r<e.length;r++){let i=e[r];i?.title&&await eo({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 Qo(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||Ka(JSON.stringify(r)),i=n.telemetryData?.inputTokens||e.estimatedInputTokens;e.progressTracker.updateTokens(i,t,!1)}return{parsedTasks:r.tasks,estimatedOutputTokens:n.telemetryData?.outputTokens||Ka(JSON.stringify(r)),actualInputTokens:n.telemetryData?.inputTokens,telemetryData:n.telemetryData,usedFallback:!0}}throw Error(`Failed to generate tasks using generateObject fallback`)}function $o(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 es(e,t,n){let r=new ka(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}=Ja(e.tasksPath,e.targetTag);Ya({existingTasks:i,targetTag:e.targetTag,append:e.append,force:e.force,isMCP:e.isMCP,logger:r});let o=await t(e,await $a(e,qa(e.prdPath),a),e.numTasks),s=ue(e.projectRoot)||`medium`,c=Xa(o.parsedTasks,a,i,s),l=e.append?[...i,...c]:c;return Qa(e.tasksPath,l,e.targetTag,r),await ts(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 ts(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 to({processedTasks:n,nextId:i,summary:t.summary,prdPath:e.prdPath,tasksPath:e.tasksPath,usedFallback:t.usedFallback,aiServiceResponse:o}):a||no({processedTasks:n,research:e.research,finalTasks:r,tasksPath:e.tasksPath,aiServiceResponse:o}))}async function ns(e,t,n,r={}){return es(new Oa(e,t,n,r),Lo,!0)}async function rs(e,t,n,r={}){return es(new Oa(e,t,n,r),ro,!1)}async function is(e,t,n,r={}){let i=new Oa(e,t,n,r);if(i.useStreaming)try{return await ns(e,t,n,r)}catch(a){if(a instanceof Sa||a.code===Ca.NOT_ASYNC_ITERABLE||a.code===Ca.STREAM_PROCESSING_FAILED||a.code===Ca.STREAM_NOT_ITERABLE||wa.isTimeoutError(a)){let o=new ka(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 rs(e,t,n,r)}else throw a}else return await rs(e,t,n,r)}var as=is;async function os(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}}var ss=os;function cs(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)}var ls=cs;async function us(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(!ls(s,e)){let t=`Task with ID ${e} in tag '${i}' not found or already removed.`;a.errors.push(t),a.success=!1;continue}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)}}if(a.removedTasks.length>0){let t=new Set(o.map(e=>typeof e==`string`&&e.includes(`.`)?e:parseInt(e,10)));for(let e in n[i].tasks=s,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(Fe.existsSync(n))try{Fe.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(`
|
|
761
761
|
`),u=a.errors.join(`
|
|
762
762
|
`);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:[]}}}var ds=us;Be.use(Ve({code:e=>e.split(`
|
|
763
763
|
`).map(e=>` `+V.cyan(e)).join(`
|
|
@@ -775,9 +775,9 @@ ${V.cyan(`1.`)} Run ${V.yellow(`taskgraph list`)} to view all tasks\n${V.cyan(`2
|
|
|
775
775
|
`);if(r.push(V.cyan(`Prompts: `)+V.yellow(i.toLocaleString())+B.muted(` (generated)`)+`
|
|
776
776
|
`+a),r.length>0){let e=G(r.join(`
|
|
777
777
|
|
|
778
|
-
`),{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(e)}}async function ms(e,t,n,r,i,a,o){let s=!1;try{let{readJSON:c}=await import(`./utils-
|
|
778
|
+
`),{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(e)}}async function ms(e,t,n,r,i,a,o){let s=!1;try{let{readJSON:c}=await import(`./utils-CS74XlwU.js`);(await import(`./update-task-by-id-CDNLHmUN.js`)).default;let{updateSubtaskById:l}=await import(`./update-subtask-by-id-Etpq966C.js`),u=[{question:a,answer:o,type:`initial`,timestamp:new Date().toISOString()}];for(;;){let{action:a}=await Je.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 gs(u,r,t,i);continue}if(a===`save`){await hs(u,r,t,i)&&(s=!0);continue}if(a===`followup`){let{followUpQuery:r}=await Je.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(`
|
|
779
779
|
`+B.muted(`─`.repeat(60))+`
|
|
780
|
-
`);let i=ys(u),a={...e,taskIds:[],customContext:i+(e.customContext?`\n\n--- Original Context ---\n${e.customContext}`:``)},o=await fs(r.trim(),a,t,n,!1);u.push({question:r.trim(),answer:o.result,type:`followup`,timestamp:new Date().toISOString()})}}}catch(e){i.debug(`Follow-up questions not available: ${e.message}`)}return{interactiveSaveOccurred:s}}async function hs(e,t,n,r){try{let{readJSON:r}=await import(`./utils-
|
|
780
|
+
`);let i=ys(u),a={...e,taskIds:[],customContext:i+(e.customContext?`\n\n--- Original Context ---\n${e.customContext}`:``)},o=await fs(r.trim(),a,t,n,!1);u.push({question:r.trim(),answer:o.result,type:`followup`,timestamp:new Date().toISOString()})}}}catch(e){i.debug(`Follow-up questions not available: ${e.message}`)}return{interactiveSaveOccurred:s}}async function hs(e,t,n,r){try{let{readJSON:r}=await import(`./utils-CS74XlwU.js`),i=(await import(`./update-task-by-id-CDNLHmUN.js`)).default,{updateSubtaskById:a}=await import(`./update-subtask-by-id-Etpq966C.js`),{taskId:o}=await Je.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=vs(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 gs(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=`${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=_s(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 _s(e,t){let n=new Date().toISOString(),r=`---
|
|
781
781
|
title: Research Session
|
|
782
782
|
query: "${t}"
|
|
783
783
|
date: ${new Date().toLocaleDateString()}
|
|
@@ -879,7 +879,7 @@ From: ${V.yellow(n)}\nTo: ${V.green(r)}`,{padding:1,borderColor:`green`,border
|
|
|
879
879
|
`+B.text(w),{padding:1,borderColor:`green`,borderStyle:`round`}))),o===`text`&&T.telemetryData&&cc(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(`
|
|
880
880
|
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(`
|
|
881
881
|
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(`
|
|
882
|
-
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}}var Ls=Is;async function Rs(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}=Ui(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(`
|
|
882
|
+
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}}var Ls=Is;async function Rs(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}=Ui(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.`)+`
|
|
883
883
|
|
|
884
884
|
`+B.text(`Completed tasks are locked to maintain consistency. To modify a completed task, you must first:`)+`
|
|
885
885
|
`+B.text(`1. Change its status to "pending" or "in-progress"`)+`
|