taskgraph-ai 0.52.12 → 0.52.23

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,468 @@
1
+ import{a as e}from"./ai-services-unified-kmQRPU0g.js";import{C as t,a as n,b as r,c as i,d as a,f as o,g as s,h as c,i as l,m as u,n as d,o as f,p,r as m,s as h,t as ee,w as te}from"./src-TZm8h0X-.js";import{$ as g,B as ne,P as re,T as ie,X as _,Z as ae,a as oe,d as se,dt as v,ft as ce,ht as y,j as le,lt as b,m as ue,mt as de,n as fe,p as pe,pt as me,rt as x,u as he,ut as ge,v as _e,y as ve}from"./config-manager-DhVH8AQp.js";import S from"chalk";import C,{resolve as ye}from"node:path";import be from"path";import{spawn as w}from"child_process";import T from"node:fs";import xe from"node:os";import E from"fs";import{Argument as Se,Command as D}from"commander";import Ce from"figlet";import we from"gradient-string";import Te from"terminal-link";import O from"boxen";import{Marked as Ee,marked as De}from"marked";import{markedTerminal as Oe}from"marked-terminal";import ke from"turndown";import Ae from"cli-table3";import je from"ora";import{stripVTControlCharacters as Me}from"node:util";import k from"process";import Ne from"https";import Pe from"os";import Fe from"cli-progress";import A from"inquirer";function Ie(){return process.env.DEBUG===`true`||process.env.DEBUG===`1`}const Le=/* @__PURE__ */ new Set([`UNKNOWN_ERROR`,`INTERNAL_ERROR`,`STORAGE_ERROR`]),Re={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 ze(e,t){let n=e;for(;n?.cause&&typeof n.code==`string`&&Le.has(n.code);)n=n.cause;let r=Ge(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??We(r,n?.code)}}const Be=/\bsubtask (\d+)\.\d+ not found\b/i,Ve=/\btask\b(?!\s+file).*\bnot found\b/i,He=/^(source |target )?tag\b.*\bnot found\b/i,Ue=/^(source |target )?tag\b.*\balready exists\b/i;function We(e,t){if(t&&Re[t])return Re[t];if(He.test(e)||Ue.test(e))return"Run `taskgraph tags` to see your tags";let n=Be.exec(e);if(n)return`Run \`taskgraph show ${n[1]}\` to see its subtasks`;if(Ve.test(e))return Re.TASK_NOT_FOUND}function Ge(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 Ke({message:e,hint:t}){let n=`${S.red(`✗`)} ${e}`;if(t){let e=t.split(/`([^`]+)`/).map((e,t)=>t%2==1?y.brand(e):y.muted(e)).join(``);n+=`\n ${e}`}return n}function qe(e,t){let[n=``,...r]=e.trim().split(`
2
+ `),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`),Ke({message:Ge(a),hint:s})}function j(e,t){console.error(`\n${Ke({message:Ge(e),hint:t})}`)}function M(e,t={}){console.error(`\n${Ke(ze(e,t.hint))}`),(Ie()||t.forceStack)&&e?.stack&&(console.error(y.muted(`
3
+ Stack trace:`)),console.error(y.muted(e.stack))),t.skipExit||process.exit(1)}function N(e,t,n){return(n?.color?S[n.color]:S.cyan)(Te(e,t,{fallback:(e,t)=>n?.textOnlyFallback?e:`${e} (${t})`}))}function Je(e,t){return N(e,e,t)}function Ye(e,t){return N(e,t,{color:`cyan`})}function Xe(){return Te.isSupported}const Ze=we(ge);function Qe(){return process.env.TM_HIDE_BANNER===`true`}function $e(){return process.stdout.columns||80}function et(e={}){if(Qe())return;let{version:t}=e;try{let e=Ce.textSync(`TaskGraph`,{font:`Standard`,horizontalLayout:`default`,verticalLayout:`default`});console.log(Ze(e))}catch{console.log(Ze(`=== TaskGraph ===`))}let n=`x.com/stephennmiller_`,r=N(n,`https://x.com/stephennmiller_`,{textOnlyFallback:!0}),i=S.dim(`by `)+S.cyan(r),a=t?t.replace(/^v/,``):``,o=`https://github.com/stephennmiller/taskgraph-ai/releases/tag/taskgraph-ai%40${a}`,s=t?N(`v${a}`,o,{color:`dim`,textOnlyFallback:!0}):``;if(s){let e=`by ${n}`.length,t=a.length+1,r=$e()-e-t-1;r>=2?console.log(i+` `.repeat(r)+s):(console.log(i),console.log(s))}else console.log(i);console.log(``)}function tt(){if(Qe())return;try{let e=Ce.textSync(`TaskGraph`,{font:`Standard`,horizontalLayout:`default`,verticalLayout:`default`});console.log(Ze(e))}catch{console.log(Ze(`=== TaskGraph ===`))}let e=N(`x.com/stephennmiller_`,`https://x.com/stephennmiller_`,{textOnlyFallback:!0});console.log(S.dim(`by `)+S.cyan(e)),console.log(``)}function nt(e){let{header:t,body:n,callToAction:r,footer:i,level:a=`warn`}=e,o=a===`info`?y.heading:S.yellow.bold,s=a===`info`?v:`yellow`,c=[o(t),...n.map(e=>y.text(e))];r&&r.label&&r.action&&c.push(S.cyan(r.label)+`
4
+ `+y.brand.underline(r.action)),i&&c.push(y.muted(i));let l=c.join(`
5
+
6
+ `);return O(l,{padding:1,borderColor:s,borderStyle:`round`,margin:{top:1,bottom:1}})}const P={done:S.green(`█`),cancelled:y.muted(`─`),deferred:y.muted(`─`),inProgress:y.active(`▓`),review:S.magenta(`▒`),pending:S.yellow(`░`),blocked:S.red(`!`)};function rt(e,t=30,n){if(!n){let n=Math.round(e/100*t),r=t-n;return P.done.repeat(n)+y.muted(`░`).repeat(r)}let r=``,i=0,a=[[n.done,P.done],[n.cancelled,P.cancelled],[n.deferred,P.deferred],[n[`in-progress`],P.inProgress],[n.review,P.review],[n.pending,P.pending],[n.blocked,P.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+=P.pending.repeat(t-i)),r}function it(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=>c(e.status)).length,t.completionPercentage=t.total>0?Math.round(t.completedCount/t.total*100):0,t}function at(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=>c(e.status)).length,t.completionPercentage=t.total>0?Math.round(t.completedCount/t.total*100):0,t}function ot(e){let t=new Set(e.filter(e=>c(e.status)).map(e=>e.id)),n=e.filter(e=>!c(e.status)&&(!e.dependencies||e.dependencies.length===0)).length,r=e.filter(e=>!c(e.status)&&e.dependencies&&e.dependencies.length>0&&e.dependencies.every(e=>t.has(e))).length,i=e.filter(e=>!c(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 l=e.reduce((e,t)=>e+(t.dependencies?t.dependencies.length:0),0),u=e.length>0?l/e.length:0;return{tasksWithNoDeps:n,tasksReadyToWork:n+r,tasksBlockedByDeps:i,mostDependedOnTaskId:o,mostDependedOnCount:s,avgDependenciesPerTask:u}}function st(e){let t={critical:0,high:0,medium:0,low:0};return e.forEach(e=>{let n=e.priority||`medium`;t[n]++}),t}function ct(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 lt(e,t=!1,n=!1){let r=[];t?r.push(`${P.done} Completed: ${S.green(`${e.completedCount}/${e.total}`)}`):r.push(`${P.done} Done: ${S.green(e.done)}`),r.push(`${P.cancelled} Cancelled: ${y.muted(e.cancelled)}`),r.push(`${P.deferred} Deferred: ${y.muted(e.deferred)}`);let i=e=>n?e.slice(0,2).join(` `)+(e.length>2?`
7
+ `+e.slice(2).join(` `):``):e.join(` `),a=i(r);return r.length=0,r.push(`${P.inProgress} In Progress: ${y.active(e.inProgress)}`),r.push(`${P.review} Review: ${S.magenta(e.review||0)}`),r.push(`${P.pending} Pending: ${S.yellow(e.pending)}`),r.push(`${P.blocked} Blocked: ${S.red(e.blocked)}`),a+`
8
+ `+i(r)}function ut(e,t,n,r=!1){let i=ct(e),a=ct(t),o=r?16:30,s=rt(e.completionPercentage,o,i),c=rt(t.completionPercentage,o,a),l=`${e.completionPercentage}% ${e.completedCount}/${e.total}`,u=`${t.completionPercentage}% ${t.completedCount}/${t.total}`;return S.bold(`Project Dashboard`)+`
9
+ Tasks Progress: ${s} ${S.yellow(l)}\n`+lt(e,!1,r)+`
10
+
11
+ Subtasks Progress: ${c} ${S.cyan(u)}\n`+lt(t,!0,r)+`
12
+
13
+ `+S.cyan.bold(`Priority Breakdown:`)+`
14
+ ${S.red(`•`)} ${y.text(`High priority:`)} ${n.high}\n${S.yellow(`•`)} ${y.text(`Medium priority:`)} ${n.medium}\n${S.green(`•`)} ${y.text(`Low priority:`)} ${n.low}`}function dt(e,t){return S.bold(`Dependency Status & Next Task`)+`
15
+ `+S.cyan.bold(`Dependency Metrics:`)+`
16
+ ${S.green(`•`)} ${y.text(`Tasks with no dependencies:`)} ${e.tasksWithNoDeps}\n${S.green(`•`)} ${y.text(`Tasks ready to work on:`)} ${e.tasksReadyToWork}\n${S.yellow(`•`)} ${y.text(`Tasks blocked by dependencies:`)} ${e.tasksBlockedByDeps}\n${y.accent(`•`)} ${y.text(`Most depended-on task:`)} ${e.mostDependedOnTaskId?S.cyan(`#${e.mostDependedOnTaskId} (${e.mostDependedOnCount} dependents)`):y.muted(`None`)}\n${y.brand(`•`)} ${y.text(`Avg dependencies per task:`)} ${e.avgDependenciesPerTask.toFixed(1)}\n\n`+S.cyan.bold(`Next Task:`)+`
17
+ ID: ${t?S.cyan(String(t.id)):y.muted(`N/A`)} - ${t?S.bold(t.title):S.yellow(`No task available`)}\nPriority: ${t?.priority||y.muted(`N/A`)} Dependencies: ${t?.dependencies?.length?S.cyan(t.dependencies.join(`, `)):y.muted(`None`)}\nComplexity: ${t?.complexity===void 0?y.muted(`N/A`):B(t.complexity)}`}function ft(e,t,n,r,i){let a=process.stdout.columns||80,o=a>=120,s=Math.floor(a/2),c=s-4,l=ut(e,t,n,(o?c:a)-8<60),u=dt(r,i);if(o){let e=O(l,{padding:1,borderColor:v,borderStyle:`round`,width:c,dimBorder:!1}),t=O(u,{padding:1,borderColor:v,borderStyle:`round`,width:c,dimBorder:!1}),n=e.split(`
18
+ `),r=t.split(`
19
+ `),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(`
20
+ `))}else{let e=O(l,{padding:1,borderColor:v,borderStyle:`round`,margin:{top:0,bottom:1}}),t=O(u,{padding:1,borderColor:v,borderStyle:`round`,margin:{top:0,bottom:1}});console.log(e),console.log(t)}}const pt={done:{color:S.green,icon:`✓`,tableIcon:`✓`},pending:{color:S.yellow,icon:`○`,tableIcon:`○`},"in-progress":{color:y.active,icon:`▶`,tableIcon:`▶`},deferred:{color:y.muted,icon:`–`,tableIcon:`–`},review:{color:S.magenta,icon:`?`,tableIcon:`?`},cancelled:{color:y.muted,icon:`x`,tableIcon:`x`},blocked:{color:S.red,icon:`!`,tableIcon:`!`},completed:{color:S.green,icon:`✓`,tableIcon:`✓`}};function mt(e){let t=pt[e];return t?t.color(t.icon):S.red(`X`)}function F(e,t=!1){let n=pt[e]||{color:S.red,icon:`X`,tableIcon:`X`},r=t?n.tableIcon:n.icon;return n.color(`${r} ${e}`)}function I(e=.9,t=40){let n=process.stdout.columns||80;return Math.max(Math.floor(n*e),t)}function L(){let e=process.stdout.columns;return e?Math.floor(e*.95):100}function ht(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 gt(e,t){return e.length<=t?e:e.substring(0,t-3)+`...`}function _t(e,t,n=30){if(t===0)return y.muted(`No tasks`);let r=Math.round(e/t*100),i=Math.round(e/t*n),a=n-i;return`${S.green(`█`).repeat(i)+y.muted(`░`).repeat(a)} ${S.cyan(`${r}%`)} (${e}/${t})`}const vt=[[`done`,`done`],[`in-progress`,`in progress`],[`review`,`review`],[`pending`,`pending`],[`blocked`,`blocked`],[`deferred`,`deferred`],[`cancelled`,`cancelled`]],yt=e=>e.replace(/\x1b\[[0-9;]*m/g,``).length;function bt(e,t={}){let n=t.width??100,r=t.nextId?String(t.nextId):null,i=r?.split(`.`)[0],a=[],o=/* @__PURE__ */ new Set,s=(e,t)=>{o.add(e.status);let a=e.id===i,s=[];e.alsoNeeds.length&&s.push(`needs ${e.alsoNeeds.join(`, `)}`);let c=e.missing.length?S.yellow(` · missing ${e.missing.join(`, `)}`):``,l=(s.length?y.muted(` · ${s.join(` · `)}`):``)+c+(a?y.brand.bold(r===i?` ← next`:` ← next: ${r}`):``),u=`${t}${mt(e.status)} ${y.brand(e.id)} `,d=Math.max(12,n-yt(u)-yt(l)),f=gt(e.title,d);return u+(a||e.status===`in-progress`?S.bold(f):e.status===`done`||e.status===`cancelled`?y.muted(f):f)+l},c=(e,t,n)=>{a.push(s(e,t+y.muted(n?`└─ `:`├─ `)));let r=t+y.muted(n?` `:`│ `);e.children.forEach((t,n)=>c(t,r,n===e.children.length-1))};if(e.roots.forEach((t,n)=>{let r=e.roots[n-1];r&&(r.children.length||t.children.length)&&a.push(``),a.push(s(t,``)),t.children.forEach((e,n)=>c(e,``,n===t.children.length-1))}),e.cyclic.length){a.push(``,S.yellow(`⚠ These tasks depend on each other in a loop:`));for(let t of e.cyclic)a.push(s(t,` `));let t=new Set(e.cyclic.map(e=>e.id)),n=e.cyclic[0],r=n.alsoNeeds.find(e=>t.has(e));r&&a.push(y.muted(` Break it with `)+y.brand(`taskgraph remove-dependency --id=${n.id} --depends-on=${r}`))}let l=vt.filter(([e])=>o.has(e)).map(([e,t])=>`${mt(e)} ${y.muted(t)}`).join(` `);return l&&a.push(``,l),a}function xt(e={}){let{tag:t}=e;t&&console.log(S.dim(`[tag] `)+S.cyan(t))}const St=new ke({headingStyle:`atx`,codeBlockStyle:`fenced`,bulletListMarker:`-`});De.use(Oe({code:e=>e.split(`
21
+ `).map(e=>` `+S.cyan(e)).join(`
22
+ `),blockquote:y.muted.italic,html:y.muted,heading:y.text.bold,hr:y.muted,listitem:y.text,paragraph:y.text,strong:y.text.bold,em:y.text.italic,codespan:S.cyan,del:S.dim.strikethrough,link:y.brand,href:y.brand.underline,showSectionPrefix:!1,unescape:!0,emoji:!1,tab:4,width:120})),De.setOptions({breaks:!0,gfm:!0});function R(e){if(!e)return``;let t=e.replace(/\\\\/g,`\\`).replace(/\\n/g,`
23
+ `).replace(/\\t/g,` `).replace(/\\"/g,`"`);/<[^>]+>/.test(t)&&(t=St.turndown(t));let n=De(t);return typeof n==`string`?n.trim():t}function Ct(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 wt(e){switch(e){case`create`:return S.green(`✚ CREATE`);case`modify`:return S.yellow(`✎ MODIFY`);case`reference`:return y.brand(`◇ REFER `);default:return y.muted(` FILE `)}}function Tt(e){return e}function Et(e,t){console.log(O(S.bold(`Task: #${e} - ${t}`),{padding:{top:0,bottom:0,left:1,right:1},borderColor:v,borderStyle:`round`}))}function Dt(e,t){let n=L(),r=new Ae({head:[],style:{head:[],border:de},colWidths:ht(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?`${Tt(e.category)}`:y.muted(`N/A`),c=e.skills&&e.skills.length>0?e.skills.map(e=>y.accent(`[${e}]`)).join(` `):y.muted(`N/A`),l=[S.cyan(`ID:`),S.cyan(`Title:`),S.cyan(`Status:`),S.cyan(`Priority:`),S.cyan(`Dependencies:`),S.cyan(`Complexity:`),S.cyan(`Category:`),S.cyan(`Skills:`),S.cyan(`Description:`)].join(`
24
+ `),u=[a,e.title,F(e.status),nn(e.priority),i,typeof e.complexity==`number`?B(e.complexity):y.muted(`N/A`),s,c,o].join(`
25
+ `);r.push([l,u]),console.log(r.toString())}function Ot(e){let t=L(),n=R(e);console.log(O(S.bold(`Implementation Details:`)+`
26
+
27
+ `+n,{padding:1,borderStyle:`round`,borderColor:v,width:t}))}function kt(e){let t=L(),n=R(e);console.log(O(S.bold(`Test Strategy:`)+`
28
+
29
+ `+n,{padding:1,borderStyle:`round`,borderColor:v,width:t}))}function At(e,t){let n=L();console.log(O(y.heading(`Subtasks`),{padding:{top:0,bottom:0,left:1,right:1},borderColor:v,borderStyle:`round`,margin:{top:1,bottom:0}}));let r=new Ae({head:[y.heading(`ID`),y.heading(`Status`),y.heading(`Title`),y.heading(`Deps`)],style:{head:[],border:de},colWidths:ht(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,F(e.status),e.title,i])}),console.log(r.toString())}function jt(e){let t=L(),n=e.map(e=>`${wt(e.action)} ${y.text(e.path)}\n ${y.muted(e.description)}`).join(`
30
+
31
+ `);console.log(O(S.bold(`Files to Touch:`)+`
32
+
33
+ `+n,{padding:1,borderStyle:`round`,borderColor:`yellow`,width:t}))}function Mt(e){let t=L(),n=e.map(e=>`${S.cyan.bold(e.name)} → ${y.muted(e.location)}\n ↳ ${y.text(e.usage)}`).join(`
34
+
35
+ `);console.log(O(S.bold(`Leverage Existing Code:`)+`
36
+
37
+ `+n,{padding:1,borderStyle:`round`,borderColor:v,width:t}))}function Nt(e){let t=L(),n=``;e.included&&(n+=S.green.bold(`✓ In Scope:
38
+ `),n+=y.text(` `+e.included)),e.excluded&&(n&&(n+=`
39
+
40
+ `),n+=S.red.bold(`✗ Out of Scope:
41
+ `),n+=y.muted(` `+e.excluded)),console.log(O(S.bold(`Scope Boundaries:`)+`
42
+
43
+ `+n,{padding:1,borderStyle:`round`,borderColor:v,width:t}))}function Pt(e){let t=L(),n=e.map(e=>y.text(`☐ ${e}`)).join(`
44
+ `);console.log(O(S.bold(`Acceptance Criteria:`)+`
45
+
46
+ `+n,{padding:1,borderStyle:`round`,borderColor:`green`,width:t}))}function Ft(e){let t=L(),n=e.map(e=>S.yellow(`▸ ${e}`)).join(`
47
+ `);console.log(O(S.bold(`Technical Constraints:`)+`
48
+
49
+ `+n,{padding:1,borderStyle:`round`,borderColor:`red`,width:t}))}function It(e){let t=L(),n=R(e);console.log(O(S.bold(`Implementation Approach:`)+`
50
+
51
+ `+n,{padding:1,borderStyle:`round`,borderColor:v,width:t}))}function Lt(e){let t=L(),n=e.map(e=>y.text(`• ${e}`)).join(`
52
+ `);console.log(O(S.bold(`Codebase Patterns:`)+`
53
+
54
+ `+n,{padding:1,borderStyle:`round`,...me,width:t}))}function Rt(e,t){let n=``;e&&(n+=y.muted(`Category: `)+S.cyan(`[${Tt(e)}]`)),t&&t.length>0&&(n&&(n+=` `),n+=y.muted(`Skills: `)+t.map(e=>y.accent(`[${e}]`)).join(` `)),n&&console.log(`
55
+ `+n)}function zt(e){(e.relevantFiles||e.existingInfrastructure||e.scopeBoundaries||e.acceptanceCriteria||e.technicalConstraints||e.implementationApproach||e.codebasePatterns)&&(e.implementationApproach&&(console.log(),It(e.implementationApproach)),e.relevantFiles&&e.relevantFiles.length>0&&(console.log(),jt(e.relevantFiles)),e.existingInfrastructure&&e.existingInfrastructure.length>0&&(console.log(),Mt(e.existingInfrastructure)),e.codebasePatterns&&e.codebasePatterns.length>0&&(console.log(),Lt(e.codebasePatterns)),e.scopeBoundaries&&(console.log(),Nt(e.scopeBoundaries)),e.technicalConstraints&&e.technicalConstraints.length>0&&(console.log(),Ft(e.technicalConstraints)),e.acceptanceCriteria&&e.acceptanceCriteria.length>0&&(console.log(),Pt(e.acceptanceCriteria)))}function Bt(e,t,n=!1){let r=Ct(e,t,n).map((e,t)=>`${S.cyan(`${t+1}.`)} Run ${S.yellow(e.command)} ${e.description}`);console.log(O(S.bold(`Suggested Actions:`)+`
56
+
57
+ `+r.join(`
58
+ `),{padding:1,margin:{top:1},borderStyle:`round`,borderColor:`green`,width:L()}))}function Vt(e,t){let{statusFilter:n,showSuggestedActions:r=!1,customHeader:i,headerColor:a=v,originalTaskId:o}=t||{};if(i?console.log(O(S.bold(i),{padding:{top:0,bottom:0,left:1,right:1},borderColor:a,borderStyle:`round`,margin:{top:1}})):Et(o||e.id,e.title),Dt(e,o),e.details&&(console.log(),Ot(e.details)),`testStrategy`in e&&e.testStrategy&&(console.log(),kt(e.testStrategy)),zt(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(y.muted(` No subtasks with status '${n}'`))):t.length>0&&(console.log(),At(t,e.id))}r&&(console.log(),Bt(o||e.id,e.status,!!(e.subtasks&&e.subtasks.length>0)))}function Ht(e,t){if(!e){console.log(t?S.yellow(`✓ All tasks are either completed, blocked by dependencies, or in progress.`):O(S.yellow(`No tasks found in this project.`),{padding:1,borderStyle:`round`,borderColor:`yellow`,title:`No tasks available`,titleAlignment:`center`}));return}let n=[];n.push(`${y.heading(`Next task:`)} ${S.yellow(`#${e.id}`)}${y.heading(` - ${e.title}`)}`),n.push(``);let r=[];if(e.priority){let t=e.priority===`high`?S.red:e.priority===`medium`?S.yellow:y.muted;r.push(`Priority: ${t.bold(e.priority)}`)}if(e.status){let t=e.status===`pending`?S.yellow(`○ pending`):e.status===`in-progress`?y.brand(`▶ in-progress`):y.muted(e.status);r.push(`Status: ${t}`)}n.push(r.join(` `));let i=!e.dependencies||e.dependencies.length===0?y.muted(`None`):S.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: ${y.text(R(e.description))}`)),n.push(``);for(let t of Ct(e.id,e.status,!0).slice(0,2))n.push(`${S.cyan(`Next step:`)} ${S.yellow(t.command)} ${y.muted(t.description)}`);n.push(`${S.cyan(`View details:`)} ${S.yellow(`taskgraph show ${e.id}`)}`),console.log(O(n.join(`
59
+ `),{padding:1,margin:{top:1,bottom:1},borderStyle:`round`,borderColor:v,title:y.heading(`Next task`),titleAlignment:`center`,width:I(.97),fullscreen:!1}))}function Ut(e){if(`description`in e&&e.description)return e.description;if(`details`in e&&e.details)return e.details.split(`
60
+ `)[0].split(`.`)[0]}const Wt=[`⠋`,`⠙`,`⠹`,`⠸`,`⠼`,`⠴`,`⠦`,`⠧`,`⠇`,`⠏`];function Gt(e=S.hex(ce.accent)){return{interval:80,frames:Wt.map(t=>e(t))}}function z(e={}){let t=je({...typeof e==`string`?{text:e}:e,spinner:Gt(),color:!1}),n=e=>n=>t.stopAndPersist({symbol:e,text:n});return t.succeed=n(S.green(`✓`)),t.fail=n(S.red(`✗`)),t.warn=n(S.yellow(`⚠`)),t}function Kt(e,t=!1){let n=e?.tasks?.length??0;return t?n:Math.max(0,n-1)}function qt(e){let t=Math.max(0,Math.floor(e/1e3));return`${Math.floor(t/60)}:${String(t%60).padStart(2,`0`)}`}function Jt(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 Yt(e,t){let n=e.replace(/\s+/g,` `).trim();return n.length>t?`${n.slice(0,t-1).trimEnd()}…`:n}var Xt=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(Kt(e)),this.refresh()}succeed(e){e&&(this.current=e),this.printCompleted(Kt(this.current,!0));let t=this.printed,n=Jt(this.options.now()-this.startedAt),r=`${t} ${t===1?`task`:`tasks`} in ${n}`;this.stop(),this.write(`${S.green(`✓`)} ${S.bold(r)}\n`)}fail(e){this.stop(),this.write(`${S.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=Yt(e?.title??``,Math.max(20,this.columns-7));this.persist(`${S.green(`✓`)} ${y.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+=y.muted(` · ${Yt(i,a)}`))}return`${r} ${y.muted(this.elapsed())}`}get columns(){return this.options.stream.columns||80}elapsed(){return qt(this.options.now()-this.startedAt)}write(e){this.options.stream.write(e)}};function Zt(){let e=[`${S.cyan(`1.`)} Run ${S.yellow(`taskgraph next`)} to see what to work on next`,`${S.cyan(`2.`)} Run ${S.yellow(`taskgraph expand --id=<id>`)} to break down a task into subtasks`,`${S.cyan(`3.`)} Run ${S.yellow(`taskgraph set-status --id=<id> --status=done`)} to mark a task as complete`];console.log(O(S.bold(`Suggested Next Steps:`)+`
61
+
62
+ `+e.join(`
63
+ `),{padding:1,margin:{top:0,bottom:1},borderStyle:`round`,...me,width:I(.97)}))}const Qt=`tasks.json`;function $t(e){let t=f(e);console.log(S.dim(`\nWatching ${Qt} for changes...`)),console.log(y.muted(`Last synced: ${t}`)),console.log(S.dim(`Press Ctrl+C to exit`))}function en(e){let t=f(e);console.log(y.brand(`\nℹ ${Qt} updated at ${t}`))}const tn={critical:S.red.bold,high:S.red,medium:S.yellow,low:y.muted};function nn(e){return(tn[e]||y.text)(e)}function rn(e){return e>=7?`High`:e>=4?`Medium`:`Low`}function an(e){let t=rn(e);return{color:t===`High`?S.red:t===`Medium`?S.yellow:S.green,label:t}}function B(e){let t=typeof e==`string`?Number(e.trim()):e;if(isNaN(t))return y.muted(`N/A`);let{color:n}=an(t);return n(`● ${t}`)}function on(e){if(typeof e!=`number`)return y.muted(`N/A`);let{color:t,label:n}=an(e);return t(`${e}/10 (${n})`)}const sn=(e,t)=>`${e} ${e===1?t:`${t}s`}`,cn=(e,t)=>e.length>t?`${e.slice(0,Math.max(1,t-1))}…`:e,ln=e=>[...e].sort((e,t)=>t.complexityScore-e.complexityScore);function un(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 dn(e,t){let n=ln(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?sn(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=cn(e.taskTitle,s).padEnd(s),n=B(e.complexityScore),o=` `.repeat(i-String(e.complexityScore).length),c=a(e);return{item:e,line:` ${y.brand(String(e.taskId).padEnd(r))} ${t} ${n}${o}${c?` ${y.muted(c)}`:``}`.trimEnd(),indent:2+r+2}})}function fn(e){let t={High:0,Medium:0,Low:0};for(let n of e)t[rn(n.complexityScore)]++;return`High ${t.High} · Medium ${t.Medium} · Low ${t.Low}`}const pn=()=>y.muted(`Run `)+y.brand(`taskgraph expand --id=<id>`)+y.muted(` or `)+y.brand(`--all`)+y.muted(` to use these recommendations`);function mn(e,t=process.stdout.columns||80){let{analyses:n,skipped:r,kept:i,reportPath:a}=e;if(n.length===0)return y.muted(`No pending tasks to analyze`);let o=[e.usedResearch?`with web research`:null,r>0?`skipped ${r} done`:null].filter(Boolean),s=[`${S.green(`✓`)} Analyzed ${sn(n.length,`task`)}${o.length?y.muted(` · ${o.join(` · `)}`):``}`,...dn(n,t).map(e=>e.line)],c=i===0?``:`, with ${i} earlier ${i===1?`analysis`:`analyses`}`;return s.push(y.muted(`Saved to ${a}${c}`)),s.push(y.muted(`Next: `)+y.brand(`taskgraph expand --all`)+y.muted(`, or `)+y.brand(`taskgraph complexity-report`)+y.muted(` to see why`)),s.join(`
64
+ `)}function hn(e,t=process.stdout.columns||80){let n=e.complexityAnalysis??[];if(n.length===0)return y.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=[sn(n.length,`task`),fn(n),e.meta.usedResearch?`with web research`:null,i].filter(Boolean).join(` · `),o=[y.heading(`Complexity report`),y.muted(a),``];for(let e of dn(n,t)){if(o.push(e.line),e.item.reasoning){let n=` `.repeat(e.indent);for(let r of un(e.item.reasoning,Math.max(20,t-e.indent)))o.push(y.muted(`${n}${r}`))}o.push(``)}return o.push(pn()),o.join(`
65
+ `)}const gn=(e,t)=>Math.round(e).toLocaleString(t);function _n(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 vn(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(`${gn(i,t)} ${i===1?`token`:`tokens`} (${gn(n,t)} in, ${gn(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(`~${_n(e.totalCost,e.currency,t)}`),a.join(` · `)}const yn=e=>e.oldStatus===e.newStatus?`${F(e.newStatus)} ${y.muted(`(unchanged)`)}`:`${F(e.oldStatus)} → ${F(e.newStatus)}`;function bn(e){let t=S.green(`✓`);if(e.length===1){let[n]=e;return`${t} Task ${y.brand(n.taskId)} ${yn(n)}`}let n=Math.max(0,...e.map(e=>e.taskId.length));return[`${t} Updated ${e.length} tasks`,...e.map(e=>` ${y.brand(e.taskId.padEnd(n))} ${yn(e)}`)].join(`
66
+ `)}function xn(e,t,n=process.stdout.columns||80){let r=t.length,i=r===1?`subtask`:`subtasks`,a=[`${S.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(` ${y.brand(o[t].padEnd(s))} ${n}`)}),a.join(`
67
+ `)}const Sn=(e,t)=>`${e} ${e===1?t:`${t}s`}`,Cn=(e,t)=>e.length>t?`${e.slice(0,Math.max(1,t-1))}…`:e;function wn(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 Tn(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}`:Sn(n.length,`task`),o=[`${S.green(`✓`)} Cleared ${Sn(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=>Sn(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?`${y.muted(l[t].padEnd(u))} `:``;o.push(` ${y.brand(s[t].padEnd(c))} ${n}${Cn(e.title,d)}`)}),r.length>0&&o.push(y.muted(wn(r.map(e=>e.id))));let f=n.length===1?String(n[0].id):`<id>`;return o.push(y.muted(`Run `)+y.brand(`taskgraph expand --id=${f}`)+y.muted(` to add new ones`)),o.join(`
68
+ `)}const En=e=>Me(e).length;function Dn(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=En(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 On(e,t){return e.split(`
69
+ `).flatMap(e=>{let n=e.replace(/^(\s*)\* /,`$1• `),r=Me(n).match(/^(\s*)(•|\d+\.)\s+/);return!r||En(n)<=t?[n]:Dn(n,t,` `.repeat(r[0].length))}).join(`
70
+ `)}function kn(e,t=process.stdout.columns||80){let n=Math.max(40,Math.min(t,100)),r=new Ee({gfm:!0,breaks:!1});r.use(Oe({code:e=>e.split(`
71
+ `).map(e=>S.cyan(e)).join(`
72
+ `),blockquote:y.muted.italic,html:y.muted,heading:y.text.bold,firstHeading:y.text.bold,hr:y.muted,listitem:y.text,paragraph:y.text,strong:y.text.bold,em:y.text.italic,codespan:S.cyan,del:S.dim.strikethrough,link:y.brand,href:y.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 On(r.parse(i,{async:!1}).trimEnd(),n)}function An(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 jn=e=>`${e.length===1?`task`:`tasks`} ${An(e).join(`, `)}`;function Mn(e){let t=[],{taskIds:n,relatedTaskIds:r,files:i}=e;return n.length>0&&t.push(jn(n)),r.length>0&&t.push(n.length>0?`related ${An(r).join(`, `)}`:`related ${jn(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?``:y.muted(`Context: ${t.join(` · `)}`)}function Nn(e){let t=e.kind===`file`?e.path:`${e.id.includes(`.`)?`subtask`:`task`} ${e.id}`;return`${S.green(`✓`)} Saved to ${t}`}function Pn(e,t){let n=e.kind===`file`?`a file`:`${e.id.includes(`.`)?`subtask`:`task`} ${e.id}`;return`${S.red(`✗`)} Couldn't save to ${n}: ${t}`}const Fn=e=>e.replace(/`([^`]+)`/g,(e,t)=>y.brand(t));function In(e){let t=Math.max(0,...e.map(e=>e.path.length));return e.map(e=>` ${e.path.padEnd(t)} ${y.muted(Fn(e.note))}`)}function Ln(e){let t=[];return e.claudeCode&&t.push([`Add the slash commands in Claude Code:`,y.brand(`/plugin marketplace add stephennmiller/taskgraph-ai`),y.brand(`/plugin install taskgraph@taskgraph`)]),e.alreadySetUp||t.push([`Write a PRD in .taskgraph/docs/prd.md`,y.muted(`Templates are in .taskgraph/templates/`)],[`Turn it into tasks: ${y.brand(`taskgraph parse-prd`)}`],[`Start the first task: ${y.brand(`taskgraph next`)}`]),t}function Rn(e){let t=S.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(y.muted(Fn(" Run `taskgraph list` to see your tasks")))):n.push(`${t} Set up TaskGraph in ${e.folder}`),n.push(...In(e.changes));let r=Ln(e);return r.length>0&&(n.push(``,y.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(``,y.muted(Fn("AI runs through Claude Code; run `claude` once to sign in"))),e.defaultModels&&n.push(y.muted(Fn("Using the default models; change them with `taskgraph models --setup`")))),n.join(`
73
+ `)}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)=>y.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=[y.heading(`Models`)];for(let t of V){let{label:a,purpose:o}=H[t],s=e[t],c=s?y.brand(s.padEnd(r)):y.muted(`none`.padEnd(r));i.push(` ${a.padEnd(n)} ${c} ${y.muted(o)}`)}return i.push(``),t.length>0&&i.push(y.muted(`Choices: ${Vn(t)}`)),i.push(y.muted(Bn("Change them with `taskgraph models --setup`"))),i.join(`
74
+ `)}const Un=e=>e.from===e.to?`${y.brand(e.to)} ${y.muted(`(unchanged)`)}`:e.from?`${e.from} → ${y.brand(e.to)}`:y.brand(e.to);function Wn(e){let t=S.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(`
75
+ `)}function Gn(e,t){if(!e||e.length===0)return y.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`?`►`:`○`}`:S.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=>` ${y.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`${S.green(`✓`)} No dependency problems${y.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=[`${S.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?y.muted(`Run `)+y.brand(`taskgraph fix-dependencies`)+y.muted(` to remove them`):y.muted(`Break the loop with `)+y.brand(`taskgraph remove-dependency --id=<id> --depends-on=<id>`)),i.join(`
76
+ `)}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(`${S.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(`
77
+ `)}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=>`${S.green(`✓`)} ${e}`,G=(...e)=>{let t=e.filter(Boolean);return t.length?y.muted(` · ${t.join(` · `)}`):``},ar=e=>y.muted(`Switch to it with `)+y.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(` ${y.muted(ir(e.description,t-2))}`),r.push(ar(e.tagName)),r.join(`
78
+ `)}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(`${y.muted(`Next:`)} ${y.brand(n)} ${i}`)}else e.taskCount===0?r.push(y.muted(`Add tasks with `)+y.brand(`taskgraph add-task`)+y.muted(` or `)+y.brand(`taskgraph parse-prd <file>`)):r.push(y.muted(`No task is ready to start`));return r.join(`
79
+ `)}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(`
80
+ `)}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=[y.muted(f.trimEnd())];return e.forEach((e,n)=>{let o=e.isCurrent?`${S.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?y.muted(n):n}`}),f=`${o}${e.isCurrent?S.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+=y.muted(` ${r}${t}`))}p.push(f.trimEnd())}),p.join(`
81
+ `)}function fr(e=`TaskGraph`){console.log(O(S.bold(e),{padding:1,margin:{top:1,bottom:1},borderStyle:`round`,borderColor:v,textAlignment:`center`}))}function pr(e,t){let n=I();console.error(O(S.red.bold(`X Error: `)+y.text(e)+(t?`
82
+
83
+ `+y.muted(t):``),{padding:1,borderStyle:`round`,borderColor:`red`,width:n}))}const mr=pr;function hr(e){let t=I();console.log(O(S.green.bold(`√ `)+y.text(e),{padding:1,borderStyle:`round`,borderColor:`green`,width:t}))}function gr(e){let t=I();console.log(O(S.yellow.bold(`⚠ `)+y.text(e),{padding:1,borderStyle:`round`,borderColor:`yellow`,width:t}))}function _r(e){let t=I();console.log(O(y.brand.bold(`i `)+y.text(e),{padding:1,borderStyle:`round`,borderColor:v,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},l=vr.filter(e=>s[e.key]??!0),u=ht(L(),l),d=e=>u.widths[u.keys.indexOf(e)],f=new Ae({head:u.keys.map(e=>y.brand.bold(vr.find(t=>t.key===e)?.header??e)),style:{head:[],border:[]},colWidths:u.widths,wordWrap:!0}),p=e=>u.keys.map(t=>e[t]??``);e.forEach(e=>{let t=e.blocks?.join(`, `)??``;f.push(p({tag:y.accent(e.tagName||`-`),id:S.cyan(e.id.toString()),title:gt(e.title,d(`title`)-3),status:F(e.status,!0),priority:nn(e.priority),dependencies:!e.dependencies||e.dependencies.length===0?y.muted(`-`):S.cyan(e.dependencies.map(e=>String(e)).join(`, `)),blocks:t?c(e.status)?y.muted(t):S.yellow(t):y.muted(`-`),complexity:typeof e.complexity==`number`?B(e.complexity):y.muted(`N/A`)})),n&&e.subtasks&&e.subtasks.length>0&&e.subtasks.forEach(e=>{f.push(p({tag:y.muted(`-`),id:y.muted(` └─ ${e.id}`),title:y.muted(gt(e.title,d(`title`)-6)),status:y.muted(F(e.status,!0)),priority:y.muted(e.priority||`medium`),dependencies:y.muted(e.dependencies&&e.dependencies.length>0?e.dependencies.map(e=>String(e)).join(`, `):`-`),blocks:y.muted(`-`),complexity:y.muted(typeof e.complexity==`number`?B(e.complexity):`--`)}))})});let m=u.hidden.length>0?`
84
+ `+y.muted(`Hidden to fit width: ${u.hidden.map(e=>vr.find(t=>t.key===e)?.header).join(`, `)}`):``;return f.toString()+m}var br=/* @__PURE__ */ e({BANNER_GRADIENT:()=>ge,BORDER_COLOR:()=>v,BRAND_COLORS:()=>ce,MODEL_NOTES:()=>zn,MODEL_ROLES:()=>H,MODEL_ROLE_ORDER:()=>V,MUTED_BOX_BORDER:()=>me,ParsePrdProgress:()=>Xt,TABLE_BORDER:()=>de,brandSpinner:()=>Gt,calculateDependencyStatistics:()=>ot,calculateSubtaskStatistics:()=>at,calculateTaskStatistics:()=>it,completedTaskCount:()=>Kt,complexityLevel:()=>rn,createLink:()=>N,createProgressBar:()=>_t,createSpinner:()=>z,createTaskLink:()=>Ye,createTaskTable:()=>yr,createUrlLink:()=>Je,displayAcceptanceCriteria:()=>Pt,displayAsciiBanner:()=>et,displayBanner:()=>fr,displayCardBox:()=>nt,displayCodebasePatterns:()=>Lt,displayDashboards:()=>ft,displayDependencyDashboard:()=>dt,displayError:()=>mr,displayErrorBox:()=>pr,displayExistingInfrastructure:()=>Mt,displayHeader:()=>xt,displayImplementationApproach:()=>It,displayImplementationDetails:()=>Ot,displayImplementationMetadata:()=>zt,displayInfo:()=>_r,displayInitBanner:()=>tt,displayProjectDashboard:()=>ut,displayRecommendedNextTask:()=>Ht,displayRelevantFiles:()=>jt,displayScopeBoundaries:()=>Nt,displaySkillsAndCategory:()=>Rt,displaySubtasks:()=>At,displaySuccess:()=>hr,displaySuggestedActions:()=>Bt,displaySuggestedNextSteps:()=>Zt,displaySyncMessage:()=>en,displayTaskDetails:()=>Vt,displayTaskHeader:()=>Et,displayTaskProperties:()=>Dt,displayTechnicalConstraints:()=>Ft,displayTestStrategy:()=>kt,displayWarning:()=>gr,displayWatchFooter:()=>$t,formatAddedSubtasks:()=>xn,formatClearedSubtasks:()=>Tn,formatComplexityReport:()=>hn,formatComplexityRun:()=>mn,formatCost:()=>_n,formatDependenciesWithStatus:()=>Gn,formatDependencyCheck:()=>er,formatDependencyFixes:()=>nr,formatDuration:()=>Jt,formatElapsed:()=>qt,formatInitSummary:()=>Rn,formatModelChanges:()=>Wn,formatModelChoices:()=>Vn,formatModelConfiguration:()=>Hn,formatResearchAnswer:()=>kn,formatResearchContext:()=>Mn,formatResearchSaveFailed:()=>Pn,formatResearchSaved:()=>Nn,formatStatusChanges:()=>bn,formatStatusLine:()=>lt,formatTagCopied:()=>lr,formatTagCreated:()=>or,formatTagDeleted:()=>ur,formatTagList:()=>dr,formatTagRenamed:()=>cr,formatTagSwitched:()=>sr,formatUsageLine:()=>vn,getBoxWidth:()=>I,getComplexityWithColor:()=>B,getComplexityWithScore:()=>on,getPriorityBreakdown:()=>st,getPriorityWithColor:()=>nn,getStatusWithColor:()=>F,getSuggestedActions:()=>Ct,getTaskDescription:()=>Ut,renderDependencyTree:()=>bt,sortTaskIds:()=>An,supportsLinks:()=>Xe,theme:()=>y,truncate:()=>gt});function K(e){xt({tag:e.tag||`master`})}function q(e){return e?ye(e):i()}var xr=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(q(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){M(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),$t(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),en(n),$t(n)}catch(e){let t=e instanceof Error?e.message:String(e);console.error(S.yellow(`\nWarning: Failed to refresh tasks: ${t}`))}else r.type===`error`&&r.error&&console.error(S.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(S.red(`Watch mode error: ${e.message}`)),e}}validateOptions(e){if(e.format&&!o.includes(e.format))return console.error(S.red(`Invalid format: ${e.format}`)),console.error(y.muted(`Valid formats: ${o.join(`, `)}`)),!1;if(e.status){let t=e.status.split(`,`).map(e=>e.trim());for(let e of t)if(e!==`all`&&!u.includes(e))return console.error(S.red(`Invalid status: ${e}`)),console.error(y.muted(`Valid statuses: ${u.join(`, `)}`)),!1}return e.allTags&&e.watch?(console.error(S.red(`--all-tags cannot be used with --watch mode`)),console.error(y.muted(`Use --all-tags without --watch, or --watch without --all-tags`)),!1):!0}async initializeCore(e){this.tmCore||=await a({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))||[]}));return e.ready&&(s=m(s)),e.blocking&&(s=d(s)),t&&n&&(s=s.filter(e=>t.includes(e.status))),{...i,tasks:s,filtered:s.length}}async getTasksFromAllTags(e){if(!this.tmCore)throw Error(`TmCore not initialized`);let t=await this.tmCore.tasks.getTagsWithStats(),n=[],r=0,i=[];for(let a of t.tags){let t=a.name;try{let i=await this.tmCore.tasks.list({tag:t,includeSubtasks:e.withSubtasks});r+=i.tasks.length;let{blocksMap:a,invalidDependencies:o}=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?m(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(S.yellow(`\nWarning: Could not fetch tasks from ${i.length} tag(s):`)),i.forEach(({name:e,error:t})=>{console.warn(y.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(S.yellow(`\nWarning: ${e.length} invalid dependency reference(s) found${n}:`)),e.slice(0,5).forEach(({taskId:e,depId:t})=>{console.warn(y.muted(` Task ${e} depends on non-existent task ${t}`))}),e.length>5&&console.warn(y.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=p[e.status],r=i&&`tagName`in e?y.accent(`[${e.tagName}] `):``;if(console.log(`${r}${S.cyan(e.id)} ${n} ${e.title}`),t.withSubtasks&&e.subtasks?.length)for(let t of e.subtasks){let e=p[t.status];console.log(` ${y.muted(String(t.id))} ${e} ${y.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=it(n),o=at(n),s=ot(n),c=st(n),l=this.findNextTask(n),u=l?n.find(e=>String(e.id)===String(l.id)):void 0,d=t.ready||t.blocking||i;if(d||ft(a,o,c,s,u),console.log(yr(n,{showSubtasks:t.withSubtasks,showDependencies:!0,showBlocks:!0,showComplexity:!0,showTag:i})),!d){if(u){let e=Ut(u);Ht({id:u.id,title:u.title,priority:u.priority,status:u.status,dependencies:u.dependencies,description:e,complexity:u.complexity})}Zt()}}setLastResult(e){this.lastResult=e}findNextTask(e){let t={critical:4,high:3,medium:2,low:1},n=/* @__PURE__ */ new Set;e.forEach(e=>{c(e.status)&&n.add(String(e.id)),e.subtasks&&e.subtasks.forEach(t=>{c(t.status)&&n.add(`${e.id}.${t.id}`)})});let r=[];if(e.filter(e=>e.status===`in-progress`&&e.subtasks&&e.subtasks.length>0).forEach(e=>{e.subtasks.forEach(t=>{let i=(t.status||`pending`).toLowerCase();if(i!==`pending`&&i!==`in-progress`)return;let a=t.dependencies?.map(t=>typeof t==`string`&&t.includes(`.`)?t:`${e.id}.${t}`)??[];(a.length===0||a.every(e=>n.has(String(e))))&&r.push({id:`${e.id}.${t.id}`,title:t.title||`Subtask ${t.id}`,priority:t.priority||e.priority||`medium`,dependencies:a.map(e=>String(e))})})}),r.length>0)return r.sort((e,n)=>{let r=t[e.priority||`medium`]??2,i=t[n.priority||`medium`]??2;if(i!==r)return i-r;let a=e.dependencies?.length||0,o=n.dependencies?.length||0;return a===o?String(e.id).localeCompare(String(n.id)):a-o}),r[0];let i=e.filter(e=>{let t=(e.status||`pending`).toLowerCase();if(t!==`pending`&&t!==`in-progress`)return!1;let r=e.dependencies||[];return r.length===0||r.every(e=>n.has(String(e)))});if(i.length===0)return;i.sort((e,n)=>{let r=t[e.priority||`medium`]??2,i=t[n.priority||`medium`]??2;if(i!==r)return i-r;let a=e.dependencies?.length||0,o=n.dependencies?.length||0;return a===o?Number(e.id)-Number(n.id):a-o});let a=i[0];return{id:a.id,title:a.title,priority:a.priority,dependencies:a.dependencies?.map(e=>String(e))}}getLastResult(){return this.lastResult}async cleanup(){this.tmCore&&=void 0}static register(t,n){let r=new e(n);return t.addCommand(r),r}},Sr=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(q(t.project));let r=e||t.id;r||(j(`Missing task ID`,"Try `taskgraph show 3`"),process.exit(1));let i=r.split(`,`).map(e=>e.trim()).filter(e=>e.length>0),a=[];for(let e of i){let t=n.safeParse(e);t.success||(j(`"${e}" isn't a task ID`,"Use a number like `3`, or `3.1` for a subtask"),process.exit(1)),a.push(t.data)}let o=a.length>1?await this.getMultipleTasks(a,t):await this.getSingleTask(a[0],t);this.setLastResult(o),t.silent||this.displayResults(o,t)}catch(e){M(e)}}validateOptions(e){return e.format&&![`text`,`json`].includes(e.format)?(console.error(S.red(`Invalid format: ${e.format}`)),console.error(y.muted(`Valid formats: text, json`)),!1):!0}async initializeCore(e){this.tmCore||=await a({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;j(`${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(),Vt(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(S.yellow(`\n⚠ Not found: ${e.notFound.join(`, `)}`)),e.tasks.length===0?gr(`No tasks found matching the criteria.`):(console.log(y.brand.bold(`
85
+ Tasks:
86
+ `)),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}},Cr=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(q(e.project));let t=await this.getNextTask(e);this.setLastResult(t),e.silent||this.displayResults(t,e)}catch(e){t=!0,M(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=C.resolve(e);this.tmCore=await a({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(S.yellow(`✓ All tasks are either completed, blocked by dependencies, or in progress.`)),console.log(`\n${S.dim(`Tip: Try`)} ${S.cyan(`taskgraph list`)} ${S.dim(`to see all tasks`)}`)):(console.log(O(S.yellow(`No tasks found in this project.`),{padding:1,borderStyle:`round`,borderColor:`yellow`,title:`No tasks available`,titleAlignment:`center`})),console.log(`\n${S.dim(`Tip: Create tasks with`)} ${S.cyan(`taskgraph parse-prd`)} ${S.dim(`or`)} ${S.cyan(`taskgraph add-task`)}`));return}let t=e.task;Vt(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}},wr=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 what depends on it`).option(`-t, --tag <tag>`,`Use a specific tag`).option(`-f, --format <format>`,`Output format (text, json)`,`text`).option(`-p, --project <path>`,`Project root directory (auto-detected if not provided)`).action(async e=>{await this.executeCommand(e)})}async executeCommand(e){let t=!1;try{if(e.format&&![`text`,`json`].includes(e.format))throw Error(`Invalid format: ${e.format}. Valid formats are: text, json`);let t=C.resolve(q(e.project));this.tmCore=await a({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,M(e,{skipExit:!0})}finally{this.tmCore=void 0}t&&process.exit(1)}displayText(e){if(K({tag:e.tag}),e.total===0){console.log(S.yellow(`No tasks yet.`)),console.log(`${y.muted(`Create some with`)} ${y.brand(`taskgraph parse-prd`)} ${y.muted(`or`)} ${y.brand(`taskgraph add-task`)}`);return}console.log();let t=bt(e,{nextId:e.nextId,width:L()});console.log(t.join(`
87
+ `))}static register(t,n){let r=new e(n);return t.addCommand(r),r}},Tr=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(q(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`),M(e)}}validateOptions(e){return e.format&&![`text`,`json`].includes(e.format)?(console.error(S.red(`Invalid format: ${e.format}`)),console.error(y.muted(`Valid formats: text, json`)),!1):!0}async initializeCore(e){this.tmCore||=await a({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(S.green(`Starting: `)+S.bold(r)),console.log(y.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(S.green(`Launching Claude Code…`)),console.log();let r=w(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(S.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}`),Vt(n,{customHeader:t,headerColor:`yellow`}),e.executionOutput&&(console.log(),console.log(O(S.bold(`Claude-Code Prompt:`)+`
88
+
89
+ `+e.executionOutput,{padding:1,borderStyle:`round`,borderColor:v,width:process.stdout.columns*.95||100}))),console.log(),console.log(O(S.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(S.green.bold(`✓ Task session complete`)+`
90
+
91
+ `+y.text(t)+`
92
+
93
+ `+S.cyan(`Next steps:`)+`
94
+ • Run ${S.yellow(`taskgraph show `+n.id)} to review task details\n• Run ${S.yellow(`taskgraph set-status --id=`+r+` --status=done`)} when complete\n• Run ${S.yellow(`taskgraph next`)} to find the next available task\n• Run ${S.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(S.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 Er=[`pending`,`in-progress`,`done`,`deferred`,`cancelled`,`blocked`,`review`];var Dr=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 - ${Er.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||(j(`Missing task ID`,"Try `taskgraph set-status --id=3 --status=done`"),process.exit(1)),e.status||(j(`Missing status`,`Try \`taskgraph set-status --id=${e.id} --status=done\``),process.exit(1)),Er.includes(e.status)||(j(`"${e.status}" isn't a status`,`Use one of: ${Er.join(`, `)}`),process.exit(1)),this.tmCore=await a({projectPath:q(e.project)});let r=e.id.split(`,`).map(e=>e.trim()),i=[];for(let e of r){let t=n.safeParse(e);t.success||(j(`"${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 o=[],s;for(let n of i)try{let t=await this.tmCore.tasks.updateStatus(n,e.status);o.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 s=r;break}this.lastResult={success:!t,updatedTasks:o},(o.length>0&&!(t&&e.format===`json`)||!t)&&this.displayResults(this.lastResult,e),s!==void 0&&!e.silent&&M(s,{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||M(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${bn(e.updatedTasks)}`)}getLastResult(){return this.lastResult}static register(t,n){let r=new e(n);return t.addCommand(r),r}};const J=`taskgraph-ai`,Or=`stephennmiller/taskgraph-ai`;function kr(e,t,n){let r=`${y.brand.bold(`Update Available!`)} ${S.dim(e)} → ${S.green(t)}`;if(n&&n.length>0){r+=`
95
+
96
+ `+S.bold(`What's New:`);for(let e of n)r+=`
97
+ `+S.cyan(`• `)+e;r+=`
98
+
99
+ Auto-updating to the latest version...`}else r+=`
100
+
101
+ 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)}function Y(e){return e<1024?`${e} B`:e<1048576?`${(e/1024).toFixed(1)} KB`:`${(e/1048576).toFixed(1)} MB`}async function Ar(e){return new Promise(t=>{let n={hostname:`registry.npmjs.org`,path:`/${J}/${e}`,method:`GET`,headers:{Accept:`application/json`,"User-Agent":`${J}/${e}`}},r=Ne.request(n,e=>{let n=``;e.on(`data`,e=>{n+=e}),e.on(`end`,()=>{try{if(e.statusCode!==200){t(null);return}let r=JSON.parse(n),i=r.dist?.tarball,a=r.dist?.unpackedSize;if(!i){t(null);return}t({url:i,size:a||0})}catch{t(null)}})});r.on(`error`,()=>{t(null)}),r.setTimeout(1e4,()=>{r.destroy(),t(null)}),r.end()})}async function jr(e,t,n,r=5){return r<=0?(console.error(S.red(`Too many redirects`)),Promise.resolve(!1)):new Promise(i=>{let a=new URL(e),o={hostname:a.hostname,path:a.pathname,method:`GET`,headers:{"User-Agent":`${J}/${n}`}},s=Ne.request(o,e=>{if(e.statusCode===301||e.statusCode===302){let a=e.headers.location;if(a){jr(a,t,n,r-1).then(i).catch(()=>i(!1));return}i(!1);return}if(e.statusCode!==200){i(!1);return}let a=Number.parseInt(e.headers[`content-length`]||`0`,10),o=0,s=new Fe.SingleBar({format:`${y.brand(`Downloading`)} ${S.cyan(`{bar}`)} {percentage}% | {downloaded}/{total}`,barCompleteChar:`█`,barIncompleteChar:`░`,hideCursor:!0,clearOnComplete:!0},Fe.Presets.shades_classic);a>0?s.start(a,0,{downloaded:Y(0),total:Y(a)}):console.log(y.brand(`Downloading ${J}@${n}...`));let c=E.createWriteStream(t);e.on(`data`,e=>{o+=e.length,a>0&&s.update(o,{downloaded:Y(o),total:Y(a)})}),e.pipe(c),c.on(`finish`,()=>{a>0&&s.stop(),c.close(()=>{console.log(S.green(`✓`)+S.dim(` Downloaded ${Y(o)}`)),i(!0)})}),c.on(`error`,e=>{a>0&&s.stop(),console.error(S.red(`Download error:`),e.message),E.unlink(t,()=>{}),i(!1)})});s.on(`error`,e=>{console.error(S.red(`Request error:`),e.message),i(!1)}),s.setTimeout(12e4,()=>{s.destroy(),console.error(S.red(`Download timeout`)),i(!1)}),s.end()})}const X=[{name:`Extracting package`,weight:15},{name:`Resolving dependencies`,weight:25},{name:`Building dependency tree`,weight:20},{name:`Linking package`,weight:25},{name:`Finalizing installation`,weight:15}],Mr=X.reduce((e,t)=>e+t.weight,0);function Nr(e){let t=e.toLowerCase();return t.includes(`extract`)||t.includes(`unpack`)?0:t.includes(`resolv`)||t.includes(`fetch`)?1:t.includes(`build`)||t.includes(`tree`)?2:t.includes(`link`)||t.includes(`bin`)?3:t.includes(`added`)||t.includes(`done`)?4:-1}function Pr(e,t){if(e<0||e>=X.length)return e>=X.length?100:0;let n=0;for(let t=0;t<e;t++)n+=X[t].weight;let r=X[e].weight*t/100;return Math.round((n+r)/Mr*100)}async function Fr(e){let t=new Fe.SingleBar({format:`${y.brand(`Installing`)} ${S.cyan(`{bar}`)} {percentage}% | {phase}`,barCompleteChar:`█`,barIncompleteChar:`░`,hideCursor:!0,clearOnComplete:!0},Fe.Presets.shades_classic);t.start(100,0,{phase:X[0].name});let n=0,r=0,i=Date.now(),a=setInterval(()=>{let e=Date.now()-i,a=1e4,o=0,s=0;for(let t=0;t<X.length;t++){let n=X[t].weight/Mr*a;if(e<s+n){o=t;break}s+=n,o=t}o>n&&(n=o);let c=X.slice(0,n).reduce((e,t)=>e+t.weight,0)/Mr*a,l=X[n].weight/Mr*a,u=e-c,d=Math.min(u/l*100,95),f=Pr(n,d);f>r&&(r=f,t.update(r,{phase:X[n].name}))},100);return new Promise(i=>{let o=w(`npm`,[`install`,`-g`,e,`--no-fund`,`--no-audit`],{stdio:[`ignore`,`pipe`,`pipe`]}),s=``;o.stdout.on(`data`,e=>{let i=Nr(e.toString());if(i>n){n=i;let e=Pr(n,0);e>r&&(r=e,t.update(r,{phase:X[n].name}))}}),o.stderr.on(`data`,e=>{let i=e.toString();s+=i;let a=Nr(i);if(a>n){n=a;let e=Pr(n,0);e>r&&(r=e,t.update(r,{phase:X[n].name}))}}),o.on(`close`,n=>{if(clearInterval(a),t.update(100,{phase:`Complete`}),t.stop(),E.existsSync(e)&&E.unlink(e,()=>{}),n===0)console.log(S.green(`✓`)+S.green(` Update installed successfully`)),i(!0);else{if(console.log(S.red(`✗`)+S.red(` Installation failed`)),s){let e=s.split(`
102
+ `).filter(e=>e.includes(`ERR`)||e.includes(`error`)||e.includes(`WARN`)).join(`
103
+ `).trim();e&&console.log(S.dim(`Error: ${e}`))}i(!1)}}),o.on(`error`,n=>{clearInterval(a),t.stop(),E.unlink(e,()=>{}),console.log(S.red(`✗`)+S.red(` Installation failed`)),console.log(S.red(`Error:`),n.message),i(!1)})})}async function Ir(e){let t=z(y.brand(`Updating ${J} to version ${S.green(e)}`)).start();return new Promise(n=>{let r=w(`npm`,[`install`,`-g`,`${J}@${e}`,`--no-fund`,`--no-audit`,`--loglevel=warn`],{stdio:[`ignore`,`pipe`,`pipe`]}),i=``;r.stdout.on(`data`,()=>{t.text=y.brand(`Installing ${J}@${e}...`)}),r.stderr.on(`data`,e=>{i+=e.toString()}),r.on(`close`,r=>{r===0?(t.succeed(S.green(`Successfully updated to version ${S.bold(e)}`)),n(!0)):(t.fail(S.red(`Auto-update failed`)),console.log(S.cyan(`Please run manually: npm install -g ${J}@${e}`)),i&&console.log(S.dim(`Error: ${i.trim()}`)),n(!1))}),r.on(`error`,r=>{t.fail(S.red(`Auto-update failed`)),console.log(S.red(`Error:`),r.message),console.log(S.cyan(`Please run manually: npm install -g ${J}@${e}`)),n(!1)})})}async function Lr(e){if(k.env.TASKGRAPH_SKIP_AUTO_UPDATE===`1`||k.env.CI||k.env.NODE_ENV===`test`){let e=k.env.TASKGRAPH_SKIP_AUTO_UPDATE===`1`?`TASKGRAPH_SKIP_AUTO_UPDATE=1`:k.env.CI?`CI environment`:`NODE_ENV=test`;return console.log(S.dim(`Skipping auto-update (${e})`)),!1}let t=await Ar(e);if(!t)return Ir(e);let n=Pe.tmpdir(),r=be.join(n,`${J}-${e}.tgz`);return await jr(t.url,r,e)?await Fr(r)?(console.log(S.green(`Successfully updated to version ${S.bold(e)}`)),!0):(console.log(S.cyan(`Please run manually: npm install -g ${J}@${e}`)),!1):(console.log(S.dim(`Falling back to npm install...`)),Ir(e))}function Rr(e){let t=e.slice(2);console.log(S.dim(`Restarting with updated version...
104
+ `));let n=w(`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(S.red(`Failed to restart with new version:`),e.message),console.log(S.yellow(`Please run your command again manually.`)),k.exit(1)})}function zr(e,t=null){let n={high:3,medium:2,low:1},r=(e,t)=>typeof t==`string`&&t.includes(`.`)?t:`${e}.${t}`,i=/* @__PURE__ */ new Set;e.forEach(e=>{(e.status===`done`||e.status===`completed`)&&i.add(String(e.id)),Array.isArray(e.subtasks)&&e.subtasks.forEach(t=>{(t.status===`done`||t.status===`completed`)&&i.add(`${e.id}.${t.id}`)})});let a=[];if(e.filter(e=>e.status===`in-progress`&&Array.isArray(e.subtasks)).forEach(e=>{e.subtasks.forEach(t=>{let n=(t.status||`pending`).toLowerCase();if(n!==`pending`&&n!==`in-progress`)return;let o=t.dependencies?.map(t=>r(e.id,t))??[];(o.length===0||o.every(e=>i.has(String(e))))&&a.push({id:`${e.id}.${t.id}`,title:t.title||`Subtask ${t.id}`,status:t.status||`pending`,priority:t.priority||e.priority||`medium`,dependencies:o,parentId:e.id})})}),a.length>0){a.sort((e,t)=>{let r=n[e.priority]??2,i=n[t.priority]??2;if(i!==r)return i-r;if(e.dependencies.length!==t.dependencies.length)return e.dependencies.length-t.dependencies.length;let[a,o]=e.id.split(`.`).map(Number),[s,c]=t.id.split(`.`).map(Number);return a===s?o-c:a-s});let e=a[0];return e&&t&&ne(e,t),e}let o=e.filter(e=>{let t=(e.status||`pending`).toLowerCase();return t!==`pending`&&t!==`in-progress`?!1:(e.dependencies??[]).every(e=>i.has(String(e)))});if(o.length===0)return null;let s=o.sort((e,t)=>{let r=n[e.priority||`medium`]??2,i=n[t.priority||`medium`]??2;if(i!==r)return i-r;let a=(e.dependencies??[]).length,o=(t.dependencies??[]).length;return a===o?e.id-t.id:a-o})[0];return s&&t&&ne(s,t),s}function Br(e){let t=Error(e);return t.hint="Use letters, numbers, - and _, like `feature-auth`",t}function Vr(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 Hr(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)=>g(`info`,...e),warn:(...e)=>g(`warn`,...e),error:(...e)=>g(`error`,...e),debug:(...e)=>g(`debug`,...e),success:(...e)=>g(`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 Br(`"${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=Vr(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||_(o);a=ae(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 b(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||_(o):null,description:l})),{tagName:t,created:!0,tasksCopied:a.length,sourceTag:s||c?c||_(o):null,description:l||u}}catch(e){throw a&&d.error(`Error creating tag: ${e.message}`),e}}async function Ur(e,t,n={},r={},i=`text`){let{mcpLog:a,projectRoot:o}=r,{yes:s=!1}=n,c=a||{info:(...e)=>g(`info`,...e),warn:(...e)=>g(`warn`,...e),error:(...e)=>g(`error`,...e),debug:(...e)=>g(`debug`,...e),success:(...e)=>g(`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=_(o)===t,l=ae(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(y.muted(`Cancelled; nothing was deleted`)),process.exit(130)}if(!n)return console.log(y.muted(`Cancelled; nothing was deleted`)),{tagName:t,deleted:!1,cancelled:!0}}delete r[t],a&&(await Z(o,`master`),c.debug(`Switched current tag to "master"`));let u={};for(let[e,t]of Object.entries(r))e!==`_rawTaggedData`&&(u[e]=t);return b(e,u,o),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 Wr(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);b(e,r,n.projectRoot)}}catch(e){(n.mcpLog||{warn:(...e)=>g(`warn`,...e)}).warn(`Could not enhance tag metadata: ${e.message}`)}return r}async function Gr(e,t={},n={},r=`text`){let{mcpLog:i,projectRoot:a}=n,{showTaskCounts:o=!0,showMetadata:s=!1,ready:l=!1}=t,u=i||{info:(...e)=>g(`info`,...e),warn:(...e)=>g(`warn`,...e),error:(...e)=>g(`error`,...e),debug:(...e)=>g(`debug`,...e),success:(...e)=>g(`success`,...e)};try{u.debug(`Listing available tags`),u.debug(`Using file storage for tags`);let t=Vr(e,a),i=_(a),o=t._rawTaggedData||t;await Wr(e,o,n);let d=[];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=m(a);d.push({name:e,isCurrent:e===i,completedTasks:n.filter(e=>c(e.status)).length,readyTasks:o.length,tasks:n||[],created:r.created||`Unknown`,description:r.description||`No description`})}d.sort((e,t)=>e.isCurrent?-1:t.isCurrent?1:e.name.localeCompare(t.name));let f=d;return l&&(f=d.filter(e=>e.readyTasks>0),u.debug(`Filtered to ${f.length} tags with ready tasks`)),u.debug(`Found ${f.length} tags`),r===`json`||r===`text`&&console.log(dr(f.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:l})),{tags:f,currentTag:i,totalTags:f.length}}catch(e){throw i&&u.error(`Error listing tags: ${e.message}`),e}}async function Kr(e,t,n={},r={},i=`text`){let{mcpLog:a,projectRoot:o}=r,s=a||{info:(...e)=>g(`info`,...e),warn:(...e)=>g(`warn`,...e),error:(...e)=>g(`error`,...e),debug:(...e)=>g(`debug`,...e),success:(...e)=>g(`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=_(o);await Z(o,t);let a=x(e,o,t),c=a&&a.tasks||[],l=c.length,u=zr(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 qr(e,t,n,r={},i={},a=`text`){let{mcpLog:o,projectRoot:s}=i,c=o||{info:(...e)=>g(`info`,...e),warn:(...e)=>g(`warn`,...e),error:(...e)=>g(`error`,...e),debug:(...e)=>g(`debug`,...e),success:(...e)=>g(`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 Br(`"${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=_(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);b(e,l,s);let u=ae(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 Jr(e,t,n,r={},i={},a=`text`){let{mcpLog:o,projectRoot:s}=i,{description:c}=r,l=o||{info:(...e)=>g(`info`,...e),warn:(...e)=>g(`warn`,...e),error:(...e)=>g(`error`,...e),debug:(...e)=>g(`debug`,...e),success:(...e)=>g(`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 Br(`"${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=ae(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 b(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=be.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){g(`warn`,`Could not update current tag in state.json: ${e.message}`)}}async function Yr(e,t,n){try{let r=be.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){g(`warn`,`Could not update branch-tag mapping: ${e.message}`)}}async function Xr(e,t,n={},r={},i=`text`){let{mcpLog:a,projectRoot:o}=r,{copyFromCurrent:s,copyFromTag:c,description:l,autoSwitch:u}=n,{sanitizeBranchNameForTag:d,isValidBranchForTag:f}=await import(`./git-utils-BezpEZd4.js`),p=a||{info:(...e)=>g(`info`,...e),warn:(...e)=>g(`warn`,...e),error:(...e)=>g(`error`,...e),debug:(...e)=>g(`debug`,...e),success:(...e)=>g(`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 Hr(e,n,{copyFromCurrent:s,copyFromTag:c,description:l,defaultDescription:`Tag created from git branch "${t}"`},r,i);return await Yr(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}}var Zr=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`).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 a({projectPath:process.cwd()})}async executeList(e){try{await this.initTmCore();let{projectRoot:t,tasksPath:n}=h(),r=await Gr(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){M(e),this.setLastResult({success:!1,action:`list`,message:e.message}),this.handleError(e instanceof Error?e:Error(e.message||String(e)))}}async executeAdd(e,t){try{await this.initTmCore();let{projectRoot:n,tasksPath:r}=h();await Hr(r,e,{description:t?.description,copyFromTag:t?.copyFrom,fromBranch:t?.fromBranch},{projectRoot:n},`text`),this.setLastResult({success:!0,action:`add`,message:`Created tag: ${e}`})}catch(e){M(e),this.setLastResult({success:!1,action:`add`,message:e.message}),this.handleError(e instanceof Error?e:Error(e.message||String(e)))}}async executeUse(e){try{await this.initTmCore();let{projectRoot:t,tasksPath:n}=h(),r=await Kr(n,e,{},{projectRoot:t},`text`);this.setLastResult({success:!0,action:`use`,currentTag:r.currentTag,message:`Switched to tag: ${e}`})}catch(e){M(e),this.setLastResult({success:!1,action:`use`,message:e.message}),this.handleError(e instanceof Error?e:Error(e.message||String(e)))}}async executeRemove(e,t){try{await this.initTmCore();let{projectRoot:n,tasksPath:r}=h(),i=await Ur(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){M(e),this.setLastResult({success:!1,action:`remove`,message:e.message}),this.handleError(e instanceof Error?e:Error(e.message||String(e)))}}async executeRename(e,t){try{await this.initTmCore();let{projectRoot:n,tasksPath:r}=h();await qr(r,e,t,{},{projectRoot:n},`text`),this.setLastResult({success:!0,action:`rename`,message:`Renamed tag from "${e}" to "${t}"`})}catch(e){M(e),this.setLastResult({success:!1,action:`rename`,message:e.message}),this.handleError(e instanceof Error?e:Error(e.message||String(e)))}}async executeCopy(e,t,n){try{await this.initTmCore();let{projectRoot:r,tasksPath:i}=h();await Jr(i,e,t,{description:n?.description},{projectRoot:r},`text`),this.setLastResult({success:!0,action:`copy`,message:`Copied tag from "${e}" to "${t}"`})}catch(e){M(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}},Qr=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 (${r.join(`, `)}) or path to custom prompt file`,`default`).option(`--progress-file <path>`,`Path to progress log file`,`.taskgraph/progress.txt`).option(`-t, --tag <tag>`,`Only work on tasks with this tag`).option(`--project <path>`,`Project root directory (auto-detected if not provided)`).option(`--sandbox`,`Run Claude in Docker sandbox mode`).option(`--no-output`,`Exclude full Claude output from iteration results`).option(`-v, --verbose`,`Show Claude's work in real-time`).action(e=>this.execute(e))}async execute(e){let t=e.prompt||`default`,n=e.progressFile||`.taskgraph/progress.txt`;try{let r=C.resolve(q(e.project));this.tmCore=await a({projectPath:r});let i=t==="default"?await this.tmCore.tasks.getCount(`pending`,e.tag):void 0,o=this.tmCore.loop.resolveIterations({userIterations:e.iterations?parseInt(e.iterations,10):void 0,preset:t,pendingTaskCount:i});if(this.validateIterations(String(o)),K({tag:e.tag||`master`}),e.sandbox&&this.handleSandboxAuth(),console.log(S.cyan(`Starting TaskGraph Loop...`)),console.log(S.dim(`Preset: ${t}`)),console.log(S.dim(`Max iterations: ${o}`)),console.log(S.dim(`Mode: ${e.sandbox?`Docker sandbox`:`Claude CLI`}`)),t==="default"){let t=await this.tmCore.tasks.getNext(e.tag);console.log(t?y.text(`Next task to work on: ${y.text(t.id)} - ${t.title}`):S.yellow(`No pending tasks found`))}console.log();let s={iterations:o,prompt:t,progressFile:n,tag:e.tag,sandbox:e.sandbox,includeOutput:e.output??!0,verbose:e.verbose??!1,callbacks:this.createOutputCallbacks()},c=await this.tmCore.loop.run(s);this.displayResult(c)}catch(e){M(e,{skipExit:!0}),process.exit(1)}}handleSandboxAuth(){console.log(S.dim(`Checking sandbox auth...`));let e=this.tmCore.loop.checkSandboxAuth();if(e.error)throw Error(e.error);if(e.ready){console.log(S.green(`✓ Sandbox ready`));return}console.log(S.yellow(`Sandbox needs authentication. Starting interactive session...`)),console.log(S.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(S.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(S.cyan(`━━━ Iteration ${e} of ${t} ━━━`))},onText:e=>{console.log(e)},onToolUse:e=>{console.log(S.dim(` → ${e}`))},onError:(e,t)=>{console.error(t===`warning`?S.yellow(`[Loop Warning] ${e}`):S.red(`[Loop Error] ${e}`))},onStderr:(e,t)=>{process.stderr.write(S.dim(`[Iteration ${e}] `)+t)},onOutput:e=>{console.log(e)},onIterationEnd:e=>{let t=e.status===`success`?S.green:e.status===`error`?S.red:S.yellow;console.log(t(` Iteration ${e.iteration} completed: ${e.status}`))}}}displayResult(e){console.log(),console.log(S.bold(`Loop Complete`)),console.log(S.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(S.red(`Error: ${e.errorMessage}`))}formatStatus(e){return{all_complete:S.green(`All tasks complete`),max_iterations:S.yellow(`Max iterations reached`),blocked:S.red(`Blocked`),error:S.red(`Error`)}[e]}static register(t,n){let r=new e(n);return t.addCommand(r),r}};function $r(e,t={}){let n=t.home??xe.homedir(),r=t.env??process.env,i=t.platform??process.platform;switch(e){case`zsh`:return{script:C.join(n,`.taskgraph-completion.zsh`),rc:C.join(r.ZDOTDIR||n,`.zshrc`)};case`bash`:{let e=C.join(n,`.bash_profile`),t=i===`darwin`&&T.existsSync(e)?e:C.join(n,`.bashrc`);return{script:C.join(n,`.taskgraph-completion.bash`),rc:t}}case`fish`:return{script:C.join(r.XDG_CONFIG_HOME||C.join(n,`.config`),`fish`,`completions`,`taskgraph.fish`)}}}function Q(e,t=xe.homedir()){return e===t||e.startsWith(t+C.sep)?`~${e.slice(t.length)}`:e}function ei(e,t,n={}){let r=n.home??xe.homedir(),i=$r(e,n),a=T.existsSync(i.script);if(T.mkdirSync(C.dirname(i.script),{recursive:!0}),T.writeFileSync(i.script,t),!i.rc)return{...i,replaced:a,rcUpdated:!1};let o=i.script.startsWith(r+C.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 ti(e){return JSON.stringify(e).replace(/'/g,`\\u0027`).replace(/\\\\/g,`\\u005c`).replace(/`/g,`\\u0060`)}function ni(e){return`var SPEC = ${ti(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 ri=[`bash`,`zsh`,`fish`];function ii(e){return ri.includes(e)}function ai(e=process.env.SHELL){let t=(e||``).split(`/`).pop()||``;return ii(t)?t:void 0}function oi(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 si(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 ci(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 li(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 ui(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 di(e,t,n=`unknown`){let r=ni(t);if(r.includes(`'`)||r.includes(`\\\\`))throw Error(`Completion program cannot be quoted for the shell`);let i={bash:ci,zsh:li,fish:ui}[e](r);return`${e===`zsh`?`#compdef taskgraph
444
+ `:``}${si(e,n)}\n\n${i}`}const fi=[`pending`,`in-progress`,`done`,`review`,`blocked`,`deferred`,`cancelled`],pi=[`high`,`medium`,`low`],mi=/* @__PURE__ */ new Set([`id`,`ids`,`taskid`,`task-id`,`parent`,`dependencies`]),hi=/* @__PURE__ */ new Set([`tag`,`tagname`,`oldname`,`sourcename`,`source`,`name`]),gi=/* @__PURE__ */ new Set([`--tag`,`--from-tag`,`--to-tag`,`--copy-from`]),_i=/* @__PURE__ */ new Set([`--from`,`--to`,`--save-to`]),vi=/* @__PURE__ */ new Set([`file`,`files`,`paths`]),yi=/* @__PURE__ */ new Set([`dir`,`path`]),bi=/* @__PURE__ */ new Set([`add`,`add-tag`]);function xi(e){let t=e.match(/[<[]([^>\]]+?)(?:\.\.\.)?[>\]]/);return t?t[1].toLowerCase():void 0}function Si(e,t,n){if(t?.length)return{kind:`choices`,choices:[...t]};let r=n.long;return r===`--status`||e===`status`?{kind:`choices`,choices:fi}:r===`--priority`||e===`priority`?{kind:`choices`,choices:pi}:r===`--format`||e===`format`?{kind:`choices`,choices:[`text`,`json`]}:r&&gi.has(r)?{kind:`tags`}:r&&_i.has(r)?{kind:`ids`}:r===`--project`||r===`--project-root`||r===`--output`?{kind:r===`--output`?`files`:`dirs`}:e?mi.has(e)?{kind:`ids`}:hi.has(e)?bi.has(n.command)?{kind:`none`}:{kind:`tags`}:vi.has(e)?{kind:`files`}:yi.has(e)?{kind:`dirs`}:{kind:`none`}:{kind:`none`}}function Ci(e,t){let n=e.required||e.optional;return{short:e.short,long:e.long,description:Ti(e.description),value:n?Si(xi(e.flags),e.argChoices,{long:e.long,command:t}):void 0,...e.optional?{optional:!0}:{},...e.variadic?{variadic:!0}:{}}}function wi(e,t){return{name:e.name(),variadic:e.variadic,value:Si(e.name().toLowerCase(),e.argChoices,{command:t})}}function Ti(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 Ei(e){return!!e._hidden||/^\[deprecated\]/i.test(e.description())}function Di(e){let t=e=>{let n=e.name(),r=e.options.filter(e=>!e.hidden).map(e=>Ci(e,n));return r.some(e=>e.long===`--help`)||r.push({short:`-h`,long:`--help`,description:`Show help`}),{name:n,aliases:e.aliases(),description:Ti(e.description()),options:r,args:e.registeredArguments.map(e=>wi(e,n)),commands:e.commands.filter(e=>!Ei(e)).map(t)}};return t(e)}var Oi=class e extends D{constructor(e){super(e||`completion`),this.description(`Set up Tab completion for bash, zsh or fish`).addArgument(new Se(`[shell]`,`Shell to complete for (default: yours)`).choices(ri)).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){M(e,{skipExit:!0}),process.exit(1)}}detectedShell(){let e=ai();if(!e)throw Error(`Couldn't tell which shell you use. Name it: taskgraph completion <${ri.join(`|`)}>`);return e}script(e){let t=this;for(;t.parent;)t=t.parent;return di(e,Di(t),t.version()||`unknown`)}install(e){let t=ei(e,this.script(e)),n=S.green(`✓`);console.log(),console.log(`${n} ${t.replaced?`Updated`:`Wrote`} ${y.brand(Q(t.script))}`),t.rc&&t.rcUpdated?console.log(`${n} Loaded it from ${y.brand(Q(t.rc))}`):t.rc&&console.log(`${n} ${y.brand(Q(t.rc))} ${y.muted(`already loads it`)}`),console.log(),console.log(`Open a new terminal, then try ${y.brand(`taskgraph show <Tab>`)}`),console.log(y.muted(`Run this again after upgrading TaskGraph to pick up new commands.`))}displayInstructions(e,t){let n=$r(e),r=n.rc?`Writes ${Q(n.script)} and loads it from ${Q(n.rc)}.`:`Writes ${Q(n.script)}.`;console.log(),console.log(S.bold(`Tab completion for ${e}`)),console.log(),console.log(` ${y.brand(`taskgraph completion --install`)}`),console.log(` ${y.muted(r)}`),console.log(),console.log(y.muted(`Or by hand:`));for(let t of oi(e))console.log(` ${t}`);if(t){let t=ri.filter(t=>t!==e).join(`|`);console.log(),console.log(y.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(S.cyan(`${t}:`)),this.outputObject(n,` `)):console.log(y.text(`${t}: ${n}`))}outputObject(e,t){for(let[n,r]of Object.entries(e))typeof r==`object`&&r?(console.log(S.cyan(`${t}${n}:`)),this.outputObject(r,t+` `)):console.log(y.muted(`${t}${n}: ${r}`))}error(e,t){if(this.useJson)console.error(JSON.stringify({error:e,...t},null,2));else if(console.error(S.red(`Error: ${e}`)),t)for(let[e,n]of Object.entries(t))console.error(y.muted(` ${e}: ${n}`))}success(e,t){this.useJson?console.log(JSON.stringify({success:!0,message:e,...t},null,2)):(console.log(S.green(`✓ ${e}`)),t&&this.output(t))}warning(e){this.useJson?console.warn(JSON.stringify({warning:e},null,2)):console.warn(S.yellow(`⚠ ${e}`))}info(e){this.useJson||console.log(y.brand(`ℹ ${e}`))}},ki=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=q(e.projectRoot||t?.projectRoot);n={...n,projectRoot:i};let o=await a({projectPath:i});if(!await o.workflow.hasWorkflow()){r.warning(`No active workflow to abort`);return}await o.workflow.resume();let s=o.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 ${s.taskId}. Progress: ${s.progress?.completed||0}/${s.progress?.total||0} subtasks completed. Continue?`,default:!1}]);if(!e){r.info(`Abort cancelled`);return}}await o.workflow.abort(),r.success(`Workflow aborted`,{taskId:s.taskId,branchName:s.branchName,progress:s.progress,lastSubtask:s.currentSubtask?{id:s.currentSubtask.id,title:s.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)}}},Ai=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 n=this.parent?.opts(),r={...n,...e,projectRoot:q(e.projectRoot||n?.projectRoot)},i=new $(r.json||!1);try{let e=r.projectRoot,n=await a({projectPath:e});await n.workflow.hasWorkflow()||(i.error(`No active workflow`,{suggestion:`Start a workflow with: autopilot start <taskId>`}),process.exit(1)),await n.workflow.resume();let o=n.workflow.getStatus(),s=n.workflow.getContext();o.tddPhase!==`COMMIT`&&(i.error(`Not in COMMIT phase`,{currentPhase:o.tddPhase||o.phase,suggestion:`Complete RED and GREEN phases first`}),process.exit(1)),o.currentSubtask||(i.error(`No current subtask`),process.exit(1));let c=new te(e);await c.ensureGitRepository(),await c.hasStagedChanges()||(i.info(`No staged changes, staging all changes...`),await c.stageFiles([`.`]));let l=await c.getStatus(),u=[...l.staged,...l.modified],d=new t,f=s.lastTestResults,p=d.generateMessage({type:`feat`,description:o.currentSubtask.title,changedFiles:u,taskId:o.taskId,phase:o.tddPhase,tag:s.metadata.tag||void 0,testsPassing:f?.passed,testsFailing:f?.failed,coveragePercent:void 0});await c.createCommit(p,{metadata:{taskId:o.taskId,subtaskId:o.currentSubtask.id,phase:`COMMIT`,tddCycle:`complete`}});let m=await c.getLastCommit(),h=await n.workflow.commit(),ee=h.phase===`COMPLETE`;i.success(`Commit created`,{commitHash:m.hash.substring(0,7),message:p.split(`
447
+ `)[0],subtask:{id:o.currentSubtask.id,title:o.currentSubtask.title},progress:h.progress,nextAction:ee?`All subtasks complete. Run: autopilot status`:`Start next subtask with RED phase`})}catch(e){i.error(e.message),r.verbose&&console.error(e.stack),process.exit(1)}}},ji=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:q(e.projectRoot||t?.projectRoot)},r=new $(n.json||!1);try{let e=n.projectRoot,t=await a({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=i.tddPhase,s=i.currentSubtask;if(o||(r.error(`Not in a TDD phase`,{phase:i.phase}),process.exit(1)),o===`RED`||o===`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:o}}catch(e){r.error(`Invalid test results JSON`,{error:e.message}),process.exit(1)}o===`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)),o===`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);o===`RED`?r.success(`RED phase completed`,{nextPhase:i.tddPhase||`GREEN`,testResults:e,subtask:s?.title}):r.success(`GREEN phase completed`,{nextPhase:i.tddPhase||`COMMIT`,testResults:e,subtask:s?.title,suggestion:`Run: autopilot commit`})}else o===`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)}}},Mi=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=q(e.projectRoot||t?.projectRoot);n={...n,projectRoot:i};let o=await a({projectPath:i});await o.workflow.hasWorkflow()||(r.error(`No active workflow`,{suggestion:`Start a workflow with: autopilot start <taskId>`}),process.exit(1)),await o.workflow.resume();let s=o.workflow.getStatus();s.phase!==`FINALIZE`&&(r.error(`Cannot finalize: workflow is in ${s.phase} phase`,{suggestion:`Complete all subtasks first`}),process.exit(1)),r.info(`Validating working tree and finalizing workflow...`);let c=await o.workflow.finalize();r.success(`Workflow completed`,{taskId:c.taskId,phase:c.phase,branchName:c.branchName,progress:c.progress})}catch(e){r.error(e.message),n.verbose&&console.error(e.stack),process.exit(1)}}},Ni=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=q(e.projectRoot||t?.projectRoot);n={...n,projectRoot:i};let o=await a({projectPath:i});await o.workflow.hasWorkflow()||(r.error(`No active workflow`,{suggestion:`Start a workflow with: autopilot start <taskId>`}),process.exit(1)),await o.workflow.resume();let s=o.workflow.getStatus(),c=o.workflow.getNextAction(),l=o.workflow.getContext(),u=s.phase,d=s.tddPhase,f=s.currentSubtask;if(u===`COMPLETE`){r.success(`Workflow complete`,{message:`All subtasks have been completed`,taskId:s.taskId});return}let p={action:c.action,description:c.description,phase:u,tddPhase:d,taskId:s.taskId,branchName:s.branchName,subtask:f?{id:f.id,title:f.title,attempts:f.attempts}:null,nextSteps:c.nextSteps,lastTestResults:l.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)}}},Pi=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:q(e.projectRoot||t?.projectRoot)},r=new $(n.json||!1);try{let e=n.projectRoot,t=await a({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)}}},Fi=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:q(t.projectRoot||n?.projectRoot)},i=new $(r.json||!1);try{let t=l.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,o=r.projectRoot,s=await a({projectPath:o});await s.workflow.hasWorkflow()&&!r.force&&(i.error(`Workflow state already exists. Use --force to overwrite or resume with "autopilot resume"`),process.exit(1));let c=s.config.getActiveTag();i.info(`Loading task ${n}...`);let{task:u}=await s.tasks.get(n);u||(i.error(`Task not found`,{taskId:n}),process.exit(1)),(!u.subtasks||u.subtasks.length===0)&&(i.error(`Task has no subtasks. Expand task first.`,{taskId:n,suggestion:`Run: taskgraph expand --id=${n}`}),process.exit(1));let d=parseInt(r.maxAttempts||`3`,10);i.info(`Starting TDD workflow...`);let f=await s.workflow.start({taskId:n,taskTitle:u.title,subtasks:u.subtasks.map(e=>({id:e.id,title:e.title,status:e.status,maxAttempts:d})),maxAttempts:d,force:r.force,tag:c});i.success(`TDD workflow started`,{taskId:f.taskId,title:u.title,phase:f.phase,tddPhase:f.tddPhase,branchName:f.branchName,subtasks:u.subtasks.length,currentSubtask:f.currentSubtask?.title})}catch(e){i.error(e.message),r.verbose&&console.error(e.stack),process.exit(1)}}},Ii=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:q(e.projectRoot||t?.projectRoot)},r=new $(n.json||!1);try{let e=n.projectRoot,t=await a({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(),o=t.workflow.getContext(),s={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:o.subtasks.map(e=>({id:e.id,title:e.title,status:e.status,attempts:e.attempts})),errors:o.errors&&o.errors.length>0?o.errors:void 0,metadata:o.metadata};n.json?r.output(s):r.success(`Workflow status`,s)}catch(e){r.error(e.message),n.verbose&&console.error(e.stack),process.exit(1)}}},Li=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 Fi),this.addCommand(new Pi),this.addCommand(new Ni),this.addCommand(new ji),this.addCommand(new Ai),this.addCommand(new Ii),this.addCommand(new Mi),this.addCommand(new ki)}static register(t){let n=new e;return t.addCommand(n),n}},Ri=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=q(e.project);await this.initializeCore(t);let n=await this.generateFiles(t,e);this.lastResult=n,this.displayResults(n,e)}catch(e){t=!0,M(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=C.resolve(e);this.tmCore=await a({projectPath:t})}}async generateFiles(e,t){if(!this.tmCore)throw Error(`TmCore not initialized`);let n=t.output?C.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(S.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(S.yellow(`No tasks found to generate files for.`),{padding:1,borderStyle:`round`,borderColor:`yellow`,title:`No tasks`,titleAlignment:`center`}));return}let n=`${S.green(`✓`)} Generated ${S.cyan(e.count)} task file(s)`;n+=`\n\n${S.dim(`Output directory:`)} ${e.directory}`,e.orphanedFilesRemoved>0&&(n+=`\n${S.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 zi={create:S.green,update:S.yellow,skip:y.muted,close:S.red};function Bi(e){let t={create:0,update:0,skip:0,close:0};for(let n of e.steps)t[n.action]++;return t}function Vi(e){let t=Bi(e);return t.create+t.update+t.close>0}function Hi(e){let t=zi[e.action](e.action.padEnd(6)),n=e.issueNumber?` -> #${e.issueNumber}`:``,r=e.reason?y.muted(` (${e.reason})`):``;return` ${t} [${e.tag}] ${e.taskId} ${e.title}${n}${r}`}function Ui(e){let t=Bi(e),n=[S.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(Hi(t));if(e.orphans.length>0){n.push(``,S.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 Wi(e){let t=e.dryRun?`would be `:``;return[S.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 Gi={apply:S.green,sync:y.muted,conflict:S.red,skip:y.muted};function Ki(e){let t={apply:0,sync:0,conflict:0,skip:0};for(let n of e.steps)t[n.action]++;return t}function qi(e){let t=Ki(e);return t.apply+t.sync>0}function Ji(e){return Ki(e).apply>0}function Yi(e){let t=Gi[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} ${y.muted(n)}`}function Xi(e){let t=Ki(e),n=[S.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(Yi(t));return t.conflict>0&&n.push(``,S.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 Zi(e){let t=e.dryRun?`would be `:``;return[S.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 Qi(e){let t=e.ghAvailable?S.green(`available and signed in`):S.red("not available (install gh and run `gh auth login`)");return[S.bold(`GitHub`),` gh CLI: ${t}`,` repo: ${e.repo??y.muted(`not detected (use --repo owner/name)`)}`,` linked: ${e.linkedTasks} task(s)`,` unlinked: ${e.unlinkedTasks} task(s)`].join(`
452
+ `)}function $i(e){return[`Unlinked task ${e.taskId} [${e.tag}] from issue #${e.issueNumber} (${e.url}).`,y.muted(`The issue was not changed. If it still carries its taskgraph marker, the next push will link it again.`)].join(`
453
+ `)}var ea=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,M(e,{skipExit:!0})}finally{await this.tmCore?.close()}n&&process.exit(1)}async initializeCore(e){if(!this.tmCore){let t=C.resolve(q(e.project));this.tmCore=await a({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):Qi(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,[Ui(r.plan),Wi(r)]);return}let r=await t.github.planPush(n);if(!Vi(r)){let i=await t.github.push({...n,dryRun:!0});this.print(e,{...i,dryRun:!1},[Ui(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(Ui(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?[Ui(i.plan)]:[],Wi(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,[Xi(r.plan),Zi(r)]);return}let r=await t.github.planPull(n);if(!qi(r)){let i=await t.github.pull({...n,dryRun:!0});this.print(e,{...i,dryRun:!1},[Xi(r),`Task statuses are already up to date.`]);return}if(Ji(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(Xi(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?[Xi(i.plan)]:[],Zi(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):$i(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}},ta=class{static commands=[{name:`list`,description:`List all tasks with filtering and status overview`,commandClass:xr,category:`task`},{name:`show`,description:`Display detailed information about a specific task`,commandClass:Sr,category:`task`},{name:`next`,description:`Find the next available task to work on`,commandClass:Cr,category:`task`},{name:`graph`,description:`Show tasks as a dependency tree`,commandClass:wr,category:`task`},{name:`start`,description:`Start working on a task with claude-code`,commandClass:Tr,category:`task`},{name:`set-status`,description:`Update the status of one or more tasks`,commandClass:Dr,category:`task`},{name:`autopilot`,description:`AI agent orchestration for TDD workflow (start, resume, next, complete, commit, status, abort)`,commandClass:Li,category:`development`},{name:`loop`,description:`Run Claude Code in a loop, one task per iteration`,commandClass:Qr,category:`development`},{name:`tags`,description:`Manage tags for task organization`,commandClass:Zr,category:`task`},{name:`generate`,description:`Generate individual task files from tasks.json`,commandClass:Ri,category:`utility`},{name:`github`,description:`Push tasks to GitHub Issues (status, push, unlink)`,commandClass:ea,category:`utility`},{name:`completion`,description:`Set up Tab completion for bash, zsh or fish`,commandClass:Oi,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 na(e){ta.registerAll(e)}function ra(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)} ${y.muted(t)}`:e.id,value:e.id,short:e.id}})}function ia(e){let{label:t,purpose:n}=H[e];return`${t} model (${n})`}function aa(e,t){return`${S.green(`✔`)} ${S.bold(ia(e))} ${S.cyan(t)}`}async function oa(e,t,n){let{model:r}=await A.createPromptModule({clearPromptOnDone:!0})([{type:`select`,name:`model`,message:ia(e),choices:t,default:n??void 0}]);return console.log(aa(e,r)),r}const sa=[`main`,`research`,`fallback`];function ca(e){if(!e)throw Error(`Project root is required but not found.`);let t=re(null,{projectRoot:e}),n=ie(e);if(g(`debug`,`Checking for config file using findConfigPath, found: ${t}`),g(`debug`,`Checking config file using isConfigFilePresent(), exists: ${n}`),!n)throw Error(`The configuration file is missing. Run "taskgraph init" to create it.`)}function la(e){return(t,...n)=>{e&&typeof e[t]==`function`&&e[t](...n)}}async function ua(e={}){let{mcpLog:t,projectRoot:n}=e,r=la(t);ca(n);try{let e=fe(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=se(n);return{success:!0,data:{activeModels:{main:t(ue(n),pe(n)),research:t(ve(n),_e(n)),fallback:r?t(r,he(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 da(e={}){let{mcpLog:t,projectRoot:n}=e,r=la(t);ca(n);try{let e=fe(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 fa(e,t,n={}){let{mcpLog:r,projectRoot:i}=n,a=la(r);if(ca(i),!sa.includes(e))return{success:!1,error:{code:`INVALID_ROLE`,message:`Invalid role: ${e}. Must be one of: ${sa.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=fe(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=oe(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),!le(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 pa(e){return ua(e)}async function ma(e,t,n){return fa(e,t,n)}function ha(){return fe()}const ga=e=>e instanceof Error&&e.name===`ExitPromptError`;async function _a(e){let t=await pa({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 va(e,t){let n=[];for(let r of e){let e=await ma(r.role,r.to,{projectRoot:t});if(!e.success)return j(`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 ya(e){let t=await _a(e),n=ha().filter(e=>e.allowed_roles),r={};try{for(let e of V)r[e]=await oa(e,ra(e,n,t[e]),t[e])}catch(e){if(!ga(e))throw e;return console.log(y.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 va(i,e);return a.length>0&&console.log(`\n${Wn(a)}`),o||(process.exitCode=1),o}export{Pn as A,et as B,nr as C,Rn as D,Hn as E,hn as F,M as H,mn as I,Xt as L,Tn as M,xn as N,kn as O,vn as P,z as R,er as S,Vn as T,qe as U,tt as V,j as W,Lr as _,na as a,Or as b,Xr as c,Z as d,Gr as f,Rr as g,zr as h,fa as i,Nn as j,Mn as k,Ur as l,Kr as m,da as n,Jr as o,Yr as p,ua as r,Hr as s,ya as t,qr as u,kr as v,Wn as w,br as x,J as y,Ct as z};