taskgraph-ai 0.54.13 → 0.54.22

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,468 +0,0 @@
1
- import{t as e}from"./rolldown-runtime-BxhE39jg.js";import{C as t,I as n,L as r,M as i,R as a,S as o,T as s,a as c,c as l,d as u,f as d,i as f,n as p,o as m,r as h,s as g,t as ee,w as _,x as te,z as ne}from"./src-Cs4ilbQ-.js";import{$ as v,B as re,P as ie,T as ae,X as y,Z as oe,_t as b,a as se,d as ce,dt as le,ft as ue,gt as de,ht as fe,it as x,j as pe,m as me,mt as he,n as ge,p as _e,pt as S,tt as ve,u as ye,v as be,y as xe}from"./config-manager-DIET_FiX.js";import C from"chalk";import w,{resolve as Se}from"node:path";import T from"node:fs";import{stripVTControlCharacters as Ce}from"node:util";import we from"path";import{spawn as Te}from"child_process";import Ee from"node:os";import E from"fs";import{Argument as De,Command as D}from"commander";import Oe from"figlet";import ke from"gradient-string";import Ae from"terminal-link";import O from"boxen";import{Marked as je,marked as Me}from"marked";import{markedTerminal as Ne}from"marked-terminal";import Pe from"turndown";import Fe from"cli-table3";import Ie from"ora";import k from"process";import A from"inquirer";const Le={done:{color:C.green,icon:`✓`,tableIcon:`✓`},pending:{color:C.yellow,icon:`○`,tableIcon:`○`},"in-progress":{color:b.active,icon:`▶`,tableIcon:`▶`},deferred:{color:b.muted,icon:`–`,tableIcon:`–`},review:{color:C.magenta,icon:`?`,tableIcon:`?`},cancelled:{color:b.muted,icon:`x`,tableIcon:`x`},blocked:{color:C.red,icon:`!`,tableIcon:`!`},completed:{color:C.green,icon:`✓`,tableIcon:`✓`}};function j(e){let t=Le[e];return t?t.color(t.icon):C.red(`X`)}function M(e,t=!1){let n=Le[e]||{color:C.red,icon:`X`,tableIcon:`X`},r=t?n.tableIcon:n.icon;return n.color(`${r} ${e}`)}function N(e=.9,t=40){let n=process.stdout.columns||80;return Math.max(Math.floor(n*e),t)}function P(){let e=process.stdout.columns;return e?Math.floor(e*.95):100}function Re(e,t,n=20){let r=e=>e.reduce((e,t)=>e+(t.width===`flex`?n:t.width),0)+e.length+1,i=[...t],a=[],o=t.filter(e=>e.dropOrder!==void 0).sort((e,t)=>(e.dropOrder??0)-(t.dropOrder??0));for(let t of o){if(r(i)<=e)break;i=i.filter(e=>e!==t),a.push(t.key)}let s=i.reduce((e,t)=>e+(t.width===`flex`?0:t.width),0),c=Math.max(n,e-s-i.length-1);return{keys:i.map(e=>e.key),widths:i.map(e=>e.width===`flex`?c:e.width),hidden:a}}function F(e,t){return e.length<=t?e:e.substring(0,t-3)+`...`}function ze(e,t,n=30){if(t===0)return b.muted(`No tasks`);let r=Math.round(e/t*100),i=Math.round(e/t*n),a=n-i;return`${C.green(`█`).repeat(i)+b.muted(`░`).repeat(a)} ${C.cyan(`${r}%`)} (${e}/${t})`}const Be=e=>e.replace(/\x1b\[[0-9;]*m/g,``).length,Ve=e=>b.brand(e),He=e=>e.length<2?e.join(``):`${e.slice(0,-1).join(`, `)} and ${e[e.length-1]}`,Ue=(e,t)=>t?`${e} (${t})`:e;function We(e){return e.status===`done`||e.status===`completed`?[`Already done.`]:e.status===`cancelled`?[`Cancelled.`]:e.status===`pending`?[`Not blocked. Start it with: ${Ve(`taskgraph set-status --id=${e.id} --status=in-progress`)}`]:[`Not blocked by any dependencies (status: ${e.status}).`]}function Ge(e,t={}){let n=t.width??100,r=[],i=e=>{if(e.repeated)return`shown above`;let t={ready:`ready to start`,stalled:`${e.status}, needs a decision`,missing:`missing`,cycle:`loops back`};return e.kind?t[e.kind]:``},a=(e,t)=>{let r=`${t}${e.kind===`missing`?C.yellow(`⚠`):j(e.status)} ${b.brand(e.id)} `,a=i(e)?b.muted(` ← ${i(e)}`):``;return r+F(e.kind===`missing`?`no such task`:e.title??``,Math.max(12,n-Be(r)-Be(a)))+a},o=(e,t,n)=>{r.push(a(e,t+b.muted(n?`└─ `:`├─ `)));let i=t+b.muted(n?` `:`│ `);e.blockers.forEach((t,n)=>o(t,i,n===e.blockers.length-1))};if(r.push(`${j(e.status)} ${b.brand(e.id)} ${F(e.title,Math.max(12,n-e.id.length-4))}`),!e.blocked)return r.push(...We(e)),r;r.push(`Blocked by:`),e.blockers.forEach((t,n)=>o(t,``,n===e.blockers.length-1));let s=Ke(e.rootCauses);return s.length&&r.push(``,`To unblock:`,...s.map(e=>` ${e}`)),r}function Ke(e){let t=[],n=e.filter(e=>e.kind===`ready`);n.length&&t.push(`Do ${He(n.map(e=>Ue(e.id,e.title)))}: nothing else stands in ${n.length>1?`their`:`its`} way.`);for(let n of e)if(n.kind===`stalled`)t.push(`${n.id} is ${n.status}. Reopen it with: ${Ve(`taskgraph set-status --id=${n.id} --status=pending`)}`);else if(n.kind===`missing`){let e=(n.listedBy??[]).map(e=>Ve(`taskgraph remove-dependency --id=${e} --depends-on=${n.id}`));t.push(`${n.id} is not a task. Remove it with: ${He(e)}`)}else if(n.kind===`cycle`){let e=(n.edges??[]).map(e=>Ve(`taskgraph remove-dependency --id=${e.from} --depends-on=${e.to}`)),r=n.cycle??[n.id];t.push(r.length===1?`${n.id} depends on itself. Remove it with: ${He(e)}`:`${r.join(`, `)} depend on each other. Break the loop with: ${He(e)}`)}return t}function I(e,t,n){return(n?.color?C[n.color]:C.cyan)(Ae(e,t,{fallback:(e,t)=>n?.textOnlyFallback?e:`${e} (${t})`}))}function qe(e,t){return I(e,e,t)}function Je(e,t){return I(e,t,{color:`cyan`})}function Ye(){return Ae.isSupported}const Xe=ke(ue);function Ze(){return process.env.TM_HIDE_BANNER===`true`}function Qe(){return process.stdout.columns||80}function $e(e={}){if(Ze())return;let{version:t}=e;try{let e=Oe.textSync(`TaskGraph`,{font:`Standard`,horizontalLayout:`default`,verticalLayout:`default`});console.log(Xe(e))}catch{console.log(Xe(`=== TaskGraph ===`))}let n=`x.com/stephennmiller_`,r=I(n,`https://x.com/stephennmiller_`,{textOnlyFallback:!0}),i=C.dim(`by `)+C.cyan(r),a=t?t.replace(/^v/,``):``,o=`https://github.com/stephennmiller/taskgraph-ai/releases/tag/taskgraph-ai%40${a}`,s=t?I(`v${a}`,o,{color:`dim`,textOnlyFallback:!0}):``;if(s){let e=`by ${n}`.length,t=a.length+1,r=Qe()-e-t-1;r>=2?console.log(i+` `.repeat(r)+s):(console.log(i),console.log(s))}else console.log(i);console.log(``)}function et(){if(Ze())return;try{let e=Oe.textSync(`TaskGraph`,{font:`Standard`,horizontalLayout:`default`,verticalLayout:`default`});console.log(Xe(e))}catch{console.log(Xe(`=== TaskGraph ===`))}let e=I(`x.com/stephennmiller_`,`https://x.com/stephennmiller_`,{textOnlyFallback:!0});console.log(C.dim(`by `)+C.cyan(e)),console.log(``)}function tt(e){let{header:t,body:n,callToAction:r,footer:i,level:a=`warn`}=e,o=a===`info`?b.heading:C.yellow.bold,s=a===`info`?S:`yellow`,c=[o(t),...n.map(e=>b.text(e))];r&&r.label&&r.action&&c.push(C.cyan(r.label)+`
2
- `+b.brand.underline(r.action)),i&&c.push(b.muted(i));let l=c.join(`
3
-
4
- `);return O(l,{padding:1,borderColor:s,borderStyle:`round`,margin:{top:1,bottom:1}})}const L={done:C.green(`█`),cancelled:b.muted(`─`),deferred:b.muted(`─`),inProgress:b.active(`▓`),review:C.magenta(`▒`),pending:C.yellow(`░`),blocked:C.red(`!`)};function nt(e,t=30,n){if(!n){let n=Math.round(e/100*t),r=t-n;return L.done.repeat(n)+b.muted(`░`).repeat(r)}let r=``,i=0,a=[[n.done,L.done],[n.cancelled,L.cancelled],[n.deferred,L.deferred],[n[`in-progress`],L.inProgress],[n.review,L.review],[n.pending,L.pending],[n.blocked,L.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+=L.pending.repeat(t-i)),r}function rt(e){let t={total:e.length,done:0,inProgress:0,pending:0,blocked:0,deferred:0,cancelled:0,review:0,completionPercentage:0,completedCount:0};return e.forEach(e=>{switch(e.status){case`done`:t.done++;break;case`in-progress`:t.inProgress++;break;case`pending`:t.pending++;break;case`blocked`:t.blocked++;break;case`deferred`:t.deferred++;break;case`cancelled`:t.cancelled++;break;case`review`:t.review=(t.review||0)+1}}),t.completedCount=e.filter(e=>_(e.status)).length,t.completionPercentage=t.total>0?Math.round(t.completedCount/t.total*100):0,t}function it(e){let t={total:0,done:0,inProgress:0,pending:0,blocked:0,deferred:0,cancelled:0,review:0,completionPercentage:0,completedCount:0},n=[];return e.forEach(e=>{e.subtasks&&e.subtasks.length>0&&e.subtasks.forEach(e=>{switch(t.total++,n.push(e),e.status){case`done`:t.done++;break;case`in-progress`:t.inProgress++;break;case`pending`:t.pending++;break;case`blocked`:t.blocked++;break;case`deferred`:t.deferred++;break;case`cancelled`:t.cancelled++;break;case`review`:t.review=(t.review||0)+1}})}),t.completedCount=n.filter(e=>_(e.status)).length,t.completionPercentage=t.total>0?Math.round(t.completedCount/t.total*100):0,t}function at(e){let t=new Set(e.filter(e=>_(e.status)).map(e=>e.id)),n=e.filter(e=>!_(e.status)&&(!e.dependencies||e.dependencies.length===0)).length,r=e.filter(e=>!_(e.status)&&e.dependencies&&e.dependencies.length>0&&e.dependencies.every(e=>t.has(e))).length,i=e.filter(e=>!_(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 ot(e){let t={critical:0,high:0,medium:0,low:0};return e.forEach(e=>{let n=e.priority||`medium`;t[n]++}),t}function st(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 ct(e,t=!1,n=!1){let r=[];t?r.push(`${L.done} Completed: ${C.green(`${e.completedCount}/${e.total}`)}`):r.push(`${L.done} Done: ${C.green(e.done)}`),r.push(`${L.cancelled} Cancelled: ${b.muted(e.cancelled)}`),r.push(`${L.deferred} Deferred: ${b.muted(e.deferred)}`);let i=e=>n?e.slice(0,2).join(` `)+(e.length>2?`
5
- `+e.slice(2).join(` `):``):e.join(` `),a=i(r);return r.length=0,r.push(`${L.inProgress} In Progress: ${b.active(e.inProgress)}`),r.push(`${L.review} Review: ${C.magenta(e.review||0)}`),r.push(`${L.pending} Pending: ${C.yellow(e.pending)}`),r.push(`${L.blocked} Blocked: ${C.red(e.blocked)}`),a+`
6
- `+i(r)}function lt(e,t,n,r=!1){let i=st(e),a=st(t),o=r?16:30,s=nt(e.completionPercentage,o,i),c=nt(t.completionPercentage,o,a),l=`${e.completionPercentage}% ${e.completedCount}/${e.total}`,u=`${t.completionPercentage}% ${t.completedCount}/${t.total}`;return C.bold(`Project Dashboard`)+`
7
- Tasks Progress: ${s} ${C.yellow(l)}\n`+ct(e,!1,r)+`
8
-
9
- Subtasks Progress: ${c} ${C.cyan(u)}\n`+ct(t,!0,r)+`
10
-
11
- `+C.cyan.bold(`Priority Breakdown:`)+`
12
- ${C.red(`•`)} ${b.text(`High priority:`)} ${n.high}\n${C.yellow(`•`)} ${b.text(`Medium priority:`)} ${n.medium}\n${C.green(`•`)} ${b.text(`Low priority:`)} ${n.low}`}function ut(e,t){return C.bold(`Dependency Status & Next Task`)+`
13
- `+C.cyan.bold(`Dependency Metrics:`)+`
14
- ${C.green(`•`)} ${b.text(`Tasks with no dependencies:`)} ${e.tasksWithNoDeps}\n${C.green(`•`)} ${b.text(`Tasks ready to work on:`)} ${e.tasksReadyToWork}\n${C.yellow(`•`)} ${b.text(`Tasks blocked by dependencies:`)} ${e.tasksBlockedByDeps}\n${b.accent(`•`)} ${b.text(`Most depended-on task:`)} ${e.mostDependedOnTaskId?C.cyan(`#${e.mostDependedOnTaskId} (${e.mostDependedOnCount} dependents)`):b.muted(`None`)}\n${b.brand(`•`)} ${b.text(`Avg dependencies per task:`)} ${e.avgDependenciesPerTask.toFixed(1)}\n\n`+C.cyan.bold(`Next Task:`)+`
15
- ID: ${t?C.cyan(String(t.id)):b.muted(`N/A`)} - ${t?C.bold(t.title):C.yellow(`No task available`)}\nPriority: ${t?.priority||b.muted(`N/A`)} Dependencies: ${t?.dependencies?.length?C.cyan(t.dependencies.join(`, `)):b.muted(`None`)}\nComplexity: ${t?.complexity===void 0?b.muted(`N/A`):B(t.complexity)}`}function dt(e,t,n,r,i){let a=process.stdout.columns||80,o=a>=120,s=Math.floor(a/2),c=s-4,l=lt(e,t,n,(o?c:a)-8<60),u=ut(r,i);if(o){let e=O(l,{padding:1,borderColor:S,borderStyle:`round`,width:c,dimBorder:!1}),t=O(u,{padding:1,borderColor:S,borderStyle:`round`,width:c,dimBorder:!1}),n=e.split(`
16
- `),r=t.split(`
17
- `),i=Math.max(n.length,r.length),a=[];for(let e=0;e<i;e++){let t=e<n.length?n[e]:``,i=e<r.length?r[e]:``,o=t.padEnd(s,` `);a.push(o+i)}console.log(a.join(`
18
- `))}else{let e=O(l,{padding:1,borderColor:S,borderStyle:`round`,margin:{top:0,bottom:1}}),t=O(u,{padding:1,borderColor:S,borderStyle:`round`,margin:{top:0,bottom:1}});console.log(e),console.log(t)}}const ft=[[`done`,`done`],[`in-progress`,`in progress`],[`review`,`review`],[`pending`,`pending`],[`blocked`,`blocked`],[`deferred`,`deferred`],[`cancelled`,`cancelled`]],pt=e=>e.replace(/\x1b\[[0-9;]*m/g,``).length;function mt(e,t){let n=`Critical path:`,r=[],i=`${n} ${e[0]}`;for(let n of e.slice(1)){let e=` → ${n}`;i.length+e.length>t-2?(r.push(`${i} →`),i=` ${n}`):i+=e}return r.push(i),r.map((e,t)=>t===0?b.muted(n)+e.slice(14):e)}function ht(e,t={}){let n=t.width??100,r=t.nextId?String(t.nextId):null,i=r?.split(`.`)[0],a=[],o=/* @__PURE__ */ new Set,s=new Map(e.bottlenecks.map(e=>[e.id,e.blocks])),c=new Set(e.criticalPath),l=!1,u=!1,d=(e,t,a)=>{o.add(e.status);let d=e.id===i,f=t=>e.inferred.includes(t),p=e=>f(e)?(u=!0,`${e}*`):e,m=[];e.alsoNeeds.length&&m.push(`needs ${e.alsoNeeds.map(p).join(`, `)}`);let h=s.get(e.id);h!==void 0&&m.push(`blocks ${h}`);let g=c.has(e.id);g&&(l=!0);let ee=a!==void 0&&f(a);ee&&(u=!0);let _=ee?`${b.brand(e.id)}${b.muted(`*`)}`:b.brand(e.id),te=e.missing.length?C.yellow(` · missing ${e.missing.join(`, `)}`):``,ne=(m.length?b.muted(` · ${m.join(` · `)}`):``)+te+(g?b.brand(` ◆`):``)+(d?b.brand.bold(r===i?` ← next`:` ← next: ${r}`):``),v=`${t}${j(e.status)} ${_} `,re=Math.max(12,n-pt(v)-pt(ne)),ie=F(e.title,re);return v+(d||e.status===`in-progress`?C.bold(ie):e.status===`done`||e.status===`cancelled`?b.muted(ie):ie)+ne},f=(e,t,n,r)=>{a.push(d(e,n+b.muted(r?`└─ `:`├─ `),t.id));let i=n+b.muted(r?` `:`│ `);e.children.forEach((t,n)=>f(t,e,i,n===e.children.length-1))};if(e.roots.forEach((t,n)=>{let r=e.roots[n-1];r&&(r.children.length||t.children.length)&&a.push(``),a.push(d(t,``)),t.children.forEach((e,n)=>f(e,t,``,n===t.children.length-1))}),e.cyclic.length){a.push(``,C.yellow(`⚠ These tasks depend on each other in a loop:`));for(let t of e.cyclic)a.push(d(t,` `));let t=new Set(e.cyclic.map(e=>e.id)),n=e.cyclic[0],r=n.alsoNeeds.find(e=>t.has(e));r&&a.push(b.muted(` Break it with `)+b.brand(`taskgraph remove-dependency --id=${n.id} --depends-on=${r}`))}if(e.bottlenecks.length){let t=Math.max(...e.bottlenecks.map(e=>e.id.length)),r=e.bottlenecks.map(e=>`blocks ${e.blocks}`),i=Math.max(...r.map(e=>e.length)),o=Math.max(12,n-(2+t+2+i+2));a.push(``,b.muted(`Bottlenecks`)),e.bottlenecks.forEach((e,n)=>{a.push(` ${b.brand(e.id.padEnd(t))} ${C.yellow(r[n].padEnd(i))} ${F(e.title,o)}`)})}e.criticalPath.length&&a.push(``,...mt(e.criticalPath,n));let p=ft.filter(([e])=>o.has(e)).map(([e,t])=>`${j(e)} ${b.muted(t)}`).join(` `);p&&a.push(``,p);let m=[l?`◆ critical path`:``,u?`* dependency inferred by AI`:``].filter(Boolean);return m.length&&a.push(b.muted(m.join(` `))),a}function gt(e={}){let{tag:t}=e;t&&console.log(C.dim(`[tag] `)+C.cyan(t))}const _t=new Pe({headingStyle:`atx`,codeBlockStyle:`fenced`,bulletListMarker:`-`});Me.use(Ne({code:e=>e.split(`
19
- `).map(e=>` `+C.cyan(e)).join(`
20
- `),blockquote:b.muted.italic,html:b.muted,heading:b.text.bold,hr:b.muted,listitem:b.text,paragraph:b.text,strong:b.text.bold,em:b.text.italic,codespan:C.cyan,del:C.dim.strikethrough,link:b.brand,href:b.brand.underline,showSectionPrefix:!1,unescape:!0,emoji:!1,tab:4,width:120})),Me.setOptions({breaks:!0,gfm:!0});function R(e){if(!e)return``;let t=e.replace(/\\\\/g,`\\`).replace(/\\n/g,`
21
- `).replace(/\\t/g,` `).replace(/\\"/g,`"`);/<[^>]+>/.test(t)&&(t=_t.turndown(t));let n=Me(t);return typeof n==`string`?n.trim():t}function vt(e,t,n){let r=String(e),i=r.includes(`.`),a=i?{command:`taskgraph update-subtask --id=${r} --prompt="..."`,description:`to log progress notes`}:{command:`taskgraph update-task --id=${r} --prompt="..."`,description:`to update details`},o=!i&&!n?[{command:`taskgraph expand --id=${r}`,description:`to break down into subtasks`}]:[];switch(t){case`in-progress`:return[a,{command:`taskgraph set-status --id=${r} --status=done`,description:`when it is finished`},...o];case`review`:return[{command:`taskgraph set-status --id=${r} --status=done`,description:`once the review passes`},{command:`taskgraph set-status --id=${r} --status=in-progress`,description:`if it needs more work`}];case`done`:case`completed`:case`cancelled`:return[{command:`taskgraph next`,description:`to find the next task to work on`}];case`blocked`:case`deferred`:return[{command:`taskgraph set-status --id=${r} --status=pending`,description:`when it is ready to pick up again`},a];default:return[{command:`taskgraph set-status --id=${r} --status=in-progress`,description:`to start working`},...o,a]}}function yt(e){switch(e){case`create`:return C.green(`✚ CREATE`);case`modify`:return C.yellow(`✎ MODIFY`);case`reference`:return b.brand(`◇ REFER `);default:return b.muted(` FILE `)}}function bt(e){return e}function xt(e,t){console.log(O(C.bold(`Task: #${e} - ${t}`),{padding:{top:0,bottom:0,left:1,right:1},borderColor:S,borderStyle:`round`}))}function St(e,t){let n=P(),r=new Fe({head:[],style:{head:[],border:de},colWidths:Re(n,[{key:`label`,width:16},{key:`value`,width:`flex`}]).widths,wordWrap:!0}),i=e.dependencies&&e.dependencies.length>0?e.dependencies.map(e=>String(e)).join(`, `):`None`,a=t||String(e.id),o=R(e.description||``),s=e.category?`${bt(e.category)}`:b.muted(`N/A`),c=e.skills&&e.skills.length>0?e.skills.map(e=>b.accent(`[${e}]`)).join(` `):b.muted(`N/A`),l=[C.cyan(`ID:`),C.cyan(`Title:`),C.cyan(`Status:`),C.cyan(`Priority:`),C.cyan(`Dependencies:`),C.cyan(`Complexity:`),C.cyan(`Category:`),C.cyan(`Skills:`),C.cyan(`Description:`)].join(`
22
- `),u=[a,e.title,M(e.status),Zt(e.priority),i,typeof e.complexity==`number`?B(e.complexity):b.muted(`N/A`),s,c,o].join(`
23
- `);r.push([l,u]),console.log(r.toString())}function Ct(e){let t=P(),n=R(e);console.log(O(C.bold(`Implementation Details:`)+`
24
-
25
- `+n,{padding:1,borderStyle:`round`,borderColor:S,width:t}))}function wt(e){let t=P(),n=R(e);console.log(O(C.bold(`Test Strategy:`)+`
26
-
27
- `+n,{padding:1,borderStyle:`round`,borderColor:S,width:t}))}function Tt(e,t){let n=P();console.log(O(b.heading(`Subtasks`),{padding:{top:0,bottom:0,left:1,right:1},borderColor:S,borderStyle:`round`,margin:{top:1,bottom:0}}));let r=new Fe({head:[b.heading(`ID`),b.heading(`Status`),b.heading(`Title`),b.heading(`Deps`)],style:{head:[],border:de},colWidths:Re(n,[{key:`id`,width:10},{key:`status`,width:15},{key:`title`,width:`flex`},{key:`deps`,width:8}]).widths,wordWrap:!0});e.forEach(e=>{let n=t?`${t}.${e.id}`:String(e.id),i=e.dependencies&&e.dependencies.length>0?e.dependencies.join(`, `):`None`;r.push([n,M(e.status),e.title,i])}),console.log(r.toString())}function Et(e){let t=P(),n=e.map(e=>`${yt(e.action)} ${b.text(e.path)}\n ${b.muted(e.description)}`).join(`
28
-
29
- `);console.log(O(C.bold(`Files to Touch:`)+`
30
-
31
- `+n,{padding:1,borderStyle:`round`,borderColor:`yellow`,width:t}))}function Dt(e){let t=P(),n=e.map(e=>`${C.cyan.bold(e.name)} → ${b.muted(e.location)}\n ↳ ${b.text(e.usage)}`).join(`
32
-
33
- `);console.log(O(C.bold(`Leverage Existing Code:`)+`
34
-
35
- `+n,{padding:1,borderStyle:`round`,borderColor:S,width:t}))}function Ot(e){let t=P(),n=``;e.included&&(n+=C.green.bold(`✓ In Scope:
36
- `),n+=b.text(` `+e.included)),e.excluded&&(n&&(n+=`
37
-
38
- `),n+=C.red.bold(`✗ Out of Scope:
39
- `),n+=b.muted(` `+e.excluded)),console.log(O(C.bold(`Scope Boundaries:`)+`
40
-
41
- `+n,{padding:1,borderStyle:`round`,borderColor:S,width:t}))}function kt(e){let t=P(),n=e.map(e=>b.text(`☐ ${e}`)).join(`
42
- `);console.log(O(C.bold(`Acceptance Criteria:`)+`
43
-
44
- `+n,{padding:1,borderStyle:`round`,borderColor:`green`,width:t}))}function At(e){let t=P(),n=e.map(e=>C.yellow(`▸ ${e}`)).join(`
45
- `);console.log(O(C.bold(`Technical Constraints:`)+`
46
-
47
- `+n,{padding:1,borderStyle:`round`,borderColor:`red`,width:t}))}function jt(e){let t=P(),n=R(e);console.log(O(C.bold(`Implementation Approach:`)+`
48
-
49
- `+n,{padding:1,borderStyle:`round`,borderColor:S,width:t}))}function Mt(e){let t=P(),n=e.map(e=>b.text(`• ${e}`)).join(`
50
- `);console.log(O(C.bold(`Codebase Patterns:`)+`
51
-
52
- `+n,{padding:1,borderStyle:`round`,...fe,width:t}))}function Nt(e,t){let n=``;e&&(n+=b.muted(`Category: `)+C.cyan(`[${bt(e)}]`)),t&&t.length>0&&(n&&(n+=` `),n+=b.muted(`Skills: `)+t.map(e=>b.accent(`[${e}]`)).join(` `)),n&&console.log(`
53
- `+n)}function Pt(e){(e.relevantFiles||e.existingInfrastructure||e.scopeBoundaries||e.acceptanceCriteria||e.technicalConstraints||e.implementationApproach||e.codebasePatterns)&&(e.implementationApproach&&(console.log(),jt(e.implementationApproach)),e.relevantFiles&&e.relevantFiles.length>0&&(console.log(),Et(e.relevantFiles)),e.existingInfrastructure&&e.existingInfrastructure.length>0&&(console.log(),Dt(e.existingInfrastructure)),e.codebasePatterns&&e.codebasePatterns.length>0&&(console.log(),Mt(e.codebasePatterns)),e.scopeBoundaries&&(console.log(),Ot(e.scopeBoundaries)),e.technicalConstraints&&e.technicalConstraints.length>0&&(console.log(),At(e.technicalConstraints)),e.acceptanceCriteria&&e.acceptanceCriteria.length>0&&(console.log(),kt(e.acceptanceCriteria)))}function Ft(e,t,n=!1){let r=vt(e,t,n).map((e,t)=>`${C.cyan(`${t+1}.`)} Run ${C.yellow(e.command)} ${e.description}`);console.log(O(C.bold(`Suggested Actions:`)+`
54
-
55
- `+r.join(`
56
- `),{padding:1,margin:{top:1},borderStyle:`round`,borderColor:`green`,width:P()}))}function It(e,t){let{statusFilter:n,showSuggestedActions:r=!1,customHeader:i,headerColor:a=S,originalTaskId:o}=t||{};if(i?console.log(O(C.bold(i),{padding:{top:0,bottom:0,left:1,right:1},borderColor:a,borderStyle:`round`,margin:{top:1}})):xt(o||e.id,e.title),St(e,o),e.details&&(console.log(),Ct(e.details)),`testStrategy`in e&&e.testStrategy&&(console.log(),wt(e.testStrategy)),Pt(e),e.subtasks&&e.subtasks.length>0){let t=n?e.subtasks.filter(e=>e.status===n):e.subtasks;t.length===0&&n?(console.log(),console.log(b.muted(` No subtasks with status '${n}'`))):t.length>0&&(console.log(),Tt(t,e.id))}r&&(console.log(),Ft(o||e.id,e.status,!!(e.subtasks&&e.subtasks.length>0)))}function Lt(e,t){if(!e){console.log(t?C.yellow(`✓ All tasks are either completed, blocked by dependencies, or in progress.`):O(C.yellow(`No tasks found in this project.`),{padding:1,borderStyle:`round`,borderColor:`yellow`,title:`No tasks available`,titleAlignment:`center`}));return}let n=[];n.push(`${b.heading(`Next task:`)} ${C.yellow(`#${e.id}`)}${b.heading(` - ${e.title}`)}`),n.push(``);let r=[];if(e.priority){let t=e.priority===`high`?C.red:e.priority===`medium`?C.yellow:b.muted;r.push(`Priority: ${t.bold(e.priority)}`)}if(e.status){let t=e.status===`pending`?C.yellow(`○ pending`):e.status===`in-progress`?b.brand(`▶ in-progress`):b.muted(e.status);r.push(`Status: ${t}`)}n.push(r.join(` `));let i=!e.dependencies||e.dependencies.length===0?b.muted(`None`):C.cyan(e.dependencies.join(`, `));n.push(`Dependencies: ${i}`),typeof e.complexity==`number`&&n.push(`Complexity: ${B(e.complexity)}`),e.description&&(n.push(``),n.push(`Description: ${b.text(R(e.description))}`)),n.push(``);for(let t of vt(e.id,e.status,!0).slice(0,2))n.push(`${C.cyan(`Next step:`)} ${C.yellow(t.command)} ${b.muted(t.description)}`);n.push(`${C.cyan(`View details:`)} ${C.yellow(`taskgraph show ${e.id}`)}`),console.log(O(n.join(`
57
- `),{padding:1,margin:{top:1,bottom:1},borderStyle:`round`,borderColor:S,title:b.heading(`Next task`),titleAlignment:`center`,width:N(.97),fullscreen:!1}))}function Rt(e){if(`description`in e&&e.description)return e.description;if(`details`in e&&e.details)return e.details.split(`
58
- `)[0].split(`.`)[0]}const zt=[`⠋`,`⠙`,`⠹`,`⠸`,`⠼`,`⠴`,`⠦`,`⠧`,`⠇`,`⠏`];function Bt(e=C.hex(he.accent)){return{interval:80,frames:zt.map(t=>e(t))}}function z(e={}){let t=Ie({...typeof e==`string`?{text:e}:e,spinner:Bt(),color:!1}),n=e=>n=>t.stopAndPersist({symbol:e,text:n});return t.succeed=n(C.green(`✓`)),t.fail=n(C.red(`✗`)),t.warn=n(C.yellow(`⚠`)),t}function Vt(e,t=!1){let n=e?.tasks?.length??0;return t?n:Math.max(0,n-1)}function Ht(e){let t=Math.max(0,Math.floor(e/1e3));return`${Math.floor(t/60)}:${String(t%60).padStart(2,`0`)}`}function Ut(e){let t=Math.max(0,Math.round(e/1e3)),n=Math.floor(t/60),r=t%60;return n===0?`${r}s`:r?`${n}m ${r}s`:`${n}m`}function Wt(e,t){let n=e.replace(/\s+/g,` `).trim();return n.length>t?`${n.slice(0,t-1).trimEnd()}…`:n}var Gt=class{options;spinner;ticker;startedAt=0;printed=0;current;interactive;constructor(e){this.options={numTasks:e.numTasks||0,startId:e.startId??1,stream:e.stream??process.stdout,now:e.now??Date.now,prdName:e.prdName},this.interactive=!!this.options.stream.isTTY}start(){return this.startedAt=this.options.now(),this.interactive?(this.spinner=z({text:this.statusText(),stream:this.options.stream}).start(),this.ticker=setInterval(()=>this.refresh(),1e3),this.ticker.unref?.()):this.write(`${this.statusText()}\n`),this}update(e){this.current=e,this.printCompleted(Vt(e)),this.refresh()}succeed(e){e&&(this.current=e),this.printCompleted(Vt(this.current,!0));let t=this.printed,n=Ut(this.options.now()-this.startedAt),r=`${t} ${t===1?`task`:`tasks`} in ${n}`;this.stop(),this.write(`${C.green(`✓`)} ${C.bold(r)}\n`)}fail(e){this.stop(),this.write(`${C.red(`✗`)} ${e}\n`)}stop(){this.ticker&&clearInterval(this.ticker),this.ticker=void 0,this.spinner?.stop(),this.spinner=void 0}get printedCount(){return this.printed}printCompleted(e){let t=this.current?.tasks??[];for(;this.printed<e;){let e=t[this.printed],n=this.options.startId+this.printed,r=Wt(e?.title??``,Math.max(20,this.columns-7));this.persist(`${C.green(`✓`)} ${b.brand(String(n).padEnd(3))}${r}`),this.printed++}}persist(e){this.spinner?(this.spinner.clear(),this.write(`${e}\n`),this.spinner.render()):this.write(`${e}\n`)}refresh(){this.spinner&&(this.spinner.text=this.statusText())}statusText(){let{numTasks:e,prdName:t}=this.options,n=this.current?.tasks?.length??0,r;if(n===0)r=e?`Reading ${t} and planning ${e} tasks`:`Reading ${t} and planning tasks`;else{let t=e?` of ${e}`:``,i=this.current?.tasks?.[n-1]?.title;r=`Writing task ${n}${t}`;let a=this.columns-2-r.length-3-2-6;i&&a>=12&&(r+=b.muted(` · ${Wt(i,a)}`))}return`${r} ${b.muted(this.elapsed())}`}get columns(){return this.options.stream.columns||80}elapsed(){return Ht(this.options.now()-this.startedAt)}write(e){this.options.stream.write(e)}};function Kt(){let e=[`${C.cyan(`1.`)} Run ${C.yellow(`taskgraph next`)} to see what to work on next`,`${C.cyan(`2.`)} Run ${C.yellow(`taskgraph expand --id=<id>`)} to break down a task into subtasks`,`${C.cyan(`3.`)} Run ${C.yellow(`taskgraph set-status --id=<id> --status=done`)} to mark a task as complete`];console.log(O(C.bold(`Suggested Next Steps:`)+`
59
-
60
- `+e.join(`
61
- `),{padding:1,margin:{top:0,bottom:1},borderStyle:`round`,...fe,width:N(.97)}))}const qt=`tasks.json`;function Jt(e){let t=m(e);console.log(C.dim(`\nWatching ${qt} for changes...`)),console.log(b.muted(`Last synced: ${t}`)),console.log(C.dim(`Press Ctrl+C to exit`))}function Yt(e){let t=m(e);console.log(b.brand(`\nℹ ${qt} updated at ${t}`))}const Xt={critical:C.red.bold,high:C.red,medium:C.yellow,low:b.muted};function Zt(e){return(Xt[e]||b.text)(e)}function Qt(e){return e>=7?`High`:e>=4?`Medium`:`Low`}function $t(e){let t=Qt(e);return{color:t===`High`?C.red:t===`Medium`?C.yellow:C.green,label:t}}function B(e){let t=typeof e==`string`?Number(e.trim()):e;if(isNaN(t))return b.muted(`N/A`);let{color:n}=$t(t);return n(`● ${t}`)}function en(e){if(typeof e!=`number`)return b.muted(`N/A`);let{color:t,label:n}=$t(e);return t(`${e}/10 (${n})`)}const tn=(e,t)=>`${e} ${e===1?t:`${t}s`}`,nn=(e,t)=>e.length>t?`${e.slice(0,Math.max(1,t-1))}…`:e,rn=e=>[...e].sort((e,t)=>t.complexityScore-e.complexityScore);function an(e,t){let n=[],r=``;for(let i of e.split(/\s+/).filter(Boolean))r&&r.length+1+i.length>t?(n.push(r),r=i):r=r?`${r} ${i}`:i;return r&&n.push(r),n}function on(e,t){let n=rn(e),r=Math.max(...n.map(e=>String(e.taskId).length)),i=Math.max(...n.map(e=>String(e.complexityScore).length)),a=e=>e.recommendedSubtasks?tn(e.recommendedSubtasks,`subtask`):``,o=Math.max(0,...n.map(e=>a(e).length)),s=Math.max(12,Math.min(Math.max(...n.map(e=>e.taskTitle.length)),t-2-r-2-2-(i+2)-(o?o+2:0)));return n.map(e=>{let t=nn(e.taskTitle,s).padEnd(s),n=B(e.complexityScore),o=` `.repeat(i-String(e.complexityScore).length),c=a(e);return{item:e,line:` ${b.brand(String(e.taskId).padEnd(r))} ${t} ${n}${o}${c?` ${b.muted(c)}`:``}`.trimEnd(),indent:2+r+2}})}function sn(e){let t={High:0,Medium:0,Low:0};for(let n of e)t[Qt(n.complexityScore)]++;return`High ${t.High} · Medium ${t.Medium} · Low ${t.Low}`}const cn=()=>b.muted(`Run `)+b.brand(`taskgraph expand --id=<id>`)+b.muted(` or `)+b.brand(`--all`)+b.muted(` to use these recommendations`);function ln(e,t=process.stdout.columns||80){let{analyses:n,skipped:r,kept:i,reportPath:a}=e;if(n.length===0)return b.muted(`No pending tasks to analyze`);let o=[e.usedResearch?`with web research`:null,r>0?`skipped ${r} done`:null].filter(Boolean),s=[`${C.green(`✓`)} Analyzed ${tn(n.length,`task`)}${o.length?b.muted(` · ${o.join(` · `)}`):``}`,...on(n,t).map(e=>e.line)],c=i===0?``:`, with ${i} earlier ${i===1?`analysis`:`analyses`}`;return s.push(b.muted(`Saved to ${a}${c}`)),s.push(b.muted(`Next: `)+b.brand(`taskgraph expand --all`)+b.muted(`, or `)+b.brand(`taskgraph complexity-report`)+b.muted(` to see why`)),s.join(`
62
- `)}function un(e,t=process.stdout.columns||80){let n=e.complexityAnalysis??[];if(n.length===0)return b.muted(`The report has no analyzed tasks yet`);let r=new Date(e.meta.generatedAt),i=Number.isNaN(r.getTime())?null:r.toLocaleString(void 0,{month:`short`,day:`numeric`,hour:`numeric`,minute:`2-digit`}),a=[tn(n.length,`task`),sn(n),e.meta.usedResearch?`with web research`:null,i].filter(Boolean).join(` · `),o=[b.heading(`Complexity report`),b.muted(a),``];for(let e of on(n,t)){if(o.push(e.line),e.item.reasoning){let n=` `.repeat(e.indent);for(let r of an(e.item.reasoning,Math.max(20,t-e.indent)))o.push(b.muted(`${n}${r}`))}o.push(``)}return o.push(cn()),o.join(`
63
- `)}const dn=(e,t)=>Math.round(e).toLocaleString(t);function fn(e,t=`USD`,n){let r=(e,r)=>{try{return new Intl.NumberFormat(n,{style:`currency`,currency:t,...r}).format(e)}catch{return`${t} ${e.toFixed(2)}`}};return e<.01?`<${r(.01,{maximumFractionDigits:2})}`:e<1?r(e,{maximumSignificantDigits:3}):r(e,{maximumFractionDigits:2,minimumFractionDigits:2})}function pn(e,t){if(!e)return null;let n=e.inputTokens??0,r=e.outputTokens??0,i=e.totalTokens||n+r;if(!i)return null;let a=[],o=e.modelUsed;o&&a.push(o===`Multiple`?`several models`:o),a.push(`${dn(i,t)} ${i===1?`token`:`tokens`} (${dn(n,t)} in, ${dn(r,t)} out)`);let s=e.cachedInputTokens??0;return n>0&&s/n>=.01&&a.push(`${Math.round(s/n*100)}% cached`),!e.isUnknownCost&&(e.totalCost??0)>0&&a.push(`~${fn(e.totalCost,e.currency,t)}`),a.join(` · `)}const mn=e=>e.oldStatus===e.newStatus?`${M(e.newStatus)} ${b.muted(`(unchanged)`)}`:`${M(e.oldStatus)} → ${M(e.newStatus)}`;function hn(e){let t=C.green(`✓`);if(e.length===1){let[n]=e;return`${t} Task ${b.brand(n.taskId)} ${mn(n)}`}let n=Math.max(0,...e.map(e=>e.taskId.length));return[`${t} Updated ${e.length} tasks`,...e.map(e=>` ${b.brand(e.taskId.padEnd(n))} ${mn(e)}`)].join(`
64
- `)}function gn(e,t,n=process.stdout.columns||80){let r=t.length,i=r===1?`subtask`:`subtasks`,a=[`${C.green(`✓`)} Added ${r} ${i} to task ${e}`],o=t.map(t=>`${e}.${t.id}`),s=Math.max(0,...o.map(e=>e.length)),c=Math.max(10,n-s-4);return t.forEach((e,t)=>{let n=e.title.length>c?`${e.title.slice(0,c-1)}…`:e.title;a.push(` ${b.brand(o[t].padEnd(s))} ${n}`)}),a.join(`
65
- `)}const _n=`stephennmiller/taskgraph-ai`,vn=`taskgraph@taskgraph`,yn=e=>e.replace(/`([^`]+)`/g,(e,t)=>b.brand(t));function bn(e){let t=Math.max(0,...e.map(e=>e.path.length));return e.map(e=>` ${e.path.padEnd(t)} ${b.muted(yn(e.note))}`)}function xn(e){let t=[];return e.claudeCode&&t.push([`Add the slash commands in Claude Code:`,b.brand(`/plugin marketplace add ${_n}`),b.brand(`/plugin install ${vn}`)]),e.alreadySetUp||t.push([`Write a PRD in .taskgraph/docs/prd.md`,b.muted(`Templates are in .taskgraph/templates/`)],[`Turn it into tasks: ${b.brand(`taskgraph parse-prd`)}`],[`Start the first task: ${b.brand(`taskgraph next`)}`]),t}function Sn(e){let t=C.green(`✓`),n=[];e.alreadySetUp?e.changes.length>0?n.push(`${t} Updated TaskGraph in ${e.folder}`):(n.push(`${t} TaskGraph is already set up in ${e.folder}`),n.push(b.muted(yn(" Run `taskgraph list` to see your tasks")))):n.push(`${t} Set up TaskGraph in ${e.folder}`),n.push(...bn(e.changes));let r=xn(e);return r.length>0&&(n.push(``,b.heading(`Next steps`)),r.forEach(([e,...t],r)=>{let i=`${r+1}. `;n.push(` ${i}${e}`);for(let e of t)n.push(` ${` `.repeat(i.length)}${e}`)})),e.alreadySetUp||(n.push(``,b.muted(yn("AI runs through Claude Code; run `claude` once to sign in"))),e.defaultModels&&n.push(b.muted(yn("Using the default models; change them with `taskgraph models --setup`")))),n.join(`
66
- `)}const Cn=[{title:`Daily workflow`,commands:[{name:`next`,desc:`Show the next task to work on`},{name:`show`,desc:`Show one task in detail`},{name:`list`,desc:`List tasks, filtered by status or tag`},{name:`set-status`,desc:`Change a task or subtask status`},{name:`add-task`,desc:`Add a task from a description`}]},{title:`Setup`,commands:[{name:`init`,desc:`Set up TaskGraph in this project`},{name:`models`,desc:`View or change the AI models`},{name:`completion`,desc:`Install Tab completion for your shell`}]},{title:`Create & update`,commands:[{name:`parse-prd`,desc:`Generate tasks from a PRD`},{name:`generate`,desc:`Write a file for each task`},{name:`update`,desc:`Update tasks from an ID onwards`},{name:`update-task`,desc:`Update one task`},{name:`update-subtask`,desc:`Add notes to a subtask`},{name:`add-subtask`,desc:`Add a subtask, or make a task one`},{name:`remove-task`,desc:`Remove a task or subtask`},{name:`remove-subtask`,desc:`Remove a subtask`},{name:`clear-subtasks`,desc:`Remove all subtasks from tasks`},{name:`sync-readme`,desc:`Export tasks to README.md`}]},{title:`Analyze & expand`,commands:[{name:`analyze-complexity`,desc:`Score tasks for complexity`},{name:`complexity-report`,desc:`Show the complexity report`},{name:`expand`,desc:`Break a task into subtasks`},{name:`research`,desc:`Ask a research question about the project`}]},{title:`Organize`,commands:[{name:`tags <add|use|remove|rename|copy>`,desc:`List or manage tags`},{name:`graph`,desc:`Show tasks as a dependency tree`},{name:`why`,desc:`Explain why a task is blocked`},{name:`add-dependency`,desc:`Make a task depend on another`},{name:`remove-dependency`,desc:`Remove a dependency`},{name:`validate-dependencies`,desc:`Report invalid dependencies`},{name:`fix-dependencies`,desc:`Fix invalid dependencies`}]}],wn=(e,t)=>e.length>t?`${e.slice(0,Math.max(1,t-1))}…`:e;function Tn(e=process.stdout.columns||80){let t=Cn.flatMap(e=>e.commands),n=Math.max(...t.map(e=>e.name.length)),r=Math.max(10,e-4-n-2),i=[`${C.bold(`TaskGraph`)} ${b.muted(`AI task management for your coding agent`)}`];for(let e of Cn){i.push(``,b.heading(e.title));for(let t of e.commands)i.push(` ${b.brand(t.name.padEnd(n))} ${b.muted(wn(t.desc,r))}`)}return i.push(``,b.muted(`Run `)+b.brand(`taskgraph <command> --help`)+b.muted(` for a command’s flags`),b.muted(`The CLI works on its own. For Claude Code slash commands:`),` ${b.brand(`/plugin marketplace add ${_n}`)}`,` ${b.brand(`/plugin install ${vn}`)}`),i.join(`
67
- `)}const En=(e,t)=>`${e} ${e===1?t:`${t}s`}`,Dn=(e,t)=>e.length>t?`${e.slice(0,Math.max(1,t-1))}…`:e;function On(e){return e.length===1?`Task ${e[0]} had no subtasks`:e.length<=3?`Tasks ${`${e.slice(0,-1).join(`, `)} and ${e.at(-1)}`} had no subtasks`:`${e.length} tasks had no subtasks`}function kn(e,t=process.stdout.columns||80){let{cleared:n,empty:r}=e;if(n.length===0)return r.length===1?`Task ${r[0].id} has no subtasks`:`No subtasks to clear`;let i=n.reduce((e,t)=>e+t.count,0),a=n.length===1?`task ${n[0].id}`:En(n.length,`task`),o=[`${C.green(`✓`)} Cleared ${En(i,`subtask`)} from ${a}`],s=n.map(e=>String(e.id)),c=Math.max(...s.map(e=>e.length)),l=n.length>1?n.map(e=>En(e.count,`subtask`)):[],u=Math.max(0,...l.map(e=>e.length)),d=Math.max(10,t-4-c-(u?u+2:0));n.forEach((e,t)=>{let n=l.length?`${b.muted(l[t].padEnd(u))} `:``;o.push(` ${b.brand(s[t].padEnd(c))} ${n}${Dn(e.title,d)}`)}),r.length>0&&o.push(b.muted(On(r.map(e=>e.id))));let f=n.length===1?String(n[0].id):`<id>`;return o.push(b.muted(`Run `)+b.brand(`taskgraph expand --id=${f}`)+b.muted(` to add new ones`)),o.join(`
68
- `)}const An=e=>Ce(e).length;function jn(e,t,n){let r=e.match(/^ */)?.[0]??``,i=e.slice(r.length).split(` `),a=[],o=r,s=r.length,c=!1;for(let e of i){let r=An(e);c&&s+1+r>t?(a.push(o),o=n+e,s=n.length+r):(o+=(c?` `:``)+e,s+=+!!c+r),c=!0}return a.push(o),a}function Mn(e,t){return e.split(`
69
- `).flatMap(e=>{let n=e.replace(/^(\s*)\* /,`$1• `),r=Ce(n).match(/^(\s*)(•|\d+\.)\s+/);return!r||An(n)<=t?[n]:jn(n,t,` `.repeat(r[0].length))}).join(`
70
- `)}function Nn(e,t=process.stdout.columns||80){let n=Math.max(40,Math.min(t,100)),r=new je({gfm:!0,breaks:!1});r.use(Ne({code:e=>e.split(`
71
- `).map(e=>C.cyan(e)).join(`
72
- `),blockquote:b.muted.italic,html:b.muted,heading:b.text.bold,firstHeading:b.text.bold,hr:b.muted,listitem:b.text,paragraph:b.text,strong:b.text.bold,em:b.text.italic,codespan:C.cyan,del:C.dim.strikethrough,link:b.brand,href:b.brand.underline,showSectionPrefix:!1,unescape:!0,emoji:!1,tab:2,width:n,reflowText:!0})),r.use({renderer:{text(e){return typeof e==`object`&&`tokens`in e&&e.tokens?this.parser.parseInline(e.tokens):typeof e==`string`?e:e.text}}});let i=e.replace(/<think>[\s\S]*?<\/think>/g,``).trim();return Mn(r.parse(i,{async:!1}).trimEnd(),n)}function Pn(e){let t=e=>e.split(`.`).map(e=>Number.parseInt(e,10));return[...e].sort((e,n)=>{let[r,i]=[t(e),t(n)];for(let e=0;e<Math.max(r.length,i.length);e++){let t=(r[e]??-1)-(i[e]??-1);if(t!==0)return t}return 0})}const Fn=e=>`${e.length===1?`task`:`tasks`} ${Pn(e).join(`, `)}`;function In(e){let t=[],{taskIds:n,relatedTaskIds:r,files:i}=e;return n.length>0&&t.push(Fn(n)),r.length>0&&t.push(n.length>0?`related ${Pn(r).join(`, `)}`:`related ${Fn(r)}`),i.length>0&&t.push(i.length<=2?i.join(`, `):`${i.length} files`),e.projectTree&&t.push(`project tree`),e.customContext&&t.push(`your notes`),t.length===0?``:b.muted(`Context: ${t.join(` · `)}`)}function Ln(e){let t=e.kind===`file`?e.path:`${e.id.includes(`.`)?`subtask`:`task`} ${e.id}`;return`${C.green(`✓`)} Saved to ${t}`}function Rn(e,t){let n=e.kind===`file`?`a file`:`${e.id.includes(`.`)?`subtask`:`task`} ${e.id}`;return`${C.red(`✗`)} Couldn't save to ${n}: ${t}`}const V=[`main`,`research`,`fallback`],H={main:{label:`Main`,purpose:`creates and updates tasks`},research:{label:`Research`,purpose:`research and --research runs`},fallback:{label:`Fallback`,purpose:`used if the main model fails`}},zn={opus:`most capable`,sonnet:`balanced`,haiku:`fastest`},Bn=e=>e.replace(/`([^`]+)`/g,(e,t)=>b.brand(t));function Vn(e){return e.map(e=>zn[e]?`${e} (${zn[e]})`:e).join(`, `)}function Hn(e,t){let n=Math.max(...V.map(e=>H[e].label.length)),r=Math.max(4,...V.map(t=>e[t]?.length??0)),i=[b.heading(`Models`)];for(let t of V){let{label:a,purpose:o}=H[t],s=e[t],c=s?b.brand(s.padEnd(r)):b.muted(`none`.padEnd(r));i.push(` ${a.padEnd(n)} ${c} ${b.muted(o)}`)}return i.push(``),t.length>0&&i.push(b.muted(`Choices: ${Vn(t)}`)),i.push(b.muted(Bn("Change them with `taskgraph models --setup`"))),i.join(`
73
- `)}const Un=e=>e.from===e.to?`${b.brand(e.to)} ${b.muted(`(unchanged)`)}`:e.from?`${e.from} → ${b.brand(e.to)}`:b.brand(e.to);function Wn(e){let t=C.green(`✓`);if(e.length===1){let[n]=e;return`${t} ${H[n.role].label} model ${Un(n)}`}let n=Math.max(...e.map(e=>H[e.role].label.length)),r=e.filter(e=>e.from!==e.to);return[r.length===0?`${t} Models unchanged`:`${t} Updated ${r.length} ${r.length===1?`model`:`models`}`,...e.map(e=>` ${H[e.role].label.padEnd(n)} ${Un(e)}`)].join(`
74
- `)}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`?`►`:`○`}`:C.red(`${e} (not found)`)}).join(`, `)}const U=(e,t)=>`${e} ${e===1?t:`${t}s`}`,Kn=(e,t)=>e.length>t?`${e.slice(0,Math.max(1,t-1))}…`:e,qn=e=>`${String(e).includes(`.`)?`subtask`:`task`} ${e}`;function Jn({taskCount:e,subtaskCount:t,dependencyCount:n}){let r=[U(e,`task`)];return t>0&&r.push(U(t,`subtask`)),r.push(n===0?`no dependencies`:n===1?`1 dependency`:`${n} dependencies`),r.join(`, `)}function Yn(e){switch(e.type){case`self`:return`depends on itself`;case`missing`:return`depends on ${qn(e.dependencyId??`?`)}, which doesn't exist`;case`circular`:return`is part of a dependency loop`}}function Xn(e){let t=qn(e.dependencyId??`?`);switch(e.type){case`self`:return`removed its dependency on itself`;case`missing`:return`removed ${t}, which doesn't exist`;case`duplicate`:return`removed a duplicate of ${t}`;case`circular`:return`removed ${t} to break a loop`}}function Zn(e,t){let n=Math.max(...e.map(e=>String(e.taskId).length)),r=Math.max(10,t-4-n);return e.map(e=>` ${b.brand(String(e.taskId).padEnd(n))} ${Kn(e.text,r)}`)}function Qn(e){let t=e=>String(e).split(`.`).map(Number);return[...e].sort((e,n)=>{let[r,i]=[t(e.taskId),t(n.taskId)];for(let e=0;e<Math.max(r.length,i.length);e++){let t=(r[e]??-1)-(i[e]??-1);if(t!==0)return t}return 0})}function $n(e){return`${C.green(`✓`)} No dependency problems${b.muted(` · ${Jn(e)}`)}`}function er(e,t=process.stdout.columns||80){let{issues:n}=e;return n.length===0?$n(e):tr(`${U(n.length,`dependency problem`)}`,n,t)}function tr(e,t,n,r=!1){let i=[`${C.red(`✗`)} ${e}`,...Zn(t.map(e=>({taskId:e.taskId,text:Yn(e)})),n)],a=!r&&t.some(e=>e.type!==`circular`||e.fixable);return i.push(a?b.muted(`Run `)+b.brand(`taskgraph fix-dependencies`)+b.muted(` to remove them`):b.muted(`Break the loop with `)+b.brand(`taskgraph remove-dependency --id=<id> --depends-on=<id>`)),i.join(`
75
- `)}function nr(e,t=process.stdout.columns||80){let{fixes:n,remaining:r=[]}=e;if(n.length===0&&r.length===0)return $n(e);let i=[];if(n.length>0&&i.push(`${C.green(`✓`)} Fixed ${U(n.length,`dependency problem`)}`,...Zn(Qn(n).map(e=>({taskId:e.taskId,text:Xn(e)})),t)),r.length>0){let e=n.length>0?`${U(r.length,`problem`)} left`:U(r.length,`dependency problem`);i.push(tr(e,r,t,!0))}return i.join(`
76
- `)}const rr=(e,t)=>`${e} ${e===1?t:`${t}s`}`,ir=(e,t)=>e.length>t?`${e.slice(0,Math.max(1,t-1))}…`:e,W=e=>`${C.green(`✓`)} ${e}`,G=(...e)=>{let t=e.filter(Boolean);return t.length?b.muted(` · ${t.join(` · `)}`):``},ar=e=>b.muted(`Switch to it with `)+b.brand(`taskgraph tags use ${e}`);function or(e,t=process.stdout.columns||80){let n=e.sourceTag&&`${rr(e.tasksCopied,`task`)} from ${e.sourceTag}`,r=[W(`Created tag ${e.tagName}`)+G(n)];return e.description&&r.push(` ${b.muted(ir(e.description,t-2))}`),r.push(ar(e.tagName)),r.join(`
77
- `)}function sr(e,t=process.stdout.columns||80){let n=rr(e.taskCount,`task`),r=[e.previousTag===e.currentTag?`Already on ${e.currentTag}${G(n)}`:W(`Switched to ${e.currentTag}`)+G(n)];if(e.nextTask){let n=String(e.nextTask.id),i=ir(e.nextTask.title,t-8-n.length);r.push(`${b.muted(`Next:`)} ${b.brand(n)} ${i}`)}else e.taskCount===0?r.push(b.muted(`Add tasks with `)+b.brand(`taskgraph add-task`)+b.muted(` or `)+b.brand(`taskgraph parse-prd <file>`)):r.push(b.muted(`No task is ready to start`));return r.join(`
78
- `)}function cr(e){return W(`Renamed ${e.oldName} to ${e.newName}`)+G(e.isCurrentTag&&`current tag`)}function lr(e){return[W(`Copied ${e.sourceName} to ${e.targetName}`)+G(rr(e.tasksCopied,`task`)),ar(e.targetName)].join(`
79
- `)}function ur(e){let t=e.tasksDeleted===0?``:e.tasksDeleted===1?` and its task`:` and its ${e.tasksDeleted} tasks`;return W(`Deleted tag ${e.tagName}${t}`)+G(e.switchedToMaster&&`switched to master`)}function dr(e,t={},n=process.stdout.columns||80){if(e.length===0)return t.ready?`No tag has a task ready to start`:`No tags yet`;let r=[`Tasks`,`Ready`,`Done`],i=t.showMetadata?e.map(e=>{let t=new Date(e.created??``);return Number.isNaN(t.getTime())?``:t.toISOString().slice(0,10)}):[],a=t.showMetadata?10:0,o=2+r.reduce((e,t)=>e+2+t.length,0)+(t.showMetadata?2+a:0),s=Math.max(3,...e.map(e=>e.name.length)),c=t.showMetadata?Math.floor((n-o-2)/2):n-o,l=Math.max(8,Math.min(s,c)),u=n-o-l-2,d=t.showMetadata&&u>=8,f=[` `,`Tag`.padEnd(l),...r.map(e=>` ${e}`),t.showMetadata?` ${`Created`.padEnd(a)}`:``,d?` Description`:``].join(``),p=[b.muted(f.trimEnd())];return e.forEach((e,n)=>{let o=e.isCurrent?`${C.green(`●`)} `:` `,s=ir(e.name,l).padEnd(l),c=[e.taskCount,e.readyTasks,e.completedTasks].map((e,t)=>{let n=String(e).padStart(r[t].length);return` ${e===0?b.muted(n):n}`}),f=`${o}${e.isCurrent?C.bold(s):s}${c.join(``)}`;if(t.showMetadata){let t=e.description&&d?` ${ir(e.description,u)}`:``,r=t?i[n].padEnd(a):i[n];(r||t)&&(f+=b.muted(` ${r}${t}`))}p.push(f.trimEnd())}),p.join(`
80
- `)}function fr(e=`TaskGraph`){console.log(O(C.bold(e),{padding:1,margin:{top:1,bottom:1},borderStyle:`round`,borderColor:S,textAlignment:`center`}))}function pr(e,t){let n=N();console.error(O(C.red.bold(`X Error: `)+b.text(e)+(t?`
81
-
82
- `+b.muted(t):``),{padding:1,borderStyle:`round`,borderColor:`red`,width:n}))}const mr=pr;function hr(e){let t=N();console.log(O(C.green.bold(`√ `)+b.text(e),{padding:1,borderStyle:`round`,borderColor:`green`,width:t}))}function gr(e){let t=N();console.log(O(C.yellow.bold(`⚠ `)+b.text(e),{padding:1,borderStyle:`round`,borderColor:`yellow`,width:t}))}function _r(e){let t=N();console.log(O(b.brand.bold(`i `)+b.text(e),{padding:1,borderStyle:`round`,borderColor:S,width:t}))}const vr=[{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 yr(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=vr.filter(e=>s[e.key]??!0),l=Re(P(),c),u=e=>l.widths[l.keys.indexOf(e)],d=new Fe({head:l.keys.map(e=>b.brand.bold(vr.find(t=>t.key===e)?.header??e)),style:{head:[],border:[]},colWidths:l.widths,wordWrap:!0}),f=e=>l.keys.map(t=>e[t]??``);e.forEach(e=>{let t=e.blocks?.join(`, `)??``;d.push(f({tag:b.accent(e.tagName||`-`),id:C.cyan(e.id.toString()),title:F(e.title,u(`title`)-3),status:M(e.status,!0),priority:Zt(e.priority),dependencies:!e.dependencies||e.dependencies.length===0?b.muted(`-`):C.cyan(e.dependencies.map(e=>String(e)).join(`, `)),blocks:t?_(e.status)?b.muted(t):C.yellow(t):b.muted(`-`),complexity:typeof e.complexity==`number`?B(e.complexity):b.muted(`N/A`)})),n&&e.subtasks&&e.subtasks.length>0&&e.subtasks.forEach(e=>{d.push(f({tag:b.muted(`-`),id:b.muted(` └─ ${e.id}`),title:b.muted(F(e.title,u(`title`)-6)),status:b.muted(M(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`?B(e.complexity):`--`)}))})});let p=l.hidden.length>0?`
83
- `+b.muted(`Hidden to fit width: ${l.hidden.map(e=>vr.find(t=>t.key===e)?.header).join(`, `)}`):``;return d.toString()+p}var br=/* @__PURE__ */ e({BANNER_GRADIENT:()=>ue,BORDER_COLOR:()=>S,BRAND_COLORS:()=>he,HELP_GROUPS:()=>Cn,MODEL_NOTES:()=>zn,MODEL_ROLES:()=>H,MODEL_ROLE_ORDER:()=>V,MUTED_BOX_BORDER:()=>fe,ParsePrdProgress:()=>Gt,TABLE_BORDER:()=>de,brandSpinner:()=>Bt,calculateDependencyStatistics:()=>at,calculateSubtaskStatistics:()=>it,calculateTaskStatistics:()=>rt,completedTaskCount:()=>Vt,complexityLevel:()=>Qt,createLink:()=>I,createProgressBar:()=>ze,createSpinner:()=>z,createTaskLink:()=>Je,createTaskTable:()=>yr,createUrlLink:()=>qe,displayAcceptanceCriteria:()=>kt,displayAsciiBanner:()=>$e,displayBanner:()=>fr,displayCardBox:()=>tt,displayCodebasePatterns:()=>Mt,displayDashboards:()=>dt,displayDependencyDashboard:()=>ut,displayError:()=>mr,displayErrorBox:()=>pr,displayExistingInfrastructure:()=>Dt,displayHeader:()=>gt,displayImplementationApproach:()=>jt,displayImplementationDetails:()=>Ct,displayImplementationMetadata:()=>Pt,displayInfo:()=>_r,displayInitBanner:()=>et,displayProjectDashboard:()=>lt,displayRecommendedNextTask:()=>Lt,displayRelevantFiles:()=>Et,displayScopeBoundaries:()=>Ot,displaySkillsAndCategory:()=>Nt,displaySubtasks:()=>Tt,displaySuccess:()=>hr,displaySuggestedActions:()=>Ft,displaySuggestedNextSteps:()=>Kt,displaySyncMessage:()=>Yt,displayTaskDetails:()=>It,displayTaskHeader:()=>xt,displayTaskProperties:()=>St,displayTechnicalConstraints:()=>At,displayTestStrategy:()=>wt,displayWarning:()=>gr,displayWatchFooter:()=>Jt,formatAddedSubtasks:()=>gn,formatClearedSubtasks:()=>kn,formatComplexityReport:()=>un,formatComplexityRun:()=>ln,formatCost:()=>fn,formatDependenciesWithStatus:()=>Gn,formatDependencyCheck:()=>er,formatDependencyFixes:()=>nr,formatDuration:()=>Ut,formatElapsed:()=>Ht,formatHelp:()=>Tn,formatInitSummary:()=>Sn,formatModelChanges:()=>Wn,formatModelChoices:()=>Vn,formatModelConfiguration:()=>Hn,formatResearchAnswer:()=>Nn,formatResearchContext:()=>In,formatResearchSaveFailed:()=>Rn,formatResearchSaved:()=>Ln,formatStatusChanges:()=>hn,formatStatusLine:()=>ct,formatTagCopied:()=>lr,formatTagCreated:()=>or,formatTagDeleted:()=>ur,formatTagList:()=>dr,formatTagRenamed:()=>cr,formatTagSwitched:()=>sr,formatUsageLine:()=>pn,getBoxWidth:()=>N,getComplexityWithColor:()=>B,getComplexityWithScore:()=>en,getPriorityBreakdown:()=>ot,getPriorityWithColor:()=>Zt,getStatusWithColor:()=>M,getSuggestedActions:()=>vt,getTaskDescription:()=>Rt,renderBlockerExplanation:()=>Ge,renderDependencyTree:()=>ht,sortTaskIds:()=>Pn,supportsLinks:()=>Ye,theme:()=>b,truncate:()=>F});function K(e){gt({tag:e.tag||`master`})}function xr(){return process.env.DEBUG===`true`||process.env.DEBUG===`1`}const Sr=/* @__PURE__ */ new Set([`UNKNOWN_ERROR`,`INTERNAL_ERROR`,`STORAGE_ERROR`]),Cr={TASK_NOT_FOUND:"Run `taskgraph list` to see task IDs",JSON_PARSE_ERROR:`Nothing was changed; fix the file or restore it from version control`};function wr(e,t){let n=e;for(;n?.cause&&typeof n.code==`string`&&Sr.has(n.code);)n=n.cause;let r=Ar(typeof n?.getUserMessage==`function`?n.getUserMessage():typeof n?.getSanitizedDetails==`function`?n.getSanitizedDetails().message:n?.message??String(n)),i=typeof n?.hint==`string`?n.hint:void 0;return{message:r,hint:t??i??kr(r,n?.code)}}const Tr=/\bsubtask (\d+)\.\d+ not found\b/i,Er=/\btask\b(?!\s+file).*\bnot found\b/i,Dr=/^(source |target )?tag\b.*\bnot found\b/i,Or=/^(source |target )?tag\b.*\balready exists\b/i;function kr(e,t){if(t&&Cr[t])return Cr[t];if(Dr.test(e)||Or.test(e))return"Run `taskgraph tags` to see your tags";let n=Tr.exec(e);if(n)return`Run \`taskgraph show ${n[1]}\` to see its subtasks`;if(Er.test(e))return Cr.TASK_NOT_FOUND}function Ar(e){return e.trim().replace(/^(error:\s*)+/i,``).replace(/\.$/,``).replace(/\b(task|subtask) with ID "?([\d.]+)"?/gi,`$1 $2`).replace(/^(source |parent )+task\b/i,`Task`).replace(/\bdoes not exist$/i,`not found`)}function jr({message:e,hint:t}){let n=`${C.red(`✗`)} ${e}`;if(t){let e=t.split(/`([^`]+)`/).map((e,t)=>t%2==1?b.brand(e):b.muted(e)).join(``);n+=`\n ${e}`}return n}function Mr(e,t){let[n=``,...r]=e.trim().split(`
84
- `),i=n.replace(/^error:\s*/i,``).replace(/^option '(?:-\w, )?(--[\w-]+)[^']*' argument missing$/i,`$1 needs a value`),a=i.charAt(0).toUpperCase()+i.slice(1),o=/\(Did you mean (.+?)\?\)/.exec(r.join(` `))?.[1],s;return/^unknown command/i.test(i)?s=o?`Did you mean \`taskgraph ${o}\`?`:"Run `taskgraph --help` to see all commands":o?s=`Did you mean \`${o}\`?`:t&&(s=`Run \`taskgraph ${t} --help\` to see its options`),jr({message:Ar(a),hint:s})}function q(e,t){console.error(`\n${jr({message:Ar(e),hint:t})}`)}function J(e,t={}){console.error(`\n${jr(wr(e,t.hint))}`),(xr()||t.forceStack)&&e?.stack&&(console.error(b.muted(`
85
- Stack trace:`)),console.error(b.muted(e.stack))),t.skipExit||process.exit(1)}function Y(e){return e?Se(e):l()}var Nr=class e extends D{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(Y(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){J(e)}}async watchTasks(e){if(!this.tmCore)throw Error(`TmCore not initialized`);let t=await this.getTasks(e),n=/* @__PURE__ */ new Date;console.clear(),this.displayResults(t,e),Jt(n);let r;try{r=await this.tmCore.tasks.watch(async r=>{if(r.type===`change`)try{t=await this.getTasks(e),n=/* @__PURE__ */ new Date,console.clear(),this.displayResults(t,e),Yt(n),Jt(n)}catch(e){let t=e instanceof Error?e.message:String(e);console.error(C.yellow(`\nWarning: Failed to refresh tasks: ${t}`))}else r.type===`error`&&r.error&&console.error(C.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(C.red(`Watch mode error: ${e.message}`)),e}}validateOptions(e){if(e.format&&!te.includes(e.format))return console.error(C.red(`Invalid format: ${e.format}`)),console.error(b.muted(`Valid formats: ${te.join(`, `)}`)),!1;if(e.status){let n=e.status.split(`,`).map(e=>e.trim());for(let e of n)if(e!==`all`&&!t.includes(e))return console.error(C.red(`Invalid status: ${e}`)),console.error(b.muted(`Valid statuses: ${t.join(`, `)}`)),!1}return e.allTags&&e.watch?(console.error(C.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 u({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}=ee(i.tasks);this.displayInvalidDependencyWarnings(o);let s=i.tasks.map(e=>({...e,blocks:a.get(String(e.id))||[]}));e.ready&&(s=h(s)),e.blocking&&(s=p(s)),t&&n&&(s=s.filter(e=>t.includes(e.status)));let c=!e.json&&!e.compact&&(e.format??`text`)===`text`&&!e.ready&&!e.blocking?await this.tmCore.tasks.getNext(e.tag):null;return{...i,tasks:s,filtered:s.length,nextTaskId:c?String(c.id):null}}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}=ee(i.tasks);this.displayInvalidDependencyWarnings(o,t);let s=i.tasks.map(e=>({...e,blocks:a.get(String(e.id))||[],tagName:t})),c=e.ready?h(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(C.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(C.yellow(`\nWarning: ${e.length} invalid dependency reference(s) found${n}:`)),e.slice(0,5).forEach(({taskId:e,depId:t})=>{console.warn(b.muted(` Task ${e} depends on non-existent task ${t}`))}),e.length>5&&console.warn(b.muted(` ...and ${e.length-5} more`))}displayResults(e,t){let n=t.format||`text`;switch(t.json?n=`json`:t.compact&&(n=`compact`),n){case`json`:this.displayJson(e);break;case`compact`:this.displayCompact(e,t);break;default:this.displayText(e,t)}}displayJson(e){console.log(JSON.stringify({tasks:e.tasks,metadata:{total:e.total,filtered:e.filtered,tag:e.allTags?`all`:e.tag,allTags:e.allTags||!1}},null,2))}displayCompact(e,t){let{tasks:n,tag:r,allTags:i}=e;t.noHeader!==!0&&K({tag:i?`all tags`:r||`master`});for(let e of n){let n=o[e.status],r=i&&`tagName`in e?b.accent(`[${e.tagName}] `):``;if(console.log(`${r}${C.cyan(e.id)} ${n} ${e.title}`),t.withSubtasks&&e.subtasks?.length)for(let t of e.subtasks){let e=o[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&&K({tag:i?`all tags`:r||`master`}),n.length===0){gr(`No tasks found matching the criteria.`);return}let a=rt(n),o=it(n),s=at(n),c=ot(n),l=e.nextTaskId?n.find(t=>String(t.id)===e.nextTaskId):void 0,u=t.ready||t.blocking||i;if(u||dt(a,o,c,s,l),console.log(yr(n,{showSubtasks:t.withSubtasks,showDependencies:!0,showBlocks:!0,showComplexity:!0,showTag:i})),!u){if(l){let e=Rt(l);Lt({id:l.id,title:l.title,priority:l.priority,status:l.status,dependencies:l.dependencies,description:e,complexity:l.complexity})}Kt()}}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}},Pr=class e extends D{tmCore;lastResult;requestedId;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(Y(t.project));let n=e||t.id;n||(q(`Missing task ID`,"Try `taskgraph show 3`"),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||(q(`"${e}" isn't a task ID`,"Use a number like `3`, or `3.1` for a subtask"),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){J(e)}}validateOptions(e){return e.format&&![`text`,`json`].includes(e.format)?(console.error(C.red(`Invalid format: ${e.format}`)),console.error(b.muted(`Valid formats: text, json`)),!1):!0}async initializeCore(e){this.tmCore||=await u({projectPath:e})}async getSingleTask(e,t){if(!this.tmCore)throw Error(`TmCore not initialized`);this.requestedId=e;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),`found`in e&&!e.found&&(process.exitCode=1);break;default:`task`in e?this.displaySingleTask(e,t):this.displayMultipleTasks(e,t)}}displayJson(e){console.log(JSON.stringify(e,null,2))}displaySingleTask(e,t){if(!e.found||!e.task){let t=e.originalTaskId??this.requestedId??``,n=t.includes(`.`)?t.split(`.`)[0]:void 0;q(`${n?`Subtask`:`Task`} ${t} not found`,n?`Run \`taskgraph show ${n}\` to see its subtasks`:"Run `taskgraph list` to see task IDs"),process.exitCode=1}else K({tag:this.tmCore?.config.getActiveTag()||`master`}),console.log(),It(e.task,{statusFilter:t.status,showSuggestedActions:!0,originalTaskId:e.originalTaskId})}displayMultipleTasks(e,t){K({tag:this.tmCore?.config.getActiveTag()||`master`}),e.notFound.length>0&&console.log(C.yellow(`\n⚠ Not found: ${e.notFound.join(`, `)}`)),e.tasks.length===0?gr(`No tasks found matching the criteria.`):(console.log(b.brand.bold(`
86
- Tasks:
87
- `)),console.log(yr(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}},Fr=class e extends D{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(Y(e.project));let t=await this.getNextTask(e);this.setLastResult(t),e.silent||this.displayResults(t,e)}catch(e){t=!0,J(e,{skipExit:!0})}finally{await this.cleanup()}t&&process.exit(1)}validateOptions(e){if(e.format&&![`text`,`json`].includes(e.format))throw Error(`Invalid format: ${e.format}. Valid formats are: text, json`)}async initializeCore(e){if(!this.tmCore){let t=w.resolve(e);this.tmCore=await u({projectPath:t})}}async getNextTask(e){if(!this.tmCore)throw Error(`TmCore not initialized`);let t=await this.tmCore.tasks.getNext(e.tag),n=e.tag||this.tmCore.config.getActiveTag(),r=await this.tmCore.tasks.list({tag:e.tag}),i=r&&r.tasks.length>0;return{task:t,found:t!==null,tag:n,hasAnyTasks:i}}displayResults(e,t){switch(t.format||`text`){case`json`:this.displayJson(e);break;default:this.displayText(e)}}displayJson(e){console.log(JSON.stringify(e,null,2))}displayText(e){if(K({tag:e.tag||`master`}),!e.found||!e.task){e.hasAnyTasks?(console.log(C.yellow(`✓ All tasks are either completed, blocked by dependencies, or in progress.`)),console.log(`\n${C.dim(`Tip: Try`)} ${C.cyan(`taskgraph list`)} ${C.dim(`to see all tasks`)}`)):(console.log(O(C.yellow(`No tasks found in this project.`),{padding:1,borderStyle:`round`,borderColor:`yellow`,title:`No tasks available`,titleAlignment:`center`})),console.log(`\n${C.dim(`Tip: Create tasks with`)} ${C.cyan(`taskgraph parse-prd`)} ${C.dim(`or`)} ${C.cyan(`taskgraph add-task`)}`));return}let t=e.task;It(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}},Ir=class e extends D{tmCore;constructor(e){super(e||`graph`),this.description(`Show tasks as a dependency tree`).option(`-i, --id <id>`,`Show only this task and the tasks drawn under it`).option(`-t, --tag <tag>`,`Use a specific tag`).option(`-f, --format <format>`,`Output format (text, json)`,`text`).option(`-p, --project <path>`,`Project root directory (auto-detected if not provided)`).action(async e=>{await this.executeCommand(e)})}async executeCommand(e){let t=!1;try{if(e.format&&![`text`,`json`].includes(e.format))throw Error(`Invalid format: ${e.format}. Valid formats are: text, json`);let t=w.resolve(Y(e.project));this.tmCore=await u({projectPath:t});let n=await this.tmCore.tasks.getDependencyTree({tag:e.tag,rootId:e.id}),r=await this.tmCore.tasks.getNext(e.tag),i={...n,tag:e.tag||this.tmCore.config.getActiveTag(),nextId:r?String(r.id):null};e.format===`json`?console.log(JSON.stringify(i,null,2)):this.displayText(i)}catch(e){t=!0,J(e,{skipExit:!0})}finally{this.tmCore=void 0}t&&process.exit(1)}displayText(e){if(K({tag:e.tag}),e.total===0){console.log(C.yellow(`No tasks yet.`)),console.log(`${b.muted(`Create some with`)} ${b.brand(`taskgraph parse-prd`)} ${b.muted(`or`)} ${b.brand(`taskgraph add-task`)}`);return}console.log();let t=ht(e,{nextId:e.nextId,width:P()});console.log(t.join(`
88
- `))}static register(t,n){let r=new e(n);return t.addCommand(r),r}},Lr=class e extends D{tmCore;constructor(e){super(e||`why`),this.description(`Explain why a task is blocked`).argument(`[id]`,`Task ID, or a subtask ID like 3.1`).option(`-i, --id <id>`,`Task ID, or a subtask ID like 3.1`).option(`-t, --tag <tag>`,`Use a specific tag`).option(`-f, --format <format>`,`Output format (text, json)`,`text`).option(`-p, --project <path>`,`Project root directory (auto-detected if not provided)`).action(async(e,t)=>{await this.executeCommand(e,t)})}async executeCommand(e,t){let n=!1;try{if(t.format&&![`text`,`json`].includes(t.format))throw Error(`Invalid format: ${t.format}. Valid formats are: text, json`);let n=e||t.id;n||(q(`Missing task ID`,"Try `taskgraph why 3`"),process.exit(1));let r=c.safeParse(n.trim());r.success||(q(`"${n}" isn't a task ID`,"Use a number like `3`, or `3.1` for a subtask"),process.exit(1));let i=w.resolve(Y(t.project));this.tmCore=await u({projectPath:i});let a={...await this.tmCore.tasks.explainBlockers(r.data,{tag:t.tag}),tag:t.tag||this.tmCore.config.getActiveTag()};t.format===`json`?console.log(JSON.stringify(a,null,2)):this.displayText(a)}catch(e){n=!0,J(e,{skipExit:!0})}finally{this.tmCore=void 0}n&&process.exit(1)}displayText(e){K({tag:e.tag}),console.log(),console.log(Ge(e,{width:P()}).join(`
89
- `))}static register(t,n){let r=new e(n);return t.addCommand(r),r}},Rr=class e extends D{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=z(`Initializing TaskGraph...`).start(),await this.initializeCore(Y(t.project)),n.succeed(`TaskGraph initialized`);let r=e||t.id||null;r||(n=z(`Finding next available task...`).start(),r=await this.performGetNextTask(),r?n.succeed(`Found next task: #${r}`):n.fail(`No available tasks found`)),r||(mr(`No task ID provided and no available tasks found`),process.exit(1)),t.dryRun||await this.showPreLaunchMessage(r),n=z(`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`),J(e)}}validateOptions(e){return e.format&&![`text`,`json`].includes(e.format)?(console.error(C.red(`Invalid format: ${e.format}`)),console.error(b.muted(`Valid formats: text, json`)),!1):!0}async initializeCore(e){this.tmCore||=await u({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(C.green(`Starting: `)+C.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=z(`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(C.green(`Launching Claude Code…`)),console.log();let r=Te(e.executable,e.args,{cwd:e.cwd,stdio:`inherit`,shell:!1});r.on(`close`,e=>{e===0?t():n(/* @__PURE__ */ Error(`Process exited with code ${e}`))}),r.on(`error`,e=>{n(/* @__PURE__ */ Error(`Failed to spawn process: ${e.message}`))});let i=()=>{r&&!r.killed&&r.kill(`SIGTERM`)};process.on(`SIGINT`,i),process.on(`SIGTERM`,i),process.on(`exit`,i)})}displayResults(e,t){switch(t.format||`text`){case`json`:this.displayJson(e);break;default:this.displayTextResult(e,t)}}displayJson(e){console.log(JSON.stringify(e,null,2))}displayTextResult(e,t){if(!e.found||!e.task){console.log(O(C.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}`),It(n,{customHeader:t,headerColor:`yellow`}),e.executionOutput&&(console.log(),console.log(O(C.bold(`Claude-Code Prompt:`)+`
90
-
91
- `+e.executionOutput,{padding:1,borderStyle:`round`,borderColor:S,width:process.stdout.columns*.95||100}))),console.log(),console.log(O(C.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(O(C.green.bold(`✓ Task session complete`)+`
92
-
93
- `+b.text(t)+`
94
-
95
- `+C.cyan(`Next steps:`)+`
96
- • Run ${C.yellow(`taskgraph show `+n.id)} to review task details\n• Run ${C.yellow(`taskgraph set-status --id=`+r+` --status=done`)} when complete\n• Run ${C.yellow(`taskgraph next`)} to find the next available task\n• Run ${C.yellow(`taskgraph start`)} to begin the next task`,{padding:1,borderStyle:`round`,borderColor:`green`,width:process.stdout.columns*.95||100,margin:{top:1}}))}else console.log(O(C.red(`✗ Failed to launch claude-code`+(e.error?`\nError: ${e.error}`:``)),{padding:{top:0,bottom:0,left:1,right:1},borderColor:`red`,borderStyle:`round`}))}setLastResult(e){this.lastResult=e}getLastResult(){return this.lastResult}async cleanup(){this.tmCore&&=void 0}static register(t,n){let r=new e(n);return t.addCommand(r),r}};const zr=[`pending`,`in-progress`,`done`,`deferred`,`cancelled`,`blocked`,`review`];var Br=class e extends D{tmCore;lastResult;constructor(e){super(e||`set-status`),this.description(`Update the status of one or more tasks`).alias(`status`).argument(`[id]`,`Task ID(s) - comma-separated for multiple (e.g., 1 or 1,1.1,2)`).argument(`[status]`,`Status - ${zr.join(`, `)}`).option(`-i, --id <id>`,`Task ID(s) (fallback if not using positional)`).option(`-s, --status <status>`,`Status (fallback if not using positional)`).option(`-f, --format <format>`,`Output format (text, json)`,`text`).option(`--silent`,`Suppress output (useful for programmatic usage)`).option(`-p, --project <path>`,`Project root directory (auto-detected if not provided)`).action(async(e,t,n)=>{let r={...n,id:e||n?.id,status:t||n?.status};await this.executeCommand(r)})}async executeCommand(e){let t=!1;try{e.id||(q(`Missing task ID`,"Try `taskgraph set-status --id=3 --status=done`"),process.exit(1)),e.status||(q(`Missing status`,`Try \`taskgraph set-status --id=${e.id} --status=done\``),process.exit(1)),zr.includes(e.status)||(q(`"${e.status}" isn't a status`,`Use one of: ${zr.join(`, `)}`),process.exit(1)),this.tmCore=await u({projectPath:Y(e.project)});let n=e.id.split(`,`).map(e=>e.trim()),r=[];for(let e of n){let t=c.safeParse(e);t.success||(q(`"${e}" isn't a task ID`,"Use a number like `3`, or `3.1` for a subtask"),process.exit(1)),r.push(t.data)}let i=[],a;for(let n of r)try{let t=await this.tmCore.tasks.updateStatus(n,e.status);i.push({taskId:t.taskId,oldStatus:t.oldStatus,newStatus:t.newStatus})}catch(r){if(t=!0,e.format===`json`){let e=r?.getSanitizedDetails?r.getSanitizedDetails().message:r instanceof Error?r.message:String(r);console.log(JSON.stringify({success:!1,error:e,taskId:n,timestamp:(/* @__PURE__ */ new Date()).toISOString()}))}else a=r;break}this.lastResult={success:!t,updatedTasks:i},(i.length>0&&!(t&&e.format===`json`)||!t)&&this.displayResults(this.lastResult,e),a!==void 0&&!e.silent&&J(a,{skipExit:!0})}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||J(n,{skipExit:!0})}finally{this.tmCore}t&&process.exit(1)}displayResults(e,t){switch(t.format||`text`){case`json`:console.log(JSON.stringify(e,null,2));break;default:t.silent||this.displayTextResults(e)}}displayTextResults(e){console.log(`\n${hn(e.updatedTasks)}`)}getLastResult(){return this.lastResult}static register(t,n){let r=new e(n);return t.addCommand(r),r}};const X=`taskgraph-ai`,Vr=`stephennmiller/taskgraph-ai`;function Hr(e,t,n){let r=`${b.brand.bold(`Update Available!`)} ${C.dim(e)} → ${C.green(t)}`;if(n&&n.length>0){r+=`
97
-
98
- `+C.bold(`What's New:`);for(let e of n)r+=`
99
- `+C.cyan(`• `)+e;r+=`
100
-
101
- Auto-updating to the latest version...`}else r+=`
102
-
103
- Auto-updating to the latest version with new features and bug fixes...`;let i=O(r,{padding:1,margin:{top:1,bottom:1},borderColor:`yellow`,borderStyle:`round`});console.log(i)}async function Ur(e){let t=z(b.brand(`Updating ${X} to version ${C.green(e)}`)).start();return new Promise(n=>{let r=Te(`npm`,[`install`,`-g`,`${X}@${e}`,`--no-fund`,`--no-audit`,`--loglevel=warn`],{stdio:[`ignore`,`pipe`,`pipe`]}),i=``;r.stdout.on(`data`,()=>{t.text=b.brand(`Installing ${X}@${e}...`)}),r.stderr.on(`data`,e=>{i+=e.toString()}),r.on(`close`,r=>{r===0?(t.succeed(C.green(`Successfully updated to version ${C.bold(e)}`)),n(!0)):(t.fail(C.red(`Auto-update failed`)),console.log(C.cyan(`Please run manually: npm install -g ${X}@${e}`)),i&&console.log(C.dim(`Error: ${i.trim()}`)),n(!1))}),r.on(`error`,r=>{t.fail(C.red(`Auto-update failed`)),console.log(C.red(`Error:`),r.message),console.log(C.cyan(`Please run manually: npm install -g ${X}@${e}`)),n(!1)})})}async function Wr(e){if(process.env.TASKGRAPH_SKIP_AUTO_UPDATE===`1`||process.env.CI||process.env.NODE_ENV===`test`){let e=process.env.TASKGRAPH_SKIP_AUTO_UPDATE===`1`?`TASKGRAPH_SKIP_AUTO_UPDATE=1`:process.env.CI?`CI environment`:`NODE_ENV=test`;return console.log(C.dim(`Skipping auto-update (${e})`)),!1}return Ur(e)}function Gr(e){let t=e.slice(2);console.log(C.dim(`Restarting with updated version...
104
- `));let n=Te(`taskgraph`,t,{stdio:`inherit`,detached:!1,shell:k.platform===`win32`});n.on(`exit`,(e,t)=>{t?k.kill(k.pid,t):k.exit(e??0)}),n.on(`error`,e=>{console.error(C.red(`Failed to restart with new version:`),e.message),console.log(C.yellow(`Please run your command again manually.`)),k.exit(1)})}function Kr(e,t=null){let n=d(e);if(!n)return null;let r;return r=n.parentId===void 0?e.find(e=>String(e.id)===String(n.id)):{id:n.id,title:n.title,status:n.status,priority:n.priority,dependencies:n.dependencies,parentId:Number(n.parentId)},t&&re(r,t),r}function qr(e){let t=Error(e);return t.hint="Use letters, numbers, - and _, like `feature-auth`",t}function Jr(e,t){let n=x(e,t);if(n)return n;if(!E.existsSync(e))return{master:{tasks:[],metadata:{created:(/* @__PURE__ */ new Date()).toISOString(),description:`Tasks for master context`}}};throw Error(`Could not read tasks file at ${e}`)}async function Yr(e,t,n={},r={},i=`text`){let{mcpLog:a,projectRoot:o}=r,{copyFromCurrent:s=!1,copyFromTag:c,description:l,defaultDescription:u=`Tag created on ${(/* @__PURE__ */ new Date()).toLocaleDateString()}`}=n,d=a||{info:(...e)=>v(`info`,...e),warn:(...e)=>v(`warn`,...e),error:(...e)=>v(`error`,...e),debug:(...e)=>v(`debug`,...e),success:(...e)=>v(`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 qr(`"${t}" isn't a valid tag name`);if([`master`,`main`,`default`].includes(t.toLowerCase()))throw Error(`"${t}" is a reserved tag name`);d.debug(`Creating new tag: ${t}`);let n=Jr(e,o),r;if(n._rawTaggedData)r=n._rawTaggedData;else if(n.tasks&&!n.master)r={master:{tasks:n.tasks,metadata:n.metadata||{created:(/* @__PURE__ */ new Date()).toISOString(),updated:(/* @__PURE__ */ new Date()).toISOString(),description:`Tasks live here by default`}}};else{r={};for(let[e,t]of Object.entries(n))e!==`_rawTaggedData`&&e!==`tag`&&(r[e]=t)}if(r[t])throw Error(`Tag "${t}" already exists`);let a=[];if(s||c){let e=c||y(o);a=oe(r,e),c&&a.length===0&&d.warn(`Source tag "${c}" not found or has no tasks`),d.debug(`Copying ${a.length} tasks from tag "${e}"`)}else d.debug(`Creating empty tag (no tasks copied)`);r[t]={tasks:[...a],metadata:{created:(/* @__PURE__ */ new Date()).toISOString(),updated:(/* @__PURE__ */ new Date()).toISOString(),description:l||u}};let f={};for(let[e,t]of Object.entries(r))e!==`_rawTaggedData`&&(f[e]=t);return le(e,f,o),d.debug(`Successfully created tag "${t}"`),i===`json`||i===`text`&&console.log(or({tagName:t,tasksCopied:a.length,sourceTag:s||c?c||y(o):null,description:l})),{tagName:t,created:!0,tasksCopied:a.length,sourceTag:s||c?c||y(o):null,description:l||u}}catch(e){throw a&&d.error(`Error creating tag: ${e.message}`),e}}async function Xr(e,t,n={},r={},i=`text`){let{mcpLog:a,projectRoot:o}=r,{yes:s=!1}=n,c=a||{info:(...e)=>v(`info`,...e),warn:(...e)=>v(`warn`,...e),error:(...e)=>v(`error`,...e),debug:(...e)=>v(`debug`,...e),success:(...e)=>v(`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.debug(`Deleting tag: ${t}`);let n=x(e,o);if(!n)throw Error(`Could not read tasks file at ${e}`);let r;if(n._rawTaggedData)r=n._rawTaggedData;else if(n.tasks&&!n.master)r={master:{tasks:n.tasks,metadata:n.metadata||{created:(/* @__PURE__ */ new Date()).toISOString(),updated:(/* @__PURE__ */ new Date()).toISOString(),description:`Tasks live here by default`}}};else{r={};for(let[e,t]of Object.entries(n))e!==`_rawTaggedData`&&e!==`tag`&&(r[e]=t)}if(!r[t])throw Error(`Tag "${t}" does not exist`);let a=y(o)===t,l=oe(r,t).length;if(!s&&l>0&&i===`text`){let e=`tag ${t} and its ${l===1?`task`:`${l} tasks`}`;if(!(process.stdin.isTTY&&process.stdout.isTTY)){let t=/* @__PURE__ */ Error(`Deleting ${e} needs confirmation`);throw t.hint="Pass `--yes` to delete it without asking",t}let n=!1;try{let t=A.createPromptModule({clearPromptOnDone:!0});({proceed:n}=await t([{type:`confirm`,name:`proceed`,message:`Delete ${e}? This can't be undone.`,default:!1}]))}catch(e){if(e?.name!==`ExitPromptError`)throw e;console.log(b.muted(`Cancelled; nothing was deleted`)),process.exit(130)}if(!n)return console.log(b.muted(`Cancelled; nothing was deleted`)),{tagName:t,deleted:!1,cancelled:!0}}return await ve(e,e=>(delete e[t],e)),a&&(await Z(o,`master`),c.debug(`Switched current tag to "master"`)),c.debug(`Successfully deleted tag "${t}"`),i===`json`||i===`text`&&console.log(ur({tagName:t,tasksDeleted:l,switchedToMaster:a})),{tagName:t,deleted:!0,tasksDeleted:l,wasCurrentTag:a,switchedToMaster:a}}catch(e){throw a&&c.error(`Error deleting tag: ${e.message}`),e}}async function Zr(e,t,n={}){let r=!1;try{let i;try{let t=E.statSync(e);i=t.birthtime<t.mtime?t.birthtime:t.mtime}catch{i=/* @__PURE__ */ new Date}for(let[e,n]of Object.entries(t))e!==`tasks`&&e!==`tag`&&e!==`_rawTaggedData`&&n&&typeof n==`object`&&Array.isArray(n.tasks)&&(n.metadata||(n.metadata={},r=!0),n.metadata.created||(n.metadata.created=i.toISOString(),r=!0),n.metadata.description||(e===`master`?n.metadata.description=`Tasks live here by default`:n.metadata.description=`Tag created on ${new Date(n.metadata.created).toLocaleDateString()}`,r=!0),n.metadata.updated||(n.metadata.updated=n.metadata.created,r=!0));if(r){let r={};for(let[e,n]of Object.entries(t))e!==`_rawTaggedData`&&(r[e]=n);le(e,r,n.projectRoot)}}catch(e){(n.mcpLog||{warn:(...e)=>v(`warn`,...e)}).warn(`Could not enhance tag metadata: ${e.message}`)}return r}async function Qr(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)=>v(`info`,...e),warn:(...e)=>v(`warn`,...e),error:(...e)=>v(`error`,...e),debug:(...e)=>v(`debug`,...e),success:(...e)=>v(`success`,...e)};try{l.debug(`Listing available tags`),l.debug(`Using file storage for tags`);let t=Jr(e,a),i=y(a),o=t._rawTaggedData||t;await Zr(e,o,n);let u=[];for(let[e,t]of Object.entries(o)){if(e===`tasks`||e===`tag`||e===`_rawTaggedData`||!t||typeof t!=`object`||!Array.isArray(t.tasks))continue;let n=t.tasks||[],r=t.metadata||{},a=n.map(e=>({...e,blocks:[]})),o=h(a);u.push({name:e,isCurrent:e===i,completedTasks:n.filter(e=>_(e.status)).length,readyTasks:o.length,tasks:n||[],created:r.created||`Unknown`,description:r.description||`No description`})}u.sort((e,t)=>e.isCurrent?-1:t.isCurrent?1:e.name.localeCompare(t.name));let d=u;return c&&(d=u.filter(e=>e.readyTasks>0),l.debug(`Filtered to ${d.length} tags with ready tasks`)),l.debug(`Found ${d.length} tags`),r===`json`||r===`text`&&console.log(dr(d.map(e=>({name:e.name,isCurrent:e.isCurrent,taskCount:e.tasks.length,readyTasks:e.readyTasks,completedTasks:e.completedTasks,created:e.created,description:e.description})),{showMetadata:s,ready:c})),{tags:d,currentTag:i,totalTags:d.length}}catch(e){throw i&&l.error(`Error listing tags: ${e.message}`),e}}async function $r(e,t,n={},r={},i=`text`){let{mcpLog:a,projectRoot:o}=r,s=a||{info:(...e)=>v(`info`,...e),warn:(...e)=>v(`warn`,...e),error:(...e)=>v(`error`,...e),debug:(...e)=>v(`debug`,...e),success:(...e)=>v(`success`,...e)};try{if(!t||typeof t!=`string`)throw Error(`Tag name is required and must be a string`);s.debug(`Switching to tag: ${t}`),s.debug(`Using file storage for tag switch`);let n=x(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=y(o);await Z(o,t);let a=x(e,o,t),c=a&&a.tasks||[],l=c.length,u=Kr(c);return s.debug(`Successfully switched to tag "${t}"`),i===`json`||i===`text`&&console.log(sr({previousTag:r,currentTag:t,taskCount:l,nextTask:u})),{previousTag:r,currentTag:t,switched:!0,taskCount:l,nextTask:u}}catch(e){throw a&&s.error(`Error switching tag: ${e.message}`),e}}async function ei(e,t,n,r={},i={},a=`text`){let{mcpLog:o,projectRoot:s}=i,c=o||{info:(...e)=>v(`info`,...e),warn:(...e)=>v(`warn`,...e),error:(...e)=>v(`error`,...e),debug:(...e)=>v(`debug`,...e),success:(...e)=>v(`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 qr(`"${n}" isn't a valid tag name`);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.debug(`Renaming tag from "${t}" to "${n}"`);let r=x(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=y(s)===t;i[n]={...i[t]},i[n].metadata&&(i[n].metadata.renamed={from:t,date:(/* @__PURE__ */ new Date()).toISOString()}),delete i[t],o&&(await Z(s,n),c.debug(`Updated current tag reference to "${n}"`));let l={};for(let[e,t]of Object.entries(i))e!==`_rawTaggedData`&&(l[e]=t);le(e,l,s);let u=oe(i,n).length;return c.debug(`Successfully renamed tag from "${t}" to "${n}"`),a===`json`||a===`text`&&console.log(cr({oldName:t,newName:n,isCurrentTag:o})),{oldName:t,newName:n,renamed:!0,taskCount:u,wasCurrentTag:o,isCurrentTag:o}}catch(e){throw o&&c.error(`Error renaming tag: ${e.message}`),e}}async function ti(e,t,n,r={},i={},a=`text`){let{mcpLog:o,projectRoot:s}=i,{description:c}=r,l=o||{info:(...e)=>v(`info`,...e),warn:(...e)=>v(`warn`,...e),error:(...e)=>v(`error`,...e),debug:(...e)=>v(`debug`,...e),success:(...e)=>v(`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 qr(`"${n}" isn't a valid tag name`);if([`master`,`main`,`default`].includes(n.toLowerCase()))throw Error(`"${n}" is a reserved tag name`);l.debug(`Copying tag from "${t}" to "${n}"`);let r=x(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=oe(i,t);i[n]={tasks:JSON.parse(JSON.stringify(o)),metadata:{created:(/* @__PURE__ */ new Date()).toISOString(),updated:(/* @__PURE__ */ new Date()).toISOString(),description:c||`Copy of "${t}" created on ${(/* @__PURE__ */ new Date()).toLocaleDateString()}`,copiedFrom:{tag:t,date:(/* @__PURE__ */ new Date()).toISOString()}}};let u={};for(let[e,t]of Object.entries(i))e!==`_rawTaggedData`&&(u[e]=t);return le(e,u,s),l.debug(`Successfully copied tag from "${t}" to "${n}"`),a===`json`||a===`text`&&console.log(lr({sourceName:t,targetName:n,tasksCopied:o.length})),{sourceName:t,targetName:n,copied:!0,description:c||`Copy of "${t}" created on ${(/* @__PURE__ */ new Date()).toLocaleDateString()}`}}catch(e){throw o&&l.error(`Error copying tag: ${e.message}`),e}}async function Z(e,t){try{let n=we.join(e,`.taskgraph`,`state.json`),r={};if(E.existsSync(n)){let e=E.readFileSync(n,`utf8`);r=JSON.parse(e)}r.currentTag=t,r.lastSwitched=(/* @__PURE__ */ new Date()).toISOString(),r.branchTagMapping||(r.branchTagMapping={}),r.migrationNoticeShown===void 0&&(r.migrationNoticeShown=!1),E.writeFileSync(n,JSON.stringify(r,null,2),`utf8`)}catch(e){v(`warn`,`Could not update current tag in state.json: ${e.message}`)}}async function ni(e,t,n){try{let r=we.join(e,`.taskgraph`,`state.json`),i={};if(E.existsSync(r)){let e=E.readFileSync(r,`utf8`);i=JSON.parse(e)}i.branchTagMapping||(i.branchTagMapping={}),i.branchTagMapping[t]=n,E.writeFileSync(r,JSON.stringify(i,null,2),`utf8`)}catch(e){v(`warn`,`Could not update branch-tag mapping: ${e.message}`)}}async function ri(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-CRR3iPaC.js`),p=a||{info:(...e)=>v(`info`,...e),warn:(...e)=>v(`warn`,...e),error:(...e)=>v(`error`,...e),debug:(...e)=>v(`debug`,...e),success:(...e)=>v(`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.debug(`Creating tag "${n}" from git branch "${t}"`);let a=await Yr(e,n,{copyFromCurrent:s,copyFromTag:c,description:l,defaultDescription:`Tag created from git branch "${t}"`},r,i);return await ni(o,t,n),p.debug(`Updated branch-tag mapping: ${t} -> ${n}`),u&&(await Z(o,n),p.debug(`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 a&&p.error(`Error creating tag from branch: ${e.message}`),e}}function ii(e,t){return Object.assign(Error(e),{hint:t})}var ai=class e extends D{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`,`
105
- Examples:
106
- $ tm tags # List all tags (default)
107
- $ tm tags list # List all tags (explicit)
108
- $ tm tags list --show-metadata # List with metadata
109
- $ tm tags list --ready # Show only tags with parallelizable work
110
- `).action(async e=>{await this.executeList(e)})}addAddCommand(){this.command(`add`).description(`Create a new tag`).argument(`[name]`,`Name of the tag to create (omit with --from-branch)`).option(`--description <desc>`,`Tag description`).option(`--copy-from <tag>`,`Copy tasks from another tag`).option(`--from-branch`,`Create tag from current git branch name`).addHelpText(`after`,`
111
- Examples:
112
- $ tm tags add feature-auth # Create new tag
113
- $ tm tags add sprint-2 --copy-from sprint-1 # Create with tasks copied
114
- $ tm tags add --from-branch # Create from current git branch
115
- `).action(async(e,t)=>{await this.executeAdd(e,t)})}addUseCommand(){this.command(`use`).description(`Switch to a different tag`).argument(`<name>`,`Name or ID of the tag to switch to`).addHelpText(`after`,`
116
- Examples:
117
- $ tm tags use feature-auth # Switch by name
118
- $ tm tags use abc123 # Switch by ID (last 8 chars)
119
- `).action(async e=>{await this.executeUse(e)})}addRemoveCommand(){this.command(`remove`).description(`Remove a tag`).argument(`<name>`,`Name or ID of the tag to remove`).option(`-y, --yes`,`Skip confirmation prompt`).addHelpText(`after`,`
120
- Examples:
121
- $ tm tags remove old-feature # Remove tag with confirmation
122
- $ tm tags remove old-feature -y # Remove without confirmation
123
-
124
- Warning: This will delete all tasks in the tag!
125
- `).action(async(e,t)=>{await this.executeRemove(e,t)})}addRenameCommand(){this.command(`rename`).description(`Rename a tag`).argument(`<oldName>`,`Current tag name`).argument(`<newName>`,`New tag name`).addHelpText(`after`,`
126
- Examples:
127
- $ tm tags rename old-name new-name
128
- `).action(async(e,t)=>{await this.executeRename(e,t)})}addCopyCommand(){this.command(`copy`).description(`Copy a tag with all its tasks`).argument(`<source>`,`Source tag name`).argument(`<target>`,`Target tag name`).option(`--description <desc>`,`Description for the new tag`).addHelpText(`after`,`
129
- Examples:
130
- $ taskgraph tags copy sprint-1 sprint-2
131
- $ taskgraph tags copy sprint-1 sprint-2 --description "Next sprint tasks"
132
- `).action(async(e,t,n)=>{await this.executeCopy(e,t,n)})}async initTmCore(){this.tmCore||=await u({projectPath:process.cwd()})}async executeList(e){try{await this.initTmCore();let{projectRoot:t,tasksPath:n}=g(),r=await Qr(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){J(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{if(e&&t?.fromBranch)throw ii(`Give a tag name or --from-branch, not both`,`--from-branch names the tag after the current git branch`);if(!e&&!t?.fromBranch)throw ii(`tags add needs a tag name`,"Example: `taskgraph tags add feature-auth`, or `--from-branch`");await this.initTmCore();let{projectRoot:i,tasksPath:a}=g(),o={description:t?.description,copyFromTag:t?.copyFrom};if(t?.fromBranch){let t="Name the tag instead: `taskgraph tags add <name>`";if(!await r(i))throw ii(`--from-branch needs a git repository, and this isn't one`,t);let s=await n(i);if(!s||s===`HEAD`)throw ii(`Couldn't tell which git branch is checked out`,t);e=(await ri(a,s,o,{projectRoot:i},`text`)).tagName}else await Yr(a,e,o,{projectRoot:i},`text`);this.setLastResult({success:!0,action:`add`,message:`Created tag: ${e}`})}catch(e){J(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}=g(),r=await $r(n,e,{},{projectRoot:t},`text`);this.setLastResult({success:!0,action:`use`,currentTag:r.currentTag,message:`Switched to tag: ${e}`})}catch(e){J(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}=g(),i=await Xr(r,e,{yes:t?.yes||!1},{projectRoot:n},`text`);this.setLastResult({success:!0,action:`remove`,message:i?.cancelled?`Cancelled; tag ${e} was not removed`:`Removed tag: ${e}`})}catch(e){J(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}=g();await ei(r,e,t,{},{projectRoot:n},`text`),this.setLastResult({success:!0,action:`rename`,message:`Renamed tag from "${e}" to "${t}"`})}catch(e){J(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}=g();await ti(i,e,t,{description:n?.description},{projectRoot:r},`text`),this.setLastResult({success:!0,action:`copy`,message:`Copied tag from "${e}" to "${t}"`})}catch(e){J(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}},oi=class e extends D{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 (${i.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(`--trust`,`Run Claude without permission prompts in this project, without asking first (for scripts)`).option(`--no-output`,`Exclude full Claude output from iteration results`).option(`-v, --verbose`,`Show Claude's work in real-time`).action(e=>this.execute(e))}async execute(e){let t=e.prompt||`default`,n=e.progressFile||`.taskgraph/progress.txt`;try{let r=w.resolve(Y(e.project));this.tmCore=await u({projectPath:r});let i=t==="default"?await this.tmCore.tasks.getCount(`pending`,e.tag):void 0,a=this.tmCore.loop.resolveIterations({userIterations:e.iterations?parseInt(e.iterations,10):void 0,preset:t,pendingTaskCount:i});if(this.validateIterations(String(a)),K({tag:e.tag||`master`}),e.sandbox&&this.handleSandboxAuth(),!e.sandbox&&!e.trust&&await this.confirmTrust(),console.log(C.cyan(`Starting TaskGraph Loop...`)),console.log(C.dim(`Preset: ${t}`)),console.log(C.dim(`Max iterations: ${a}`)),console.log(C.dim(`Mode: ${e.sandbox?`Docker sandbox`:`Claude CLI`}`)),t==="default"){let t=await this.tmCore.tasks.getNext(e.tag);console.log(t?b.text(`Next task to work on: ${b.text(t.id)} - ${t.title}`):C.yellow(`No pending tasks found`))}console.log();let o={iterations:a,prompt:t,progressFile:n,tag:e.tag,sandbox:e.sandbox,trusted:e.trust,includeOutput:e.output??!0,verbose:e.verbose??!1,callbacks:this.createOutputCallbacks()},s=await this.tmCore.loop.run(o);this.displayResult(s),(s.finalStatus===`error`||s.finalStatus===`blocked`)&&(process.exitCode=1)}catch(e){J(e,{skipExit:!0}),process.exit(1)}}async confirmTrust(){if(this.tmCore.loop.isTrusted())return;if(!process.stdin.isTTY||!process.stdout.isTTY)throw Error(`loop runs Claude with permission prompts off. Pass --trust to allow that here, or --sandbox to run in Docker.`);let{confirmed:e}=await A.prompt([{type:`confirm`,name:`confirmed`,message:`loop runs Claude with permission prompts off: it can read, edit and run anything in this project without asking. Allow that here?`,default:!1}]);if(!e)throw Error(`Not approved. Use --sandbox to run in Docker.`);this.tmCore.loop.trust()}handleSandboxAuth(){console.log(C.dim(`Checking sandbox auth...`));let e=this.tmCore.loop.checkSandboxAuth();if(e.error)throw Error(e.error);if(e.ready){console.log(C.green(`✓ Sandbox ready`));return}console.log(C.yellow(`Sandbox needs authentication. Starting interactive session...`)),console.log(C.dim(`Please complete auth, then Ctrl+C to continue.
133
- `));let t=this.tmCore.loop.runInteractiveAuth();if(!t.success)throw Error(t.error||`Interactive authentication failed`);console.log(C.green(`✓ Auth complete
134
- `))}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(C.cyan(`━━━ Iteration ${e} of ${t} ━━━`))},onText:e=>{console.log(e)},onToolUse:e=>{console.log(C.dim(` → ${e}`))},onError:(e,t)=>{console.error(t===`warning`?C.yellow(`[Loop Warning] ${e}`):C.red(`[Loop Error] ${e}`))},onStderr:(e,t)=>{process.stderr.write(C.dim(`[Iteration ${e}] `)+t)},onOutput:e=>{console.log(e)},onIterationEnd:e=>{let t=e.status===`success`?C.green:e.status===`error`?C.red:C.yellow;console.log(t(` Iteration ${e.iteration} completed: ${e.status}`))}}}displayResult(e){console.log(),console.log(C.bold(`Loop Complete`)),console.log(C.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(C.red(`Error: ${e.errorMessage}`))}formatStatus(e){return{all_complete:C.green(`All tasks complete`),max_iterations:C.yellow(`Max iterations reached`),blocked:C.red(`Blocked`),error:C.red(`Error`)}[e]}static register(t,n){let r=new e(n);return t.addCommand(r),r}};function si(e,t={}){let n=t.home??Ee.homedir(),r=t.env??process.env,i=t.platform??process.platform;switch(e){case`zsh`:return{script:w.join(n,`.taskgraph-completion.zsh`),rc:w.join(r.ZDOTDIR||n,`.zshrc`)};case`bash`:{let e=w.join(n,`.bash_profile`),t=i===`darwin`&&T.existsSync(e)?e:w.join(n,`.bashrc`);return{script:w.join(n,`.taskgraph-completion.bash`),rc:t}}case`fish`:return{script:w.join(r.XDG_CONFIG_HOME||w.join(n,`.config`),`fish`,`completions`,`taskgraph.fish`)}}}function Q(e,t=Ee.homedir()){return e===t||e.startsWith(t+w.sep)?`~${e.slice(t.length)}`:e}function ci(e,t,n={}){let r=n.home??Ee.homedir(),i=si(e,n),a=T.existsSync(i.script);if(T.mkdirSync(w.dirname(i.script),{recursive:!0}),T.writeFileSync(i.script,t),!i.rc)return{...i,replaced:a,rcUpdated:!1};let o=i.script.startsWith(r+w.sep)?`$HOME${i.script.slice(r.length)}`:i.script,s=T.existsSync(i.rc)?T.readFileSync(i.rc,`utf8`):``;if(s.includes(o)||s.includes(i.script))return{...i,replaced:a,rcUpdated:!1};let c=s===``||s.endsWith(`
135
- `)?``:`
136
- `;return T.appendFileSync(i.rc,`${c}\n# TaskGraph Tab completion\n[ -f "${o}" ] && source "${o}"\n`),{...i,replaced:a,rcUpdated:!0}}function li(e){return JSON.stringify(e).replace(/'/g,`\\u0027`).replace(/\\\\/g,`\\u005c`).replace(/`/g,`\\u0060`)}function ui(e){return`var SPEC = ${li(e)};\n
137
- var fs = require("fs");
138
- var path = require("path");
139
- var args = process.argv.slice(1);
140
- var shell = args.shift();
141
- var words = shell === "bash" ? joinEquals(args) : args;
142
- if (!words.length) words = [""];
143
-
144
- function joinEquals(ws) {
145
- var out = [];
146
- for (var i = 0; i < ws.length; i++) {
147
- var last = out[out.length - 1];
148
- if (ws[i] === "=" && last && last.charAt(0) === "-" && last.indexOf("=") < 0) {
149
- out[out.length - 1] = last + "=" + (i + 1 < ws.length ? ws[++i] : "");
150
- } else {
151
- out.push(ws[i]);
152
- }
153
- }
154
- return out;
155
- }
156
-
157
- function findOption(cmd, flag) {
158
- for (var i = 0; i < cmd.options.length; i++) {
159
- var o = cmd.options[i];
160
- if (o.long === flag || o.short === flag) return o;
161
- }
162
- return null;
163
- }
164
-
165
- function findCommand(cmd, name) {
166
- for (var i = 0; i < cmd.commands.length; i++) {
167
- var c = cmd.commands[i];
168
- if (c.name === name || c.aliases.indexOf(name) >= 0) return c;
169
- }
170
- return null;
171
- }
172
-
173
- function emit(mode, optPrefix, listPrefix, label, items) {
174
- var lines = ["@" + mode, "@" + optPrefix, "@" + listPrefix, "@" + label];
175
- for (var i = 0; i < items.length; i++) {
176
- lines.push(items[i][1] ? items[i][0] + "\\t" + items[i][1] : items[i][0]);
177
- }
178
- process.stdout.write(lines.join("\\n") + "\\n");
179
- process.exit(0);
180
- }
181
-
182
- function startsWith(s, p) {
183
- return s.slice(0, p.length) === p;
184
- }
185
-
186
- function findProject(start) {
187
- var dir = path.resolve(start);
188
- for (;;) {
189
- var file = path.join(dir, ".taskgraph", "tasks", "tasks.json");
190
- if (fs.existsSync(file)) return { dir: dir, file: file };
191
- var up = path.dirname(dir);
192
- if (up === dir) return null;
193
- dir = up;
194
- }
195
- }
196
-
197
- function readProject() {
198
- var project = findProject(projectDir || process.cwd());
199
- if (!project) return null;
200
- var data;
201
- try {
202
- data = JSON.parse(fs.readFileSync(project.file, "utf8"));
203
- } catch (e) {
204
- return null;
205
- }
206
- if (Array.isArray(data.tasks)) return { tags: [], tasks: data.tasks };
207
- var tags = Object.keys(data).filter(function (k) {
208
- return data[k] && Array.isArray(data[k].tasks);
209
- });
210
- var tag = tagOverride || process.env.TASKGRAPH_TAG;
211
- if (!tag) {
212
- try {
213
- var state = JSON.parse(
214
- fs.readFileSync(path.join(project.dir, ".taskgraph", "state.json"), "utf8")
215
- );
216
- tag = state.currentTag || state.activeTag;
217
- } catch (e) {}
218
- }
219
- if (!data[tag]) tag = tags.indexOf("master") >= 0 ? "master" : tags[0];
220
- return { tags: tags, tasks: tag ? data[tag].tasks : [] };
221
- }
222
-
223
- function taskIds(tasks) {
224
- var out = [];
225
- (function walk(list, parent) {
226
- for (var i = 0; i < (list || []).length; i++) {
227
- var t = list[i];
228
- var raw = String(t.id);
229
- var id = parent && raw.indexOf(".") < 0 ? parent + "." + raw : raw;
230
- var title = String(t.title || "").split(/\\s+/).join(" ").trim();
231
- out.push([id, t.status ? title + " (" + t.status + ")" : title]);
232
- walk(t.subtasks, id);
233
- }
234
- })(tasks, "");
235
- return out;
236
- }
237
-
238
- function completeValue(value, text, optPrefix) {
239
- if (value.kind === "files" || value.kind === "dirs") {
240
- emit(value.kind, optPrefix, "", value.kind, []);
241
- }
242
- var comma = value.kind === "ids" ? text.lastIndexOf(",") : -1;
243
- var listPrefix = comma < 0 ? "" : text.slice(0, comma + 1);
244
- var partial = text.slice(comma + 1);
245
- var taken = listPrefix.split(",");
246
- var items = [];
247
- var label = "values";
248
- if (value.kind === "choices") {
249
- items = value.choices.map(function (c) { return [c, ""]; });
250
- } else if (value.kind === "ids" || value.kind === "tags") {
251
- var project = readProject();
252
- if (project && value.kind === "ids") {
253
- items = taskIds(project.tasks);
254
- label = "task IDs";
255
- } else if (project) {
256
- items = project.tags.map(function (t) { return [t, ""]; });
257
- label = "tags";
258
- }
259
- }
260
- items = items.filter(function (it) {
261
- return startsWith(it[0], partial) && taken.indexOf(it[0]) < 0;
262
- });
263
- emit("values", optPrefix, listPrefix, label, items);
264
- }
265
-
266
- function completeOptions(cmd, cur, used) {
267
- var items = [];
268
- for (var i = 0; i < cmd.options.length; i++) {
269
- var o = cmd.options[i];
270
- if ((used[o.long] || used[o.short]) && !o.variadic) continue;
271
- if (o.long && startsWith(o.long, cur)) items.push([o.long, o.description]);
272
- else if (o.short && startsWith(o.short, cur) && cur.slice(0, 2) !== "--") {
273
- items.push([o.short, o.description]);
274
- }
275
- }
276
- emit("values", "", "", "options", items);
277
- }
278
-
279
- var cmd = SPEC;
280
- var positional = 0;
281
- var used = {};
282
- var expecting = null;
283
- var projectDir = null;
284
- var tagOverride = null;
285
- var cur = words[words.length - 1];
286
- var before = words.slice(0, -1);
287
-
288
- for (var i = 0; i < before.length; i++) {
289
- var w = before[i];
290
- if (w.length > 1 && w.charAt(0) === "-") {
291
- var eq = w.indexOf("=");
292
- var flag = eq < 0 ? w : w.slice(0, eq);
293
- var opt = findOption(cmd, flag);
294
- used[flag] = true;
295
- if (!opt || !opt.value) continue;
296
- var val = eq < 0 ? before[i + 1] : w.slice(eq + 1);
297
- if (eq < 0 && opt.optional && val !== undefined && val.charAt(0) === "-") continue;
298
- if (eq < 0 && i + 1 >= before.length) expecting = opt;
299
- else if (eq < 0) i++;
300
- if (opt.long === "--project") projectDir = val;
301
- if (opt.long === "--tag") tagOverride = val;
302
- continue;
303
- }
304
- var sub = positional === 0 ? findCommand(cmd, w) : null;
305
- if (sub) {
306
- cmd = sub;
307
- used = {};
308
- } else {
309
- positional++;
310
- }
311
- }
312
-
313
- if (expecting) completeValue(expecting.value, cur, "");
314
-
315
- if (cur.charAt(0) === "-") {
316
- var eqAt = cur.indexOf("=");
317
- if (eqAt > 0) {
318
- var o = findOption(cmd, cur.slice(0, eqAt));
319
- if (o && o.value) completeValue(o.value, cur.slice(eqAt + 1), cur.slice(0, eqAt + 1));
320
- emit("values", "", "", "values", []);
321
- }
322
- completeOptions(cmd, cur, used);
323
- }
324
-
325
- if (positional === 0 && cmd.commands.length) {
326
- emit(
327
- "values", "", "", "commands",
328
- cmd.commands
329
- .filter(function (c) { return startsWith(c.name, cur); })
330
- .map(function (c) { return [c.name, c.description]; })
331
- .sort(function (a, b) { return a[0] < b[0] ? -1 : 1; })
332
- );
333
- }
334
-
335
- var arg = cmd.args[positional];
336
- if (!arg && cmd.args.length && cmd.args[cmd.args.length - 1].variadic) {
337
- arg = cmd.args[cmd.args.length - 1];
338
- }
339
- if (arg && arg.value.kind !== "none") completeValue(arg.value, cur, "");
340
- if (!arg && cur === "") completeOptions(cmd, cur, used);
341
- emit("values", "", "", "values", []);
342
- `}const di=[`bash`,`zsh`,`fish`];function fi(e){return di.includes(e)}function pi(e=process.env.SHELL){let t=(e||``).split(`/`).pop()||``;return fi(t)?t:void 0}function mi(e){switch(e){case`bash`:return[`taskgraph completion bash > ~/.taskgraph-completion.bash`,`echo 'source ~/.taskgraph-completion.bash' >> ~/.bashrc`];case`zsh`:return[`taskgraph completion zsh > ~/.taskgraph-completion.zsh`,`echo 'source ~/.taskgraph-completion.zsh' >> ~/.zshrc`];case`fish`:return[`mkdir -p ~/.config/fish/completions`,`taskgraph completion fish > ~/.config/fish/completions/taskgraph.fish`]}}function hi(e,t){return[`# TaskGraph completion for ${e} (taskgraph ${t})`,`# Install or update with: taskgraph completion --install`,`# Run that again after upgrading TaskGraph.`].join(`
343
- `)}function gi(e){return`__taskgraph_program='${e}'
344
-
345
- _taskgraph() {
346
- local cur="\${COMP_WORDS[COMP_CWORD]}" line i
347
- local -a out=()
348
- while IFS= read -r line; do
349
- out+=("$line")
350
- done < <(node -e "$__taskgraph_program" -- bash "\${COMP_WORDS[@]:1:COMP_CWORD}" 2>/dev/null)
351
- COMPREPLY=()
352
- [[ \${#out[@]} -ge 4 ]] || return 0
353
- local mode="\${out[0]#@}" listp="\${out[2]#@}"
354
- [[ "$cur" == "=" ]] && cur=""
355
- case "$mode" in
356
- files)
357
- compopt -o filenames 2>/dev/null
358
- while IFS= read -r line; do COMPREPLY+=("$line"); done < <(compgen -f -- "$cur")
359
- ;;
360
- dirs)
361
- compopt -o filenames 2>/dev/null
362
- while IFS= read -r line; do COMPREPLY+=("$line"); done < <(compgen -d -- "$cur")
363
- ;;
364
- *)
365
- compopt -o nosort 2>/dev/null
366
- for ((i = 4; i < \${#out[@]}; i++)); do
367
- COMPREPLY+=("$listp\${out[i]%%$'\\t'*}")
368
- done
369
- ;;
370
- esac
371
- }
372
-
373
- complete -F _taskgraph taskgraph
374
- if alias tm >/dev/null 2>&1; then
375
- complete -F _taskgraph tm
376
- fi
377
- `}function _i(e){return`__taskgraph_program='${e}'
378
-
379
- _taskgraph() {
380
- local -a out items
381
- local mode optp listp label line
382
- out=("\${(@f)$(node -e "$__taskgraph_program" -- zsh "\${(@)words[2,CURRENT]}" 2>/dev/null)}")
383
- (( \${#out} >= 4 )) || return 1
384
- mode=\${out[1]#@} optp=\${out[2]#@} listp=\${out[3]#@} label=\${out[4]#@}
385
- if [[ -n "$optp$listp" ]]; then
386
- IPREFIX="$IPREFIX$optp$listp"
387
- PREFIX="\${PREFIX#"$optp$listp"}"
388
- fi
389
- case $mode in
390
- files) _files ;;
391
- dirs) _files -/ ;;
392
- *)
393
- for line in "\${(@)out[5,-1]}"; do
394
- [[ -n "$line" ]] || continue
395
- if [[ "$line" == *$'\\t'* ]]; then
396
- items+=("\${\${line%%$'\\t'*}//:/\\\\:}:\${line#*$'\\t'}")
397
- else
398
- items+=("\${line//:/\\\\:}")
399
- fi
400
- done
401
- (( \${#items} )) || return 1
402
- _describe -V -t "\${label// /-}" "$label" items
403
- ;;
404
- esac
405
- }
406
-
407
- if [[ "\${zsh_eval_context[-1]}" == loadautofunc ]]; then
408
- _taskgraph "$@"
409
- else
410
- (( $+functions[compdef] )) || { autoload -Uz compinit && compinit }
411
- compdef _taskgraph taskgraph
412
- fi
413
- `}function vi(e){return`set -g __taskgraph_program '${e}'
414
-
415
- function __taskgraph_complete
416
- set -l tokens (commandline -opc)
417
- set -e tokens[1]
418
- set -l cur (commandline -ct)
419
- set -l out (node -e $__taskgraph_program -- fish $tokens "$cur" 2>/dev/null)
420
- test (count $out) -ge 4; or return
421
- set -l mode (string sub -s 2 -- $out[1])
422
- set -l optp (string sub -s 2 -- $out[2])
423
- set -l listp (string sub -s 2 -- $out[3])
424
- set -l value (string sub -s (math (string length -- "$optp") + 1) -- "$cur")
425
- switch $mode
426
- case files
427
- for p in (__fish_complete_path "$value")
428
- echo "$optp$p"
429
- end
430
- case dirs
431
- for p in (__fish_complete_directories "$value")
432
- echo "$optp$p"
433
- end
434
- case '*'
435
- test (count $out) -ge 5; or return
436
- for line in $out[5..-1]
437
- echo "$optp$listp$line"
438
- end
439
- end
440
- end
441
-
442
- complete -c taskgraph -f -k -a '(__taskgraph_complete)'
443
- `}function yi(e,t,n=`unknown`){let r=ui(t);if(r.includes(`'`)||r.includes(`\\\\`))throw Error(`Completion program cannot be quoted for the shell`);let i={bash:gi,zsh:_i,fish:vi}[e](r);return`${e===`zsh`?`#compdef taskgraph
444
- `:``}${hi(e,n)}\n\n${i}`}const bi=[`pending`,`in-progress`,`done`,`review`,`blocked`,`deferred`,`cancelled`],xi=[`high`,`medium`,`low`],Si=/* @__PURE__ */ new Set([`id`,`ids`,`taskid`,`task-id`,`parent`,`dependencies`]),Ci=/* @__PURE__ */ new Set([`tag`,`tagname`,`oldname`,`sourcename`,`source`,`name`]),wi=/* @__PURE__ */ new Set([`--tag`,`--from-tag`,`--to-tag`,`--copy-from`]),Ti=/* @__PURE__ */ new Set([`--from`,`--to`,`--save-to`]),Ei=/* @__PURE__ */ new Set([`file`,`files`,`paths`]),Di=/* @__PURE__ */ new Set([`dir`,`path`]),Oi=/* @__PURE__ */ new Set([`add`,`add-tag`]);function ki(e){let t=e.match(/[<[]([^>\]]+?)(?:\.\.\.)?[>\]]/);return t?t[1].toLowerCase():void 0}function Ai(e,t,n){if(t?.length)return{kind:`choices`,choices:[...t]};let r=n.long;return r===`--status`||e===`status`?{kind:`choices`,choices:bi}:r===`--priority`||e===`priority`?{kind:`choices`,choices:xi}:r===`--format`||e===`format`?{kind:`choices`,choices:[`text`,`json`]}:r&&wi.has(r)?{kind:`tags`}:r&&Ti.has(r)?{kind:`ids`}:r===`--project`||r===`--project-root`||r===`--output`?{kind:r===`--output`?`files`:`dirs`}:e?Si.has(e)?{kind:`ids`}:Ci.has(e)?Oi.has(n.command)?{kind:`none`}:{kind:`tags`}:Ei.has(e)?{kind:`files`}:Di.has(e)?{kind:`dirs`}:{kind:`none`}:{kind:`none`}}function ji(e,t){let n=e.required||e.optional;return{short:e.short,long:e.long,description:Ni(e.description),value:n?Ai(ki(e.flags),e.argChoices,{long:e.long,command:t}):void 0,...e.optional?{optional:!0}:{},...e.variadic?{variadic:!0}:{}}}function Mi(e,t){return{name:e.name(),variadic:e.variadic,value:Ai(e.name().toLowerCase(),e.argChoices,{command:t})}}function Ni(e){let t=(e||``).split(`
445
- `)[0].trim().replace(/^(.+?[.!?])\s.*$/,`$1`).replace(/\.$/,``);if(t.length<=60)return t;let n=t.slice(0,59),r=n.lastIndexOf(` `);return`${(r>30?n.slice(0,r):n).replace(/[\s,;:(]+$/,``)}…`}function Pi(e){return!!e._hidden||/^\[deprecated\]/i.test(e.description())}function Fi(e){let t=e=>{let n=e.name(),r=e.options.filter(e=>!e.hidden).map(e=>ji(e,n));return r.some(e=>e.long===`--help`)||r.push({short:`-h`,long:`--help`,description:`Show help`}),{name:n,aliases:e.aliases(),description:Ni(e.description()),options:r,args:e.registeredArguments.map(e=>Mi(e,n)),commands:e.commands.filter(e=>!Pi(e)).map(t)}};return t(e)}var Ii=class e extends D{constructor(e){super(e||`completion`),this.description(`Set up Tab completion for bash, zsh or fish`).addArgument(new De(`[shell]`,`Shell to complete for (default: yours)`).choices(di)).option(`--install`,`Install it and load it from your shell startup file`).option(`--script`,`Print the script even when writing to a terminal`).addHelpText(`after`,[``,`Examples:`,` taskgraph completion --install # set it up for your shell`,` taskgraph completion zsh > ~/.taskgraph-completion.zsh`].join(`
446
- `)).action((e,t)=>{this.executeCommand(e,t)})}executeCommand(e,t){try{let n=e??this.detectedShell();t.install?this.install(n):process.stdout.isTTY&&!t.script?this.displayInstructions(n,!e):process.stdout.write(this.script(n))}catch(e){J(e,{skipExit:!0}),process.exit(1)}}detectedShell(){let e=pi();if(!e)throw Error(`Couldn't tell which shell you use. Name it: taskgraph completion <${di.join(`|`)}>`);return e}script(e){let t=this;for(;t.parent;)t=t.parent;return yi(e,Fi(t),t.version()||`unknown`)}install(e){let t=ci(e,this.script(e)),n=C.green(`✓`);console.log(),console.log(`${n} ${t.replaced?`Updated`:`Wrote`} ${b.brand(Q(t.script))}`),t.rc&&t.rcUpdated?console.log(`${n} Loaded it from ${b.brand(Q(t.rc))}`):t.rc&&console.log(`${n} ${b.brand(Q(t.rc))} ${b.muted(`already loads it`)}`),console.log(),console.log(`Open a new terminal, then try ${b.brand(`taskgraph show <Tab>`)}`),console.log(b.muted(`Run this again after upgrading TaskGraph to pick up new commands.`))}displayInstructions(e,t){let n=si(e),r=n.rc?`Writes ${Q(n.script)} and loads it from ${Q(n.rc)}.`:`Writes ${Q(n.script)}.`;console.log(),console.log(C.bold(`Tab completion for ${e}`)),console.log(),console.log(` ${b.brand(`taskgraph completion --install`)}`),console.log(` ${b.muted(r)}`),console.log(),console.log(b.muted(`Or by hand:`));for(let t of mi(e))console.log(` ${t}`);if(t){let t=di.filter(t=>t!==e).join(`|`);console.log(),console.log(b.muted(`Not using ${e}? Name your shell: taskgraph completion <${t}> --install`))}}static register(t,n){let r=new e(n);return t.addCommand(r),r}},$=class{useJson;constructor(e){this.useJson=e}output(e){this.useJson?console.log(JSON.stringify(e,null,2)):this.outputText(e)}outputText(e){for(let[t,n]of Object.entries(e))typeof n==`object`&&n?(console.log(C.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(C.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(C.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(C.green(`✓ ${e}`)),t&&this.output(t))}warning(e){this.useJson?console.warn(JSON.stringify({warning:e},null,2)):console.warn(C.yellow(`⚠ ${e}`))}info(e){this.useJson||console.log(b.brand(`ℹ ${e}`))}},Li=class extends D{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 $(e.json||t?.json||!1);try{let i=Y(e.projectRoot||t?.projectRoot);n={...n,projectRoot:i};let a=await u({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 A.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)}}},Ri=class extends D{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:Y(e.projectRoot||t?.projectRoot)},r=new $(n.json||!1);try{let e=n.projectRoot,t=await u({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(),o=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 s=new ne(e);await s.ensureGitRepository(),await s.hasStagedChanges()||(r.info(`No staged changes, staging all changes...`),await s.stageFiles([`.`]));let c=await s.getStatus(),l=[...c.staged,...c.modified],d=new a,f=o.lastTestResults,p=d.generateMessage({type:`feat`,description:i.currentSubtask.title,changedFiles:l,taskId:i.taskId,phase:i.tddPhase,tag:o.metadata.tag||void 0,testsPassing:f?.passed,testsFailing:f?.failed,coveragePercent:void 0});await s.createCommit(p,{metadata:{taskId:i.taskId,subtaskId:i.currentSubtask.id,phase:`COMMIT`,tddCycle:`complete`}});let m=await s.getLastCommit(),h=await t.workflow.commit(),g=h.phase===`COMPLETE`;r.success(`Commit created`,{commitHash:m.hash.substring(0,7),message:p.split(`
447
- `)[0],subtask:{id:i.currentSubtask.id,title:i.currentSubtask.title},progress:h.progress,nextAction:g?`All subtasks complete. Run: autopilot status`:`Start next subtask with RED phase`})}catch(e){r.error(e.message),n.verbose&&console.error(e.stack),process.exit(1)}}},zi=class extends D{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:Y(e.projectRoot||t?.projectRoot)},r=new $(n.json||!1);try{let e=n.projectRoot,t=await u({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)}}},Bi=class extends D{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 $(e.json||t?.json||!1);try{let i=Y(e.projectRoot||t?.projectRoot);n={...n,projectRoot:i};let a=await u({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)}}},Vi=class extends D{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 $(e.json||t?.json||!1);try{let i=Y(e.projectRoot||t?.projectRoot);n={...n,projectRoot:i};let a=await u({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,d=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:d,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)}}},Hi=class extends D{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:Y(e.projectRoot||t?.projectRoot)},r=new $(n.json||!1);try{let e=n.projectRoot,t=await u({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)}}},Ui=class extends D{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:Y(t.projectRoot||n?.projectRoot)},i=new $(r.json||!1);try{let t=f.safeParse(e);t.success||(i.error(`Invalid task ID format`,{taskId:e,error:t.error.issues[0]?.message}),process.exit(1));let n=t.data,a=r.projectRoot,o=await u({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 d=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:d.taskId,title:c.title,phase:d.phase,tddPhase:d.tddPhase,branchName:d.branchName,subtasks:c.subtasks.length,currentSubtask:d.currentSubtask?.title})}catch(e){i.error(e.message),r.verbose&&console.error(e.stack),process.exit(1)}}},Wi=class extends D{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:Y(e.projectRoot||t?.projectRoot)},r=new $(n.json||!1);try{let e=n.projectRoot,t=await u({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)}}},Gi=class e extends D{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 Ui),this.addCommand(new Hi),this.addCommand(new Vi),this.addCommand(new zi),this.addCommand(new Ri),this.addCommand(new Wi),this.addCommand(new Bi),this.addCommand(new Li)}static register(t){let n=new e;return t.addCommand(n),n}},Ki=class e extends D{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=Y(e.project);await this.initializeCore(t);let n=await this.generateFiles(t,e);this.lastResult=n,this.displayResults(n,e)}catch(e){t=!0,J(e,{skipExit:!0})}finally{await this.cleanup()}t&&process.exit(1)}validateOptions(e){if(e.format&&![`text`,`json`].includes(e.format))throw Error(`Invalid format: ${e.format}. Valid formats are: text, json`)}async initializeCore(e){if(!this.tmCore){let t=w.resolve(e);this.tmCore=await u({projectPath:t})}}async generateFiles(e,t){if(!this.tmCore)throw Error(`TmCore not initialized`);let n=t.output?w.resolve(e,t.output):void 0;return this.tmCore.tasks.generateTaskFiles({tag:t.tag,outputDir:n})}displayResults(e,t){switch(t.format||`text`){case`json`:this.displayJson(e);break;default:this.displayText(e,t)}}displayJson(e){console.log(JSON.stringify(e,null,2))}displayText(e,t){if(this.tmCore&&K({tag:t.tag||this.tmCore.config.getActiveTag()}),!e.success){console.log(O(C.red(`Error: ${e.error||`Unknown error`}`),{padding:1,borderStyle:`round`,borderColor:`red`,title:`Generation failed`,titleAlignment:`center`}));return}if(e.count===0){console.log(O(C.yellow(`No tasks found to generate files for.`),{padding:1,borderStyle:`round`,borderColor:`yellow`,title:`No tasks`,titleAlignment:`center`}));return}let n=`${C.green(`✓`)} Generated ${C.cyan(e.count)} task file(s)`;n+=`\n\n${C.dim(`Output directory:`)} ${e.directory}`,e.orphanedFilesRemoved>0&&(n+=`\n${C.dim(`Orphaned files removed:`)} ${e.orphanedFilesRemoved}`),console.log(O(n,{padding:1,borderStyle:`round`,borderColor:`green`,title:`Task files generated`,titleAlignment:`center`}))}getLastResult(){return this.lastResult}async cleanup(){this.tmCore&&=void 0}static register(t,n){let r=new e(n);return t.addCommand(r),r}};const qi={create:C.green,update:C.yellow,skip:b.muted,close:C.red};function Ji(e){let t={create:0,update:0,skip:0,close:0};for(let n of e.steps)t[n.action]++;return t}function Yi(e){let t=Ji(e);return t.create+t.update+t.close>0}function Xi(e){let t=qi[e.action](e.action.padEnd(6)),n=e.issueNumber?` -> #${e.issueNumber}`:``,r=e.reason?b.muted(` (${e.reason})`):``;return` ${t} [${e.tag}] ${e.taskId} ${e.title}${n}${r}`}function Zi(e){let t=Ji(e),n=[C.bold(`Plan for ${e.repo}`),` ${t.create} to create, ${t.update} to update, ${t.skip} unchanged, ${t.close} to close`];for(let t of e.steps.filter(e=>e.action!==`skip`))n.push(Xi(t));if(e.orphans.length>0){n.push(``,C.yellow(`${e.orphans.length} open issue(s) have no local task (pass --close-orphans to close them):`));for(let t of e.orphans)n.push(` #${t.issueNumber} ${t.title}`)}return n.join(`
448
- `)}function Qi(e){let t=e.dryRun?`would be `:``;return[C.bold(e.dryRun?`Dry run, nothing written`:`Push complete`),` ${t}created ${e.created}, ${t}updated ${e.updated}, unchanged ${e.skipped}, ${t}closed ${e.closed}`].join(`
449
- `)}const $i={apply:C.green,sync:b.muted,conflict:C.red,skip:b.muted};function ea(e){let t={apply:0,sync:0,conflict:0,skip:0};for(let n of e.steps)t[n.action]++;return t}function ta(e){let t=ea(e);return t.apply+t.sync>0}function na(e){return ea(e).apply>0}function ra(e){let t=$i[e.action](e.action.padEnd(8)),n=e.action===`conflict`?`local ${e.from}, GitHub ${e.to}`:`${e.from} -> ${e.to}`,r=e.issueNumber?` (#${e.issueNumber})`:``;return` ${t} [${e.tag}] ${e.taskId} ${e.title}${r} ${b.muted(n)}`}function ia(e){let t=ea(e),n=[C.bold(`Pull plan for ${e.repo}`),` ${t.apply} to update, ${t.sync} already in sync, ${t.conflict} conflict(s), ${t.skip} unchanged or skipped`];for(let t of e.steps.filter(e=>e.action!==`skip`))n.push(ra(t));return t.conflict>0&&n.push(``,C.yellow(`${t.conflict} task(s) changed on both sides and keep their local status. Run \`taskgraph github push\` to overwrite GitHub with it.`)),n.join(`
450
- `)}function aa(e){let t=e.dryRun?`would be `:``;return[C.bold(e.dryRun?`Dry run, nothing written`:`Pull complete`),` ${t}updated ${e.applied}, ${t}marked in sync ${e.synced}, conflicts ${e.conflicts}, skipped ${e.skipped}`].join(`
451
- `)}function oa(e){let t=e.ghAvailable?C.green(`available and signed in`):C.red("not available (install gh and run `gh auth login`)");return[C.bold(`GitHub`),` gh CLI: ${t}`,` repo: ${e.repo??b.muted(`not detected (use --repo owner/name)`)}`,` linked: ${e.linkedTasks} task(s)`,` unlinked: ${e.unlinkedTasks} task(s)`].join(`
452
- `)}function sa(e){return[`Unlinked task ${e.taskId} [${e.tag}] from issue #${e.issueNumber} (${e.url}).`,b.muted(`The issue was not changed. If it still carries its taskgraph marker, the next push will link it again.`)].join(`
453
- `)}var ca=class extends D{tmCore;constructor(e){super(e||`github`),this.description(`Push tasks to GitHub Issues and pull issue status back`),this.addStatusCommand(),this.addPushCommand(),this.addPullCommand(),this.addUnlinkCommand()}addStatusCommand(){this.command(`status`).description(`Show gh availability, target repo and linked task counts`).option(`--repo <owner/name>`,`Repository to check`).option(`-p, --project <path>`,`Project root directory`).option(`--json`,`Output as JSON`).action(e=>this.guard(e,()=>this.runStatus(e)))}addPushCommand(){this.command(`push`).description(`Create or update GitHub issues for tasks`).option(`--tag <name>`,`Tag to push (default: the active tag)`).option(`--all-tags`,`Push every tag`).option(`--id <ids>`,`Only push these task ids, comma separated`).option(`--dry-run`,`Show the plan without writing anything`).option(`-y, --yes`,`Write without asking for confirmation`).option(`--repo <owner/name>`,`Repository (default: detected via gh)`).option(`--include-details`,`Include task details in issue bodies`).option(`--close-orphans`,`Close open issues whose task is gone`).option(`-p, --project <path>`,`Project root directory`).option(`--json`,`Output as JSON (requires --yes or --dry-run)`).addHelpText(`after`,`
454
- Examples:
455
- $ taskgraph github push --dry-run # Preview the active tag
456
- $ taskgraph github push --all-tags -y # Push every tag without asking
457
- $ taskgraph github push --id 1,2 # Push only tasks 1 and 2
458
- `).action(e=>this.guard(e,()=>this.runPush(e)))}addPullCommand(){this.command(`pull`).description(`Update task statuses from their GitHub issues (status only, never writes to GitHub)`).option(`--tag <name>`,`Tag to pull (default: the active tag)`).option(`--all-tags`,`Pull every tag`).option(`--id <ids>`,`Only pull these task ids, comma separated`).option(`--dry-run`,`Show the plan without changing any task`).option(`-y, --yes`,`Update tasks without asking for confirmation`).option(`--repo <owner/name>`,`Repository (default: detected via gh)`).option(`-p, --project <path>`,`Project root directory`).option(`--json`,`Output as JSON (requires --yes or --dry-run)`).addHelpText(`after`,`
459
- A task that changed on GitHub and not locally takes the issue's status.
460
- A task that changed on both sides keeps its local status and is reported.
461
-
462
- Examples:
463
- $ taskgraph github pull --dry-run # Preview the active tag
464
- $ taskgraph github pull -y # Update tasks without asking
465
- `).action(e=>this.guard(e,()=>this.runPull(e)))}addUnlinkCommand(){this.command(`unlink`).description(`Forget the GitHub issue a task is linked to`).argument(`<id>`,`Task id`).option(`--tag <name>`,`Tag the task lives in`).option(`-p, --project <path>`,`Project root directory`).option(`--json`,`Output as JSON`).action((e,t)=>this.guard(t,()=>this.runUnlink(e,t)))}async guard(e,t){let n=!1;try{await this.initializeCore(e),await t()}catch(e){n=!0,J(e,{skipExit:!0})}finally{await this.tmCore?.close()}n&&process.exit(1)}async initializeCore(e){if(!this.tmCore){let t=w.resolve(Y(e.project));this.tmCore=await u({projectPath:t})}}core(){if(!this.tmCore)throw Error(`TmCore not initialized`);return this.tmCore}async runStatus(e){let t=await this.core().github.status({repo:e.repo});console.log(e.json?JSON.stringify(t,null,2):oa(t))}async runPush(e){let t=this.core(),n={repo:e.repo,tag:e.tag,allTags:e.allTags,taskIds:e.id,includeDetails:e.includeDetails,closeOrphans:e.closeOrphans};if(e.dryRun){let r=await t.github.push({...n,dryRun:!0});this.print(e,r,[Zi(r.plan),Qi(r)]);return}let r=await t.github.planPush(n);if(!Yi(r)){let i=await t.github.push({...n,dryRun:!0});this.print(e,{...i,dryRun:!1},[Zi(r),`GitHub is already up to date.`]);return}if(!e.yes){if(e.json||!this.isInteractive())throw Error(`Refusing to write to GitHub without confirmation. Pass --yes to proceed or --dry-run to preview.`);if(console.log(Zi(r)),!await this.confirm(`Write these changes to ${r.repo}?`)){console.log(`Cancelled. Nothing was written.`);return}}let i=await t.github.push({...n,dryRun:!1});this.print(e,i,[...e.yes?[Zi(i.plan)]:[],Qi(i)])}async runPull(e){let t=this.core(),n={repo:e.repo,tag:e.tag,allTags:e.allTags,taskIds:e.id};if(e.dryRun){let r=await t.github.pull({...n,dryRun:!0});this.print(e,r,[ia(r.plan),aa(r)]);return}let r=await t.github.planPull(n);if(!ta(r)){let i=await t.github.pull({...n,dryRun:!0});this.print(e,{...i,dryRun:!1},[ia(r),`Task statuses are already up to date.`]);return}if(na(r)&&!e.yes){if(e.json||!this.isInteractive())throw Error(`Refusing to change tasks without confirmation. Pass --yes to proceed or --dry-run to preview.`);if(console.log(ia(r)),!await this.confirm(`Update these task statuses?`)){console.log(`Cancelled. Nothing was changed.`);return}}let i=await t.github.pull({...n,dryRun:!1});this.print(e,i,[...e.yes?[ia(i.plan)]:[],aa(i)])}async runUnlink(e,t){let n=await this.core().github.unlink(e,{tag:t.tag});console.log(t.json?JSON.stringify(n,null,2):sa(n))}print(e,t,n){console.log(e.json?JSON.stringify(t,null,2):n.join(`
466
-
467
- `))}isInteractive(){return!!(process.stdin.isTTY&&process.stdout.isTTY)}async confirm(e){let{proceed:t}=await A.prompt([{type:`confirm`,name:`proceed`,message:e,default:!1}]);return t}},la=class{static commands=[{name:`list`,description:`List all tasks with filtering and status overview`,commandClass:Nr,category:`task`},{name:`show`,description:`Display detailed information about a specific task`,commandClass:Pr,category:`task`},{name:`next`,description:`Find the next available task to work on`,commandClass:Fr,category:`task`},{name:`graph`,description:`Show tasks as a dependency tree`,commandClass:Ir,category:`task`},{name:`why`,description:`Explain why a task is blocked`,commandClass:Lr,category:`task`},{name:`start`,description:`Start working on a task with claude-code`,commandClass:Rr,category:`task`},{name:`set-status`,description:`Update the status of one or more tasks`,commandClass:Br,category:`task`},{name:`autopilot`,description:`AI agent orchestration for TDD workflow (start, resume, next, complete, commit, status, abort)`,commandClass:Gi,category:`development`},{name:`loop`,description:`Run Claude Code in a loop, one task per iteration`,commandClass:oi,category:`development`},{name:`tags`,description:`Manage tags for task organization`,commandClass:ai,category:`task`},{name:`generate`,description:`Generate individual task files from tasks.json`,commandClass:Ki,category:`utility`},{name:`github`,description:`Push tasks to GitHub Issues (status, push, unlink)`,commandClass:ca,category:`utility`},{name:`completion`,description:`Set up Tab completion for bash, zsh or fish`,commandClass:Ii,category:`utility`}];static registerAll(e){for(let t of this.commands)this.registerCommand(e,t)}static registerByCategory(e,t){let n=this.commands.filter(e=>e.category===t);for(let t of n)this.registerCommand(e,t)}static registerByName(e,t){let n=this.commands.find(e=>e.name===t);if(n)this.registerCommand(e,n);else throw Error(`Command '${t}' not found in registry`)}static registerCommand(e,t){let n=t.commandClass;if(n.registerOn)n.registerOn(e);else if(n.register)n.register(e);else{let t=new n;e.addCommand(t)}}static getCommandNames(){return this.commands.map(e=>e.name)}static getCommandsByCategory(e){return this.commands.filter(t=>t.category===e)}static addCommand(e){if(this.commands.some(t=>t.name===e.name))throw Error(`Command '${e.name}' already exists in registry`);this.commands.push(e)}static removeCommand(e){let t=this.commands.findIndex(t=>t.name===e);return t>=0&&(this.commands.splice(t,1),!0)}static getCommand(e){return this.commands.find(t=>t.name===e)}static hasCommand(e){return this.commands.some(t=>t.name===e)}static getFormattedCommandList(){let e={task:`Task Management`,utility:`Utilities`,development:`Development`},t=``;for(let[n,r]of Object.entries(e)){let e=this.getCommandsByCategory(n);if(e.length>0){t+=`\n${r}:\n`;for(let n of e)t+=` ${n.name.padEnd(20)} ${n.description}\n`}}return t}};function ua(e){la.registerAll(e)}function da(e,t,n){let r=t.filter(t=>t.allowed_roles.includes(e)),i=Math.max(0,...r.map(e=>e.id.length));return r.map(e=>{let t=[zn[e.id],e.id===n?`current`:void 0].filter(Boolean).join(` · `);return{name:t?`${e.id.padEnd(i)} ${b.muted(t)}`:e.id,value:e.id,short:e.id}})}function fa(e){let{label:t,purpose:n}=H[e];return`${t} model (${n})`}function pa(e,t){return`${C.green(`✔`)} ${C.bold(fa(e))} ${C.cyan(t)}`}async function ma(e,t,n){let{model:r}=await A.createPromptModule({clearPromptOnDone:!0})([{type:`select`,name:`model`,message:fa(e),choices:t,default:n??void 0}]);return console.log(pa(e,r)),r}const ha=[`main`,`research`,`fallback`];function ga(e){if(!e)throw Error(`Project root is required but not found.`);let t=ie(null,{projectRoot:e}),n=ae(e);if(v(`debug`,`Checking for config file using findConfigPath, found: ${t}`),v(`debug`,`Checking config file using isConfigFilePresent(), exists: ${n}`),!n)throw Error(`The configuration file is missing. Run "taskgraph init" to create it.`)}function _a(e){return(t,...n)=>{e&&typeof e[t]==`function`&&e[t](...n)}}async function va(e={}){let{mcpLog:t,projectRoot:n}=e,r=_a(t);ga(n);try{let e=ge(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=ce(n);return{success:!0,data:{activeModels:{main:t(me(n),_e(n)),research:t(xe(n),be(n)),fallback:r?t(r,ye(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 ya(e={}){let{mcpLog:t,projectRoot:n}=e,r=_a(t);ga(n);try{let e=ge(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 ba(e,t,n={}){let{mcpLog:r,projectRoot:i}=n,a=_a(r);if(ga(i),!ha.includes(e))return{success:!1,error:{code:`INVALID_ROLE`,message:`Invalid role: ${e}. Must be one of: ${ha.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=ge(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=se(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),!pe(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 xa(e){return va(e)}async function Sa(e,t,n){return ba(e,t,n)}function Ca(){return ge()}const wa=e=>e instanceof Error&&e.name===`ExitPromptError`;async function Ta(e){let t=await xa({projectRoot:e}),n=t.success?t.data?.activeModels:void 0;return{main:n?.main?.modelId??null,research:n?.research?.modelId??null,fallback:n?.fallback?.modelId??null}}async function Ea(e,t){let n=[];for(let r of e){let e=await Sa(r.role,r.to,{projectRoot:t});if(!e.success)return q(`Couldn't set the ${r.role} model: ${e.error?.message??`unknown error`}`),{saved:n,ok:!1};n.push(r)}return{saved:n,ok:!0}}async function Da(e){let t=await Ta(e),n=Ca().filter(e=>e.allowed_roles),r={};try{for(let e of V)r[e]=await ma(e,da(e,n,t[e]),t[e])}catch(e){if(!wa(e))throw e;return console.log(b.muted(`
468
- Cancelled; no models changed`)),process.exitCode=130,!1}let i=V.filter(e=>r[e]&&r[e]!==t[e]).map(e=>({role:e,from:t[e],to:r[e]}));if(i.length===0)return!0;let{saved:a,ok:o}=await Ea(i,e);return a.length>0&&console.log(`\n${Wn(a)}`),o||(process.exitCode=1),o}export{Nn as A,ln as B,q as C,Wn as D,nr as E,Tn as F,et as G,z as H,Sn as I,gn as L,Rn as M,Ln as N,Vn as O,kn as P,pn as R,Mr as S,er as T,vt as U,Gt as V,$e as W,Wr as _,ua as a,Vr as b,ri as c,Z as d,Qr as f,Gr as g,Kr as h,ba as i,In as j,Hn as k,Xr as l,$r as m,ya as n,ti as o,ni as p,va as r,Yr as s,Da as t,ei as u,Hr as v,br as w,J as x,X as y,un as z};