@hhsw2015/task-master-ai 0.43.20 → 0.43.22
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/{ai-services-unified-DWAPupZV.js → ai-services-unified-C8J7Phtj.js} +1 -1
- package/dist/ai-services-unified-D8U4gub7.js +1 -0
- package/dist/{commands-CV7nje1G.js → commands-Dy7jrPwm.js} +4 -4
- package/dist/config-manager-BShVbTKv.js +345 -0
- package/dist/{config-manager-BI29Nudz.js → config-manager-BXmWyJ0Q.js} +1 -1
- package/dist/{dependency-manager-mDsYzQ71.js → dependency-manager-DwuytYCA.js} +84 -80
- package/dist/mcp-server.js +2 -2
- package/dist/{profiles-CVELZrKz.js → profiles-B02F8eQH.js} +2 -2
- package/dist/research-CtyiGvG0.js +1 -0
- package/dist/response-language-C2l7xfTI.js +1 -0
- package/dist/{response-language-BmOan_mF.js → response-language-D5YyjQUa.js} +1 -1
- package/dist/{sentry-DsxpJLVM.js → sentry-Kc9f9Kgq.js} +1 -1
- package/dist/tag-management-Uth1KJyf.js +1 -0
- package/dist/{task-manager-GO2y5Uvp.js → task-manager-DWe0kRWf.js} +1 -1
- package/dist/task-master.js +1 -1
- package/dist/update-subtask-by-id-BZB0AG2e.js +1 -0
- package/dist/update-task-by-id-TVSsRUFk.js +1 -0
- package/dist/{utils-DGz7V7Kw.js → utils-B86D4uiR.js} +1 -1
- package/package.json +1 -1
- package/dist/ai-services-unified-DPFFMTq4.js +0 -1
- package/dist/config-manager-cNtpB94F.js +0 -275
- package/dist/research-BK3rN6lz.js +0 -1
- package/dist/response-language-0vTrIr_j.js +0 -1
- package/dist/tag-management-B8NsLhr8.js +0 -1
- package/dist/update-subtask-by-id-ntk5CuRW.js +0 -1
- package/dist/update-task-by-id-DP498AAF.js +0 -1
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import{a as e,i as t,l as n,n as r,t as i}from"./ai-services-unified-
|
|
1
|
+
import{a as e,i as t,l as n,n as r,t as i}from"./ai-services-unified-C8J7Phtj.js";import{$ as a,At as o,B as s,Bt as c,C as l,Ct as u,Dn as d,En as f,Jt as p,Kt as m,Lt as h,M as g,Mt as _,O as v,Ot as y,R as b,Rt as x,T as S,Tn as C,Tt as w,X as T,Xt as E,Y as D,Yt as O,Z as k,Zt as A,_ as j,_n as M,a as N,an as P,bt as ee,cn as te,ct as ne,dn as re,dt as ie,en as ae,et as F,fn as oe,ft as se,g as ce,gn as le,gt as ue,hn as de,ht as fe,i as pe,it as me,j as he,k as ge,kn as _e,kt as ve,ln as I,lt as ye,m as be,mn as xe,mt as Se,n as Ce,nn as we,o as Te,on as Ee,p as De,pn as Oe,pt as ke,q as Ae,rt as je,sn as Me,tt as Ne,un as Pe,ut as Fe,v as Ie,vn as Le,vt as L,w as Re,wn as ze,wt as Be,xn as R,y as Ve,yn as He,yt as z,z as Ue}from"./config-manager-BShVbTKv.js";import We,{resolve as Ge}from"node:path";import B from"chalk";import*as Ke from"fs";import V from"fs";import H from"path";import qe from"os";import Je from"node:fs";import{fileURLToPath as Ye}from"node:url";import Xe from"node:fs/promises";import Ze from"node:os";import{z as U}from"zod";import{spawn as Qe}from"child_process";import{fileURLToPath as $e}from"url";import{FastMCP as et}from"fastmcp";import{smoothStream as tt}from"ai";import W from"boxen";import nt from"readline";import{Command as G}from"commander";import rt from"figlet";import it from"gradient-string";import at from"terminal-link";import{marked as ot}from"marked";import{markedTerminal as st}from"marked-terminal";import ct from"turndown";import K from"cli-table3";import q from"inquirer";import J from"ora";import lt from"open";import ut,{Separator as dt}from"@inquirer/search";import ft from"process";import pt from"https";import mt from"cli-progress";import ht from"http";import gt from"fuse.js";import _t from"ajv";import vt from"ajv-formats";import yt from"gpt-tokens";import{LRUCache as bt}from"lru-cache";import"@streamparser/json";var xt=`@hhsw2015/task-master-ai`,St=`0.43.22`;function Ct(e,t,n){return(n?.color?B[n.color]:B.cyan)(at(e,t,{fallback:(e,t)=>`${e} (${t})`}))}function wt(e,t){return Ct(e,e,t)}const Tt=it([`#00b4d8`,`#0077b6`,`#03045e`]);function Et(){return process.env.TM_HIDE_BANNER===`true`}function Dt(){return process.stdout.columns||80}function Ot(e={}){if(Et())return;let{version:t}=e;try{let e=rt.textSync(`Task Master`,{font:`Standard`,horizontalLayout:`default`,verticalLayout:`default`});console.log(Tt(e))}catch{console.log(Tt(`=== Task Master ===`))}let n=Ct(`x.com/eyaltoledano`,`https://x.com/eyaltoledano`),r=B.dim(`by `)+B.cyan(n),i=t?t.replace(/^v/,``):``,a=`https://github.com/eyaltoledano/claude-task-master/releases/tag/task-master-ai%40${i}`,o=t?Ct(`v${i}`,a,{color:`gray`}):``;if(o){let e=i.length+1,t=Dt(),n=Math.max(2,t-22-e-2);console.log(r+` `.repeat(n)+o)}else console.log(r);let s=Ct(`tryhamster.com`,`https://tryhamster.com`);console.log(B.dim(`Taskmaster for teams: `)+B.magenta(s)),console.log(``)}function kt(){if(Et())return;try{let e=rt.textSync(`Task Master`,{font:`Standard`,horizontalLayout:`default`,verticalLayout:`default`});console.log(Tt(e))}catch{console.log(Tt(`=== Task Master ===`))}let e=Ct(`x.com/eyaltoledano`,`https://x.com/eyaltoledano`);console.log(B.dim(`by `)+B.cyan(e));let t=Ct(`tryhamster.com`,`https://tryhamster.com`);console.log(B.dim(`Taskmaster for teams: `)+B.magenta(t)),console.log(``)}function At(e){let{header:t,body:n,callToAction:r,footer:i,level:a=`warn`}=e,o=a===`info`?B.blue.bold:B.yellow.bold,s=a===`info`?`blue`:`yellow`,c=[o(t),...n.map(e=>B.white(e))];return r&&r.label&&r.action&&c.push(B.cyan(r.label)+`
|
|
2
2
|
`+B.blue.underline(r.action)),i&&c.push(B.gray(i)),W(c.join(`
|
|
3
3
|
|
|
4
4
|
`),{padding:1,borderColor:s,borderStyle:`round`,margin:{top:1,bottom:1}})}function jt(e,t=30,n){if(!n){let n=Math.round(e/100*t),r=t-n;return B.green(`█`).repeat(n)+B.gray(`░`).repeat(r)}let r=``,i=0;if(n.done&&n.done>0){let e=Math.round(n.done/100*t);e>0&&(r+=B.green(`█`).repeat(e),i+=e)}if(n.cancelled&&i<t){let e=Math.round(n.cancelled/100*t),a=Math.min(e,t-i);a>0&&(r+=B.gray(`█`).repeat(a),i+=a)}if(n.deferred&&i<t){let e=Math.round(n.deferred/100*t),a=Math.min(e,t-i);a>0&&(r+=B.gray(`█`).repeat(a),i+=a)}if(n[`in-progress`]&&i<t){let e=Math.round(n[`in-progress`]/100*t),a=Math.min(e,t-i);a>0&&(r+=B.blue(`█`).repeat(a),i+=a)}if(n.review&&i<t){let e=Math.round(n.review/100*t),a=Math.min(e,t-i);a>0&&(r+=B.magenta(`░`).repeat(a),i+=a)}if(n.pending&&i<t){let e=Math.round(n.pending/100*t),a=Math.min(e,t-i);a>0&&(r+=B.yellow(`░`).repeat(a),i+=a)}if(n.blocked&&i<t){let e=Math.round(n.blocked/100*t),a=Math.min(e,t-i);a>0&&(r+=B.red(`░`).repeat(a),i+=a)}return i<t&&(r+=B.yellow(`░`).repeat(t-i)),r}function Mt(e){let t={total:e.length,done:0,inProgress:0,pending:0,blocked:0,deferred:0,cancelled:0,review:0,completionPercentage:0,completedCount:0};return e.forEach(e=>{switch(e.status){case`done`:t.done++;break;case`in-progress`:t.inProgress++;break;case`pending`:t.pending++;break;case`blocked`:t.blocked++;break;case`deferred`:t.deferred++;break;case`cancelled`:t.cancelled++;break;case`review`:t.review=(t.review||0)+1;break}}),t.completedCount=e.filter(e=>He(e.status)).length,t.completionPercentage=t.total>0?Math.round(t.completedCount/t.total*100):0,t}function Nt(e){let t={total:0,done:0,inProgress:0,pending:0,blocked:0,deferred:0,cancelled:0,review:0,completionPercentage:0,completedCount:0},n=[];return e.forEach(e=>{e.subtasks&&e.subtasks.length>0&&e.subtasks.forEach(e=>{switch(t.total++,n.push(e),e.status){case`done`:t.done++;break;case`in-progress`:t.inProgress++;break;case`pending`:t.pending++;break;case`blocked`:t.blocked++;break;case`deferred`:t.deferred++;break;case`cancelled`:t.cancelled++;break;case`review`:t.review=(t.review||0)+1;break}})}),t.completedCount=n.filter(e=>He(e.status)).length,t.completionPercentage=t.total>0?Math.round(t.completedCount/t.total*100):0,t}function Pt(e){let t=new Set(e.filter(e=>He(e.status)).map(e=>e.id)),n=e.filter(e=>!He(e.status)&&(!e.dependencies||e.dependencies.length===0)).length,r=e.filter(e=>!He(e.status)&&e.dependencies&&e.dependencies.length>0&&e.dependencies.every(e=>t.has(e))).length,i=e.filter(e=>!He(e.status)&&e.dependencies&&e.dependencies.length>0&&!e.dependencies.every(e=>t.has(e))).length,a={};e.forEach(e=>{e.dependencies&&e.dependencies.length>0&&e.dependencies.forEach(e=>{let t=String(e);a[t]=(a[t]||0)+1})});let o,s=0;for(let[e,t]of Object.entries(a))t>s&&(s=t,o=parseInt(e));let c=e.reduce((e,t)=>e+(t.dependencies?t.dependencies.length:0),0),l=e.length>0?c/e.length:0;return{tasksWithNoDeps:n,tasksReadyToWork:n+r,tasksBlockedByDeps:i,mostDependedOnTaskId:o,mostDependedOnCount:s,avgDependenciesPerTask:l}}function Ft(e){let t={critical:0,high:0,medium:0,low:0};return e.forEach(e=>{let n=e.priority||`medium`;t[n]++}),t}function It(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){let n=[];t?n.push(`Completed: ${B.green(`${e.completedCount}/${e.total}`)}`):n.push(`Done: ${B.green(e.done)}`),n.push(`Cancelled: ${B.gray(e.cancelled)}`),n.push(`Deferred: ${B.gray(e.deferred)}`);let r=n.join(` `);n.length=0,n.push(`In Progress: ${B.blue(e.inProgress)}`),n.push(`Review: ${B.magenta(e.review||0)}`),n.push(`Pending: ${B.yellow(e.pending)}`),n.push(`Blocked: ${B.red(e.blocked)}`);let i=n.join(` `);return r+`
|
|
@@ -144,16 +144,19 @@ Tasks to Export
|
|
|
144
144
|
Team Invitations:`));for(let t of e)switch(t.status){case`sent`:console.log(B.green(` ${t.email}: Invitation sent`));break;case`already_member`:console.log(B.gray(` ${t.email}: Already a team member`));break;case`already_invited`:console.log(B.yellow(` ${t.email}: Already invited (pending)`));break;case`error`:case`failed`:console.log(B.red(` ${t.email}: ${t.error||`Failed to invite`}`));break}}}showInviteUrl(e){let t=e.match(/^(https?:\/\/[^/]+)\/home\/([^/]+)\/briefs\//);if(t){let[,e,n]=t,r=`${e}/home/${n}/members`;console.log(B.gray(` Invite teammates: `)+wt(r)+`
|
|
145
145
|
`)}}async setContextToBrief(e){try{if(!this.taskMasterCore)return;(await Zn(de.getInstance(),e,this.taskMasterCore)).success}catch{}}getStatusIcon(e){switch(e){case`done`:return B.green(`●`);case`in-progress`:case`in_progress`:return B.yellow(`◐`);case`blocked`:return B.red(`⊘`);default:return B.gray(`○`)}}getLastResult(){return this.lastResult}async cleanup(){}async getExportedTags(){let e=Z();if(!e)return{};let t=We.join(e,`.taskmaster`,`state.json`);try{let e=await Xe.readFile(t,`utf-8`);return JSON.parse(e).metadata?.exportedTags||{}}catch{return{}}}async sendInvitationsForBrief(e,t){if(!t.length||!this.taskMasterCore)return;let n=J(`Sending invitations...`).start();try{let e=(await this.taskMasterCore.auth.getContext())?.orgSlug;if(!e){n.fail(`Failed to send invitations: Organization context missing.`),console.error(B.red(`
|
|
146
146
|
Please ensure you have an organization selected (tm auth status).
|
|
147
|
-
`));return}let r=await this.taskMasterCore.integration.sendTeamInvitations(e,t,`member`);if(r.success&&r.invitations)n.succeed(`Invitations sent!`),this.displayInvitationResults(r.invitations);else{n.fail(`Failed to send invitations`);let e=r.error?.message||`Unknown error occurred`;console.error(B.red(`\n ${e}\n`))}}catch(e){n.fail(`Failed to send invitations`),console.error(B.red(`\n ${e.message}\n`))}}async trackExportedTag(e,t,n){let r=Z();if(!r)return;let i=We.join(r,`.taskmaster`,`state.json`);try{let r={};try{let e=await Xe.readFile(i,`utf-8`);r=JSON.parse(e)}catch{}r.metadata||={},r.metadata.exportedTags||(r.metadata.exportedTags={}),r.metadata.exportedTags[e]={briefId:t,briefUrl:n,exportedAt:new Date().toISOString()},r.lastUpdated=new Date().toISOString(),await Xe.writeFile(i,JSON.stringify(r,null,2),`utf-8`)}catch{}}static register(t,n){let r=new e(n);return t.addCommand(r),r}},hr=class e extends G{constructor(){super(`export-tag`),this.description(`Export a specific tag to Hamster (alias for: tm export --tag <tag>)`),this.argument(`<tag>`,`Name of the tag to export`),this.option(`--title <title>`,`Specify a title for the generated brief`),this.option(`--description <description>`,`Specify a description for the generated brief`),this.option(`--invite-emails <emails>`,`Invite collaborators with comma-separated emails (non-interactive)`),this.option(`-y, --yes`,`Skip interactive prompts and run non-interactively`),this.option(`--non-interactive`,`Force non-interactive mode (same as --yes)`),this.action(async(e,t)=>{await new mr().parseAsync([`node`,`export`,`--tag`,e,...t.title?[`--title`,t.title]:[],...t.description?[`--description`,t.description]:[],...t.inviteEmails?[`--invite-emails`,t.inviteEmails]:[],...t.yes?[`--yes`]:[],...t.nonInteractive?[`--non-interactive`]:[]])})}static register(t){let n=new e;return t.addCommand(n),n}},gr=class e extends G{taskMasterCore;lastResult;constructor(e){super(e||`sync`),this.description(`Sync local tasks to an existing Hamster brief`),this.addPushCommand(),this.action(async e=>{await this.executePush(e||{})})}addPushCommand(){this.command(`push`).description(`Push local tasks to an existing Hamster brief`).option(`--brief <briefOrUrl>`,`Target brief ID or Hamster brief URL (defaults to current context brief)`).option(`--tag <tag>`,`Local tag to sync (defaults to active tag)`).option(`-y, --yes`,`Skip interactive prompts and run non-interactively`).option(`--non-interactive`,`Force non-interactive mode (same as --yes)`).addHelpText(`after`,`
|
|
147
|
+
`));return}let r=await this.taskMasterCore.integration.sendTeamInvitations(e,t,`member`);if(r.success&&r.invitations)n.succeed(`Invitations sent!`),this.displayInvitationResults(r.invitations);else{n.fail(`Failed to send invitations`);let e=r.error?.message||`Unknown error occurred`;console.error(B.red(`\n ${e}\n`))}}catch(e){n.fail(`Failed to send invitations`),console.error(B.red(`\n ${e.message}\n`))}}async trackExportedTag(e,t,n){let r=Z();if(!r)return;let i=We.join(r,`.taskmaster`,`state.json`);try{let r={};try{let e=await Xe.readFile(i,`utf-8`);r=JSON.parse(e)}catch{}r.metadata||={},r.metadata.exportedTags||(r.metadata.exportedTags={}),r.metadata.exportedTags[e]={briefId:t,briefUrl:n,exportedAt:new Date().toISOString()},r.lastUpdated=new Date().toISOString(),await Xe.writeFile(i,JSON.stringify(r,null,2),`utf-8`)}catch{}}static register(t,n){let r=new e(n);return t.addCommand(r),r}},hr=class e extends G{constructor(){super(`export-tag`),this.description(`Export a specific tag to Hamster (alias for: tm export --tag <tag>)`),this.argument(`<tag>`,`Name of the tag to export`),this.option(`--title <title>`,`Specify a title for the generated brief`),this.option(`--description <description>`,`Specify a description for the generated brief`),this.option(`--invite-emails <emails>`,`Invite collaborators with comma-separated emails (non-interactive)`),this.option(`-y, --yes`,`Skip interactive prompts and run non-interactively`),this.option(`--non-interactive`,`Force non-interactive mode (same as --yes)`),this.action(async(e,t)=>{await new mr().parseAsync([`node`,`export`,`--tag`,e,...t.title?[`--title`,t.title]:[],...t.description?[`--description`,t.description]:[],...t.inviteEmails?[`--invite-emails`,t.inviteEmails]:[],...t.yes?[`--yes`]:[],...t.nonInteractive?[`--non-interactive`]:[]])})}static register(t){let n=new e;return t.addCommand(n),n}},gr=class e extends G{taskMasterCore;lastResult;constructor(e){super(e||`sync`),this.description(`Sync local tasks to an existing Hamster brief`),this.addPushCommand(),this.action(async e=>{await this.executePush(e||{})})}addPushCommand(){this.command(`push`).description(`Push local tasks to an existing Hamster brief`).option(`--brief <briefOrUrl>`,`Target brief ID or Hamster brief URL (defaults to current context brief)`).option(`--tag <tag>`,`Local tag to sync (defaults to active tag)`).option(`--mode <mode>`,`Sync mode: append (default) | replace`,`append`).option(`-y, --yes`,`Skip interactive prompts and run non-interactively`).option(`--non-interactive`,`Force non-interactive mode (same as --yes)`).addHelpText(`after`,`
|
|
148
148
|
Examples:
|
|
149
149
|
$ tm sync push --brief <brief-id-or-url>
|
|
150
150
|
$ tm sync push --brief <brief-id-or-url> --tag master_zh
|
|
151
|
+
$ tm sync push --mode replace --brief <brief-id-or-url>
|
|
151
152
|
$ tm sync push --yes --brief https://tryhamster.com/home/<org>/briefs/<id>
|
|
152
|
-
`).action(async e=>{await this.executePush(e)})}isNonInteractive(e){return!!(e?.yes||e?.nonInteractive)}async initializeServices(){this.taskMasterCore||=await I({projectPath:Z()})}async executePush(e){let t;try{let n=this.isNonInteractive(e),r=
|
|
153
|
+
`).action(async e=>{await this.executePush(e)})}isNonInteractive(e){return!!(e?.yes||e?.nonInteractive)}async initializeServices(){this.taskMasterCore||=await I({projectPath:Z()})}async executePush(e){let t;try{let n=this.isNonInteractive(e),r=this.resolveSyncMode(e.mode);if(!r){this.lastResult={success:!1,action:`cancelled`,message:`Invalid sync mode. Supported values: append, replace.`},console.error(B.red(`
|
|
154
|
+
Invalid sync mode. Supported values: append, replace.
|
|
155
|
+
`));return}let i=await pr({actionName:`sync local tasks to an existing Hamster brief`,skipConfirmation:n,nonInteractive:n});if(!i.authenticated){this.lastResult={success:!1,action:`cancelled`,message:i.error||(n?`Authentication required`:`User cancelled authentication`)},i.error&&console.error(B.red(`\n${i.error}\n`));return}await this.initializeServices();let a=await this.ensureTargetBrief(e,n);if(!a.success){this.lastResult={success:!1,action:`cancelled`,message:a.message||`No target brief selected`},a.message&&console.error(B.yellow(`\n${a.message}\n`));return}let o=this.taskMasterCore.auth.getContext();if(!o?.briefId||!o.orgId){this.lastResult={success:!1,action:`cancelled`,message:`Missing brief or organization context. Select a brief first with "tm context brief <url>".`},console.error(B.red(`
|
|
153
156
|
Missing brief or organization context. Select a brief first with "tm context brief <url>".
|
|
154
|
-
`));return}let
|
|
157
|
+
`));return}let s=e.tag||this.taskMasterCore.config.getActiveTag();if(!n){let{confirmed:e}=await q.prompt([{type:`confirm`,name:`confirmed`,message:r===`replace`?`Replace sync will delete existing tasks in brief "${o.briefName||o.briefId}" and import local tag "${s}". Continue?`:`Sync local tag "${s}" to brief "${o.briefName||o.briefId}"?`,default:!0}]);if(!e){this.lastResult={success:!1,action:`cancelled`,message:`Sync cancelled`},console.log(B.gray(`
|
|
155
158
|
Sync cancelled.
|
|
156
|
-
`));return}}t=J(`Syncing local tasks to Hamster brief...`).start();let
|
|
159
|
+
`));return}}t=J(`Syncing local tasks to Hamster brief...`).start();let c=await this.taskMasterCore.integration.exportTasks({briefId:o.briefId,orgId:o.orgId,tag:s,mode:r});if(c.success)t.succeed(`Synced ${c.taskCount} task(s)`),console.log(B.gray(` Brief: ${o.briefName||o.briefId}\n Tag: ${s}\n Mode: ${r}\n`)),this.lastResult={success:!0,action:`push`,briefId:o.briefId,tag:s,taskCount:c.taskCount,message:c.message};else{t.fail(`Sync failed`);let e=c.error?.message||`Unknown error occurred`;console.error(B.red(`\n${e}\n`)),this.lastResult={success:!1,action:`push`,briefId:o.briefId,tag:s,taskCount:0,message:e}}}catch(e){t?.isSpinning&&t.fail(`Sync failed`),X(e)}}resolveSyncMode(e){let t=(e||`append`).trim().toLowerCase();return t===`append`||t===`replace`?t:null}async ensureTargetBrief(e,t){if(!this.taskMasterCore)return{success:!1,message:`Task Master core is not initialized`};if(e.brief?.trim())return await Zn(de.getInstance(),e.brief.trim(),this.taskMasterCore),{success:!0};if(this.taskMasterCore.auth.getContext()?.briefId)return{success:!0};if(t)return{success:!1,message:`No brief selected. Provide --brief <brief-id-or-url> or run "tm context brief <brief-url>" first.`};let n=de.getInstance(),r=await Qn(n,{promptMessage:`Select an organization for sync:`,forceSelection:!1});if(!r.success||!r.orgId)return{success:!1,message:r.message||`Organization selection cancelled`};let i=await Xn(n,r.orgId);return!i.success||!i.briefId?{success:!1,message:i.message||`Brief selection cancelled`}:{success:!0}}getLastResult(){return this.lastResult}static register(t,n){let r=new e(n);return t.addCommand(r),r}};function _r(e){return[`add-dependency`,`remove-dependency`,`validate-dependencies`,`fix-dependencies`].includes(e)?{header:`Hamster Manages Dependencies`,getBody:e=>[`Hamster handles dependencies for the ${B.blue(`"${e}"`)} Brief.`,`To manage dependencies manually, log out with ${B.cyan(`tm auth logout`)} and work locally.`],footer:`Switch between local and remote workflows anytime by logging in/out.`}:e===`clear-subtasks`?{header:`Hamster Manages Subtasks`,getBody:e=>[`Hamster handles subtask management for the ${B.blue(`"${e}"`)} Brief.`,`To manage subtasks manually, log out with ${B.cyan(`tm auth logout`)} and work locally.`],footer:`Switch between local and remote workflows anytime by logging in/out.`}:e===`models`?{header:`Hamster Manages AI Models`,getBody:e=>[`Hamster configures AI models automatically for the ${B.blue(`"${e}"`)} Brief.`,`To configure models manually, log out with ${B.cyan(`tm auth logout`)} and work locally.`],footer:`Switch between local and remote workflows anytime by logging in/out.`}:{header:`Command Not Available in Hamster`,getBody:t=>[`The ${B.cyan(e)} command is managed by Hamster for the ${B.blue(`"${t}"`)} Brief.`,`To use this command, log out with ${B.cyan(`tm auth logout`)} and work locally.`],footer:`Switch between local and remote workflows anytime by logging in/out.`}}async function vr(e,t){let n=typeof t==`string`?await I({projectPath:t}):t,r=await n.auth.guardCommand(e,n.tasks.getStorageType());if(r.isBlocked){let t=_r(e),n=r.briefName||`remote brief`;return console.log(At({header:t.header,body:t.getBody(n),footer:t.footer,level:`info`})),!0}return!1}function yr(){let e=ft.env.TM_PUBLIC_VERSION;return e&&e!==`unknown`?e:(console.warn(`Could not read version from TM_PUBLIC_VERSION, using fallback`),`0.0.0`)}function br(e,t){let n=e=>{let[t,n=``]=e.split(`-`,2);return{nums:t.split(`.`).map(e=>Number.parseInt(e,10)||0),pre:n}},r=n(e),i=n(t),a=Math.max(r.nums.length,i.nums.length);for(let e=0;e<a;e++){let t=(r.nums[e]||0)-(i.nums[e]||0);if(t!==0)return t<0?-1:1}return r.pre&&!i.pre?-1:!r.pre&&i.pre?1:r.pre===i.pre?0:r.pre<i.pre?-1:1}async function xr(e){return new Promise(t=>{let n={hostname:`raw.githubusercontent.com`,path:`/eyaltoledano/claude-task-master/main/CHANGELOG.md`,method:`GET`,headers:{"User-Agent":`task-master-ai/${e}`}},r=pt.request(n,n=>{let r=``;n.on(`data`,e=>{r+=e}),n.on(`end`,()=>{try{if(n.statusCode!==200){t([]);return}t(Sr(r,e))}catch{t([])}})});r.on(`error`,()=>{t([])}),r.setTimeout(3e3,()=>{r.destroy(),t([])}),r.end()})}function Sr(e,t){try{if(!/^\d+\.\d+\.\d+(-[a-zA-Z0-9.-]+)?$/.test(t))return[];let n=RegExp(`## ${t.replace(/\./g,`\\.`)}\\s*\\n`,`i`),r=e.match(n);if(!r)return[];let i=r.index+r[0].length,a=e.indexOf(`
|
|
157
160
|
## `,i),o=(a>0?e.slice(i,a):e.slice(i)).match(/### Minor Changes\s*\n([\s\S]*?)(?=\n###|\n##|$)/i);if(!o)return[];let s=o[1],c=[],l=/^-\s+\[#\d+\][^\n]*?!\s+-\s+(.+?)$/gm,u;for(;(u=l.exec(s))!==null;){let e=u[1].trim();c.push(e)}return c}catch{return[]}}const Cr=()=>We.join(Ze.tmpdir(),`taskmaster-update-cache.json`);function wr(){try{let e=Cr();if(!Je.existsSync(e))return null;let t=JSON.parse(Je.readFileSync(e,`utf-8`));return Date.now()-t.timestamp>36e5?null:t}catch{return null}}function Tr(e,t){try{Je.writeFileSync(Cr(),JSON.stringify({timestamp:Date.now(),latestVersion:e,highlights:t},null,2))}catch{}}function Er(e){return new Promise(t=>{let n=pt.request({hostname:`registry.npmjs.org`,path:`/task-master-ai`,method:`GET`,headers:{Accept:`application/vnd.npm.install-v1+json`,"User-Agent":`task-master-ai/${e}`}},e=>{let n=``;e.on(`data`,e=>n+=e),e.on(`end`,()=>{try{if(e.statusCode!==200){t(null);return}t(JSON.parse(n)[`dist-tags`]?.latest||null)}catch{t(null)}})});n.on(`error`,()=>t(null)),n.setTimeout(3e3,()=>{n.destroy(),t(null)}),n.end()})}function Dr(e,t,n){return{currentVersion:e,latestVersion:t,needsUpdate:br(e,t)<0,highlights:n}}async function Or(e){let t=e||yr(),n=wr();if(n)return Dr(t,n.latestVersion,n.highlights);let r=await Er(t);if(!r)return Dr(t,t);let i=br(t,r)<0?await xr(r):void 0;return Tr(r,i),Dr(t,r,i)}function kr(e,t,n){let r=`${B.blue.bold(`Update Available!`)} ${B.dim(e)} → ${B.green(t)}`;if(n&&n.length>0){r+=`
|
|
158
161
|
|
|
159
162
|
`+B.bold(`What's New:`);for(let e of n)r+=`
|
|
@@ -241,25 +244,26 @@ Examples:
|
|
|
241
244
|
Note: Briefs must be created through the Hamster Studio web interface.
|
|
242
245
|
`).action(async e=>{await this.executeCreate(e)})}async initTmCore(){this.tmCore||=await I({projectPath:process.cwd()})}async executeList(e){try{await this.checkAuth()||process.exit(1);let t=await this.ensureOrgSelectedLocal();t||process.exit(1);let n=J(`Fetching briefs...`).start(),r=await this.authManager.getBriefs(t);n.stop();let i=this.authManager.getContext()?.briefId,a=r.map(e=>({name:e.document?.title||`Brief ${e.id.slice(-8)}`,isCurrent:e.id===i,taskCount:e.taskCount||0,completedTasks:0,statusBreakdown:{},created:e.createdAt,description:e.document?.description,status:e.status,briefId:e.id,updatedAt:e.updatedAt}));a.sort((e,t)=>e.isCurrent?-1:t.isCurrent?1:0),this.setLastResult({success:!0,action:`list`,briefs:a,currentBrief:i||null,message:`Found ${a.length} brief(s)`}),process.stdout.isTTY&&a.length>0?await this.promptBriefSelection(a):a.length===0?An(`No briefs found in this organization`):this.displayBriefsTable(a,e?.showMetadata)}catch(e){Y(`Failed to list briefs: ${e.message}`),this.setLastResult({success:!1,action:`list`,message:e.message}),process.exit(1)}}async ensureOrgSelectedLocal(){let e=await Qn(this.authManager);return e.success&&e.orgId||null}displayBriefsTable(e,t){let r=n(`cli-table3`),i=Math.max(process.stdout.columns||120,80),a=Math.floor(i*.95),o=[.35,.25,.2,.1,.1].map((e,t)=>Math.max(Math.floor(a*e),t===0?20:8)),s=new r({head:[B.cyan.bold(`Brief Name`),B.cyan.bold(`Status`),B.cyan.bold(`Updated`),B.cyan.bold(`Tasks`),B.cyan.bold(`Completed`)],colWidths:o,wordWrap:!0});e.forEach(e=>{let t=e.briefId?e.briefId.slice(-8):`unknown`,n=e.isCurrent?`${B.green(`●`)} ${B.green.bold(e.name)} ${B.gray(`(current - ${t})`)}`:` ${e.name} ${B.gray(`(${t})`)}`,r=e.updatedAt?new Date(e.updatedAt).toLocaleDateString(`en-US`,{month:`short`,day:`numeric`,year:`numeric`}):B.gray(`N/A`);s.push([n,bn(e.status,!0),B.gray(r),B.white(String(e.taskCount||0)),B.green(String(e.completedTasks||0))])}),console.log(s.toString())}formatBriefAsTableRow(e,t){let n=e.briefId?e.briefId.slice(-8):`unknown`,r=e.isCurrent,i=r?B.green(`●`):` `,a=r?`(current)`:`(${n})`,o=t.name-4-a.length,s=e.name;s.length>o&&(s=s.substring(0,o-1)+`…`);let c=r?B.green.bold(s):s,l=r?B.gray(`(current)`):B.gray(`(${n})`),u=2+s.length+1+a.length,d=Math.max(0,t.name-u),f=`${i} ${c} ${l}${` `.repeat(d)}`,p=bn(e.status,!0),m=(e.status||`unknown`).length+2,h=Math.max(0,t.status-m),g=`${p}${` `.repeat(h)}`,_=e.updatedAt?new Date(e.updatedAt).toLocaleDateString(`en-US`,{month:`short`,day:`numeric`,year:`numeric`}):`N/A`;return`${f} ${g} ${B.gray(_.padEnd(t.updated))} ${B.white(String(e.taskCount||0).padStart(t.tasks))} ${B.green(String(e.completedTasks||0).padStart(t.done))}`}async promptBriefSelection(e){try{if(!this.authManager.getContext()?.orgId)return;let t=Math.max(process.stdout.columns||120,80),n=Math.floor(t*.95),r={name:Math.floor(n*.42),status:Math.floor(n*.14),updated:Math.floor(n*.16),tasks:6,done:6},i=B.cyan.bold(`Brief Name`.padEnd(r.name))+B.cyan.bold(`Status`.padEnd(r.status))+B.cyan.bold(`Updated`.padEnd(r.updated))+B.cyan.bold(`Tasks`.padStart(r.tasks+2))+B.cyan.bold(`Done`.padStart(r.done+2)),a=B.gray(`─`.repeat(n)),o=[new q.Separator(i),new q.Separator(a)];e.forEach(e=>{o.push({name:this.formatBriefAsTableRow(e,r),value:e.briefId||e.name,short:e.name})}),o.push(new q.Separator(a)),o.push({name:B.dim(` (Cancel - keep current selection)`),value:null,short:`Cancelled`});let s=!1,c=(e,t)=>{t&&t.name===`escape`&&(s=!0,process.stdin.emit(`keypress`,``,{name:`c`,ctrl:!0}))};process.stdin.isTTY&&(nt.emitKeypressEvents(process.stdin),process.stdin.on(`keypress`,c));let l;try{l=await q.prompt([{type:`list`,name:`selectedBrief`,message:`Select a brief:`,choices:o,pageSize:Math.min(e.length+5,20),loop:!1}])}finally{process.stdin.isTTY&&process.stdin.removeListener(`keypress`,c)}if(s)return;if(l.selectedBrief&&l.selectedBrief!==null){let t=e.find(e=>e.briefId===l.selectedBrief||e.name===l.selectedBrief);t&&(await this.authManager.updateContext({briefId:t.briefId||void 0,briefName:t.name,briefStatus:t.status||void 0,briefUpdatedAt:t.updatedAt||void 0}),kn(`Selected brief: ${t.name}`),this.setLastResult({success:!0,action:`select`,currentBrief:t.briefId||t.name,message:`Selected brief: ${t.name}`}))}}catch(e){if(e.isTtyError)return;console.error(B.yellow(`\nNote: Could not prompt for brief selection: ${e.message}`))}}async executeSelect(e){try{if(await this.authManager.hasValidSession()||(Y(`Not authenticated. Run "tm auth login" first.`),process.exit(1)),e&&e.trim().length>0){await this.executeSelectFromUrl(e.trim());return}let t=this.authManager.getContext();t?.orgId||(On(`No organization selected. Run "tm context org" first.`),process.exit(1));let n=await Xn(this.authManager,t.orgId);this.setLastResult({success:n.success,action:`select`,currentBrief:n.briefId,message:n.message}),n.success||process.exit(1)}catch(e){On(`Failed to select brief: ${e.message}`),this.setLastResult({success:!1,action:`select`,message:e.message}),process.exit(1)}}async executeSelectFromUrl(e){try{await this.authManager.hasValidSession()||(Y(`Not authenticated. Run "tm auth login" first.`),process.exit(1)),await this.initTmCore();let t=await Zn(this.authManager,e,this.tmCore);this.setLastResult({success:t.success,action:`select`,currentBrief:t.briefId,message:t.message}),t.success||process.exit(1)}catch(e){On(`Failed to select brief: ${e.message}`),this.setLastResult({success:!1,action:`select`,message:e.message}),process.exit(1)}}async executeCreate(e){try{await this.checkAuth()||process.exit(1);let t=await Kr({tagName:e||`new-brief`,projectRoot:process.cwd(),report:(e,...t)=>{let n=t[0];e===`error`?Y(n):e===`warn`?An(n):e===`info`&&jn(n)}});if(!t)throw Error(`Failed to get brief creation URL`);this.setLastResult({success:t.success,action:`create`,message:t.message}),t.success||process.exit(1)}catch(e){On(`Failed to create brief: ${e.message}`),this.setLastResult({success:!1,action:`create`,message:e.message}),process.exit(1)}}setLastResult(e){this.lastResult=e}getLastResult(){return this.lastResult}static register(t,n){let r=new e(n);return t.addCommand(r),r}},si=class e extends G{tmCore;constructor(e){super(e||`loop`),this.description(`Run coding agent CLI in a loop, one task per iteration`).option(`-n, --iterations <number>`,`Maximum iterations`).option(`-p, --prompt <preset|path>`,`Preset name (${Pe.join(`, `)}) or path to custom prompt file`,`default`).option(`--progress-file <path>`,`Path to progress log file`,`.taskmaster/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`,`Enable sandbox mode (Docker for Claude, native sandbox for Codex)`).option(`-e, --executor <executor>`,`Execution backend (claude|codex)`).option(`--no-output`,`Exclude full executor output from iteration results`).option(`-v, --verbose`,`Show executor's work in real-time`).action(e=>this.execute(e))}async execute(e){let t=e.prompt||`default`,n=e.progressFile||`.taskmaster/progress.txt`;try{this.tmCore=await I({projectPath:We.resolve(Z(e.project))});let r=this.resolveExecutor(e.executor),i=t===`default`?await this.tmCore.tasks.getCount(`pending`,e.tag):void 0,a=this.tmCore.loop.resolveIterations({userIterations:e.iterations?parseInt(e.iterations,10):void 0,preset:t,pendingTaskCount:i});if(this.validateIterations(String(a)),Pn(this.tmCore,{tag:e.tag||`master`,storageType:this.tmCore.tasks.getStorageType()}),e.sandbox&&(r===`claude`?this.handleSandboxAuth(r):console.log(B.dim(`Using Codex native sandbox mode (workspace-write) for loop execution.`))),console.log(B.cyan(`Starting Task Master Loop...`)),console.log(B.dim(`Preset: ${t}`)),console.log(B.dim(`Max iterations: ${a}`)),console.log(B.dim(`Mode: ${e.sandbox?r===`codex`?`Codex sandbox (workspace-write)`:`Docker sandbox (Claude)`:r===`codex`?`Codex CLI`:`Claude CLI`}`)),t===`default`){let t=await this.tmCore.tasks.getNext(e.tag);t?console.log(B.white(`Next task to work on: ${B.white(t.id)} - ${t.title}`)):console.log(B.yellow(`No pending tasks found`))}console.log();let o=this.tmCore.auth.getContext()?.briefName,s={iterations:a,prompt:t,progressFile:n,tag:e.tag,executor:r,sandbox:e.sandbox,includeOutput:e.output??!0,verbose:e.verbose??!1,brief:o,callbacks:this.createOutputCallbacks()},c=await this.tmCore.loop.run(s);this.displayResult(c)}catch(e){X(e,{skipExit:!0}),process.exit(1)}}handleSandboxAuth(e){console.log(B.dim(`Checking sandbox auth...`));let t=this.tmCore.loop.checkSandboxAuth(e);if(t.error)throw Error(t.error);if(t.ready){console.log(B.green(`✓ Sandbox ready`));return}console.log(B.yellow(`Sandbox needs authentication. Starting interactive session...`)),console.log(B.dim(`Please complete auth, then Ctrl+C to continue.
|
|
243
246
|
`));let n=this.tmCore.loop.runInteractiveAuth(e);if(!n.success)throw Error(n.error||`Interactive authentication failed`);console.log(B.green(`✓ Auth complete
|
|
244
|
-
`))}resolveExecutor(e){let t=this.getConfiguredExecutor(),n=this.inferExecutorFromConfig(),r=e??process.env.TASKMASTER_EXECUTOR??t??n??`claude`,i=r.toLowerCase();if(i===`claude`||i===`codex`)return i;throw Error(`Invalid executor "${r}". Supported values: claude, codex.`)}getConfiguredExecutor(){let e=this.tmCore.config.getConfig().custom?.executor;return typeof e==`string`?e:void 0}inferExecutorFromConfig(){let e=this.tmCore.config.getConfig();if(this.isCodexProvider(e.aiProvider))return`codex`;let t=this.asObject(e.models);if(this.isCodexModelConfig(t?.main)||this.isNonEmptyObject(e.codexCli))return`codex`}isCodexModelConfig(e){if(typeof e==`string`)return this.isCodexModelId(e);let t=this.asObject(e);return t?this.isCodexProvider(t.provider)||this.isCodexModelId(t.modelId):!1}isCodexProvider(e){if(typeof e!=`string`)return!1;let t=e.trim().toLowerCase();return t===`codex`||t===`codex-cli`||t===`codex-lb`}isCodexModelId(e){return typeof e==`string`&&e.toLowerCase().includes(`codex`)}asObject(e){if(typeof e==`object`&&e)return e}isNonEmptyObject(e){let t=this.asObject(e);return!!(t&&Object.keys(t).length>0)}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(B.cyan(`━━━ Iteration ${e} of ${t} ━━━`))},onText:e=>{console.log(e)},onToolUse:e=>{console.log(B.dim(` → ${e}`))},onError:(e,t)=>{t===`warning`?console.error(B.yellow(`[Loop Warning] ${e}`)):console.error(B.red(`[Loop Error] ${e}`))},onStderr:(e,t)=>{process.stderr.write(B.dim(`[Iteration ${e}] `)+t)},onOutput:e=>{console.log(e)},onIterationEnd:e=>{let t=e.status===`success`?B.green:e.status===`error`?B.red:B.yellow;console.log(t(` Iteration ${e.iteration} completed: ${e.status}`))}}}displayResult(e){console.log(),console.log(B.bold(`Loop Complete`)),console.log(B.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(B.red(`Error: ${e.errorMessage}`))}formatStatus(e){return{all_complete:B.green(`All tasks complete`),max_iterations:B.yellow(`Max iterations reached`),blocked:B.red(`Blocked`),error:B.red(`Error`)}[e]}static register(t,n){let r=new e(n);return t.addCommand(r),r}},ci=class{constructor(
|
|
245
|
-
`)[0],subtask:{id:i.currentSubtask.id,title:i.currentSubtask.title},progress:p.progress,nextAction:m?`All subtasks complete. Run: autopilot status`:`Start next subtask with RED phase`})}catch(e){r.error(e.message),n.verbose&&console.error(e.stack),process.exit(1)}}},di=class extends G{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:Z(e.projectRoot||t?.projectRoot)},r=new ci(n.json||!1);try{let e=n.projectRoot,t=await I({projectPath:e});await t.workflow.hasWorkflow()||(r.error(`No active workflow`,{suggestion:`Start a workflow with: autopilot start <taskId>`}),process.exit(1)),await t.workflow.resume();let i=t.workflow.getStatus(),a=i.tddPhase,o=i.currentSubtask;if(a||(r.error(`Not in a TDD phase`,{phase:i.phase}),process.exit(1)),a===`RED`||a===`GREEN`){n.results||(r.error(`Test results required for RED/GREEN phase`,{usage:`--results '{"total":10,"passed":9,"failed":1,"skipped":0}'`}),process.exit(1));let e;try{let t=JSON.parse(n.results);e={total:t.total||0,passed:t.passed||0,failed:t.failed||0,skipped:t.skipped||0,phase:a}}catch(e){r.error(`Invalid test results JSON`,{error:e.message}),process.exit(1)}a===`RED`&&e.failed===0&&(r.error(`RED phase validation failed`,{reason:`At least one test must be failing`,actual:{passed:e.passed,failed:e.failed}}),process.exit(1)),a===`GREEN`&&e.failed!==0&&(r.error(`GREEN phase validation failed`,{reason:`All tests must pass`,actual:{passed:e.passed,failed:e.failed}}),process.exit(1));let i=await t.workflow.completePhase(e);a===`RED`?r.success(`RED phase completed`,{nextPhase:i.tddPhase||`GREEN`,testResults:e,subtask:o?.title}):r.success(`GREEN phase completed`,{nextPhase:i.tddPhase||`COMMIT`,testResults:e,subtask:o?.title,suggestion:`Run: autopilot commit`})}else a===`COMMIT`&&(r.error(`Use "autopilot commit" to complete COMMIT phase`),process.exit(1))}catch(e){r.error(e.message),n.verbose&&console.error(e.stack),process.exit(1)}}},fi=class extends G{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 ci(e.json||t?.json||!1);try{let i=Z(e.projectRoot||t?.projectRoot);n={...n,projectRoot:i};let a=await I({projectPath:i});await a.workflow.hasWorkflow()||(r.error(`No active workflow`,{suggestion:`Start a workflow with: autopilot start <taskId>`}),process.exit(1)),await a.workflow.resume();let o=a.workflow.getStatus();o.phase!==`FINALIZE`&&(r.error(`Cannot finalize: workflow is in ${o.phase} phase`,{suggestion:`Complete all subtasks first`}),process.exit(1)),r.info(`Validating working tree and finalizing workflow...`);let s=await a.workflow.finalize();r.success(`Workflow completed`,{taskId:s.taskId,phase:s.phase,branchName:s.branchName,progress:s.progress})}catch(e){r.error(e.message),n.verbose&&console.error(e.stack),process.exit(1)}}},pi=class extends G{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 ci(e.json||t?.json||!1);try{let i=Z(e.projectRoot||t?.projectRoot);n={...n,projectRoot:i};let a=await I({projectPath:i});await a.workflow.hasWorkflow()||(r.error(`No active workflow`,{suggestion:`Start a workflow with: autopilot start <taskId>`}),process.exit(1)),await a.workflow.resume();let o=a.workflow.getStatus(),s=a.workflow.getNextAction(),c=a.workflow.getContext(),l=this.resolveExecutor(a,n.executor),u=o.phase,d=o.tddPhase,f=o.currentSubtask;if(u===`COMPLETE`){r.success(`Workflow complete`,{message:`All subtasks have been completed`,taskId:o.taskId});return}let p=await this.buildExecutionHint(a,o.taskId,o.phase,o.tddPhase,o.currentSubtask?.id,l),m=p?.command?`${s.nextSteps}\n\nLaunch coding agent:\n${p.command}`:s.nextSteps,h={action:s.action,description:s.description,phase:u,tddPhase:d,taskId:o.taskId,branchName:o.branchName,subtask:f?{id:f.id,title:f.title,attempts:f.attempts}:null,nextSteps:m,lastTestResults:c.lastTestResults,execution:p??{executor:l}};n.json?r.output(h):r.success(`Next action`,h)}catch(e){r.error(e.message),n.verbose&&console.error(e.stack),process.exit(1)}}async buildExecutionHint(e,t,n,r,i,a){if(n!==`SUBTASK_LOOP`||!i)return null;if(r!==`RED`&&r!==`GREEN`)return{executor:a};let o=this.composeWorkItemId(t,i),s=await e.tasks.start(o,{dryRun:!0,force:!0,updateStatus:!1,executor:a});return{executor:a,workItemId:o,command:s.command?this.buildShellCommand(s.command.executable,s.command.args):void 0}}composeWorkItemId(e,t){let n=String(t);return n.includes(`.`)?n:`${e}.${n}`}buildShellCommand(e,t){return[e,...t.map(e=>this.shellEscapeArg(e))].join(` `)}shellEscapeArg(e){return e?`'${e.replace(/'/g,`'"'"'`)}'`:`''`}resolveExecutor(e,t){let n=this.getConfiguredExecutor(e),r=this.inferExecutorFromConfig(e),i=t??process.env.TASKMASTER_EXECUTOR??n??r??`claude`,a=i.toLowerCase();if(a===`claude`||a===`codex`)return a;throw Error(`Invalid executor "${i}". Supported values: claude, codex.`)}getConfiguredExecutor(e){let t=e.config.getConfig().custom?.executor;return typeof t==`string`?t:void 0}inferExecutorFromConfig(e){let t=e.config.getConfig();if(this.isCodexProvider(t.aiProvider))return`codex`;let n=this.asObject(t.models);if(this.isCodexModelConfig(n?.main)||this.isNonEmptyObject(t.codexCli))return`codex`}isCodexModelConfig(e){if(typeof e==`string`)return this.isCodexModelId(e);let t=this.asObject(e);return t?this.isCodexProvider(t.provider)||this.isCodexModelId(t.modelId):!1}isCodexProvider(e){if(typeof e!=`string`)return!1;let t=e.trim().toLowerCase();return t===`codex`||t===`codex-cli`||t===`codex-lb`}isCodexModelId(e){return typeof e==`string`&&e.toLowerCase().includes(`codex`)}asObject(e){if(typeof e==`object`&&e)return e}isNonEmptyObject(e){let t=this.asObject(e);return!!(t&&Object.keys(t).length>0)}},mi=class extends G{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:Z(e.projectRoot||t?.projectRoot)},r=new ci(n.json||!1);try{let e=n.projectRoot,t=await I({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)}}},hi=class extends G{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:Z(t.projectRoot||n?.projectRoot)},i=new ci(r.json||!1);try{let t=ae.safeParse(e);t.success||(i.error(`Invalid task ID format`,{taskId:e,error:t.error.issues[0]?.message}),process.exit(1));let n=t.data,a=r.projectRoot,o=await I({projectPath:a});await o.workflow.hasWorkflow()&&!r.force&&(i.error(`Workflow state already exists. Use --force to overwrite or resume with "autopilot resume"`),process.exit(1));let s=o.config.getActiveTag(),c=o.auth.getContext()?.orgSlug;i.info(`Loading task ${n}...`);let{task:l}=await o.tasks.get(n);l||(i.error(`Task not found`,{taskId:n}),process.exit(1)),(!l.subtasks||l.subtasks.length===0)&&(i.error(`Task has no subtasks. Expand task first.`,{taskId:n,suggestion:`Run: task-master expand --id=${n}`}),process.exit(1));let u=parseInt(r.maxAttempts||`3`,10);i.info(`Starting TDD workflow...`);let d=await o.workflow.start({taskId:n,taskTitle:l.title,subtasks:l.subtasks.map(e=>({id:e.id,title:e.title,status:e.status,maxAttempts:u})),maxAttempts:u,force:r.force,tag:s,orgSlug:c});i.success(`TDD workflow started`,{taskId:d.taskId,title:l.title,phase:d.phase,tddPhase:d.tddPhase,branchName:d.branchName,subtasks:l.subtasks.length,currentSubtask:d.currentSubtask?.title})}catch(e){i.error(e.message),r.verbose&&console.error(e.stack),process.exit(1)}}},gi=class extends G{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:Z(e.projectRoot||t?.projectRoot)},r=new ci(n.json||!1);try{let e=n.projectRoot,t=await I({projectPath:e});if(!await t.workflow.hasWorkflow()){n.json?r.output({active:!1,message:`No active workflow`}):(r.info(`No active workflow`),console.log(`Start a workflow with: autopilot start <taskId>`));return}await t.workflow.resume();let i=t.workflow.getStatus(),a=t.workflow.getContext(),o={taskId:i.taskId,phase:i.phase,tddPhase:i.tddPhase,branchName:i.branchName,progress:i.progress,currentSubtask:i.currentSubtask?{id:i.currentSubtask.id,title:i.currentSubtask.title,attempts:i.currentSubtask.attempts,maxAttempts:i.currentSubtask.maxAttempts}:null,subtasks:a.subtasks.map(e=>({id:e.id,title:e.title,status:e.status,attempts:e.attempts})),errors:a.errors&&a.errors.length>0?a.errors:void 0,metadata:a.metadata};n.json?r.output(o):r.success(`Workflow status`,o)}catch(e){r.error(e.message),n.verbose&&console.error(e.stack),process.exit(1)}}},_i=class e extends G{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(`-e, --executor <executor>`,`Execution backend (claude|codex)`).option(`-p, --project-root <path>`,`Project root directory (auto-detected if not specified)`),this.registerSubcommands()}registerSubcommands(){this.addCommand(new hi),this.addCommand(new mi),this.addCommand(new pi),this.addCommand(new di),this.addCommand(new ui),this.addCommand(new gi),this.addCommand(new fi),this.addCommand(new li)}static register(t){let n=new e;return t.addCommand(n),n}},vi=class e extends G{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 .taskmaster/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=Z(e.project);await this.initializeCore(t);let n=await this.generateFiles(t,e);this.lastResult=n,this.displayResults(n,e)}catch(e){t=!0,X(e,{skipExit:!0})}finally{await this.cleanup()}t&&process.exit(1)}validateOptions(e){if(e.format&&![`text`,`json`].includes(e.format))throw Error(`Invalid format: ${e.format}. Valid formats are: text, json`)}async initializeCore(e){this.tmCore||=await I({projectPath:We.resolve(e)})}async generateFiles(e,t){if(!this.tmCore)throw Error(`TmCore not initialized`);let n=t.output?We.resolve(e,t.output):void 0;return this.tmCore.tasks.generateTaskFiles({tag:t.tag,outputDir:n})}displayResults(e,t){switch(t.format||`text`){case`json`:this.displayJson(e);break;case`text`:default:this.displayText(e,t);break}}displayJson(e){console.log(JSON.stringify(e,null,2))}displayText(e,t){if(this.tmCore){let e=this.tmCore.tasks.getStorageType(),n=t.tag||this.tmCore.config.getActiveTag();Pn(this.tmCore,{tag:n,storageType:e})}if(!e.success){console.log(W(B.red(`Error: ${e.error||`Unknown error`}`),{padding:1,borderStyle:`round`,borderColor:`red`,title:`❌ GENERATION FAILED`,titleAlignment:`center`}));return}if(e.count===0){console.log(W(B.yellow(`No tasks found to generate files for.`),{padding:1,borderStyle:`round`,borderColor:`yellow`,title:`⚠️ NO TASKS`,titleAlignment:`center`}));return}let n=`${B.green(`✓`)} Generated ${B.cyan(e.count)} task file(s)`;n+=`\n\n${B.dim(`Output directory:`)} ${e.directory}`,e.orphanedFilesRemoved>0&&(n+=`\n${B.dim(`Orphaned files removed:`)} ${e.orphanedFilesRemoved}`),console.log(W(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}},yi=class e extends G{authCommand;constructor(e){super(e||`login`),this.authCommand=new er,this.description(`Login to Hamster (alias for "auth login")`),this.argument(`[token]`,`Authentication token (optional, for SSH/remote environments)`),this.option(`-y, --yes`,`Skip interactive prompts`),this.addHelpText(`after`,`
|
|
247
|
+
`))}resolveExecutor(e){let t=this.getConfiguredExecutor(),n=this.inferExecutorFromConfig(),r=e??process.env.TASKMASTER_EXECUTOR??t??n??`claude`,i=r.toLowerCase();if(i===`claude`||i===`codex`)return i;throw Error(`Invalid executor "${r}". Supported values: claude, codex.`)}getConfiguredExecutor(){let e=this.tmCore.config.getConfig().custom?.executor;return typeof e==`string`?e:void 0}inferExecutorFromConfig(){let e=this.tmCore.config.getConfig();if(this.isCodexProvider(e.aiProvider))return`codex`;let t=this.asObject(e.models);if(this.isCodexModelConfig(t?.main)||this.isNonEmptyObject(e.codexCli))return`codex`}isCodexModelConfig(e){if(typeof e==`string`)return this.isCodexModelId(e);let t=this.asObject(e);return t?this.isCodexProvider(t.provider)||this.isCodexModelId(t.modelId):!1}isCodexProvider(e){if(typeof e!=`string`)return!1;let t=e.trim().toLowerCase();return t===`codex`||t===`codex-cli`||t===`codex-lb`}isCodexModelId(e){return typeof e==`string`&&e.toLowerCase().includes(`codex`)}asObject(e){if(typeof e==`object`&&e)return e}isNonEmptyObject(e){let t=this.asObject(e);return!!(t&&Object.keys(t).length>0)}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(B.cyan(`━━━ Iteration ${e} of ${t} ━━━`))},onText:e=>{console.log(e)},onToolUse:e=>{console.log(B.dim(` → ${e}`))},onError:(e,t)=>{t===`warning`?console.error(B.yellow(`[Loop Warning] ${e}`)):console.error(B.red(`[Loop Error] ${e}`))},onStderr:(e,t)=>{process.stderr.write(B.dim(`[Iteration ${e}] `)+t)},onOutput:e=>{console.log(e)},onIterationEnd:e=>{let t=e.status===`success`?B.green:e.status===`error`?B.red:B.yellow;console.log(t(` Iteration ${e.iteration} completed: ${e.status}`))}}}displayResult(e){console.log(),console.log(B.bold(`Loop Complete`)),console.log(B.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(B.red(`Error: ${e.errorMessage}`))}formatStatus(e){return{all_complete:B.green(`All tasks complete`),max_iterations:B.yellow(`Max iterations reached`),blocked:B.red(`Blocked`),error:B.red(`Error`)}[e]}static register(t,n){let r=new e(n);return t.addCommand(r),r}},ci=class extends G{constructor(){super(`init`),this.description(`Initialize AGENTS.md + Skill assets for codex longrun mode`).option(`-p, --project <path>`,`Project root directory`).option(`--skill-path <path>`,`Custom SKILL.md path relative to project root`).option(`--agents-path <path>`,`Custom AGENTS.md path relative to project root`).option(`--agents-mode <mode>`,`How to handle existing AGENTS without hook: append|skip|fail`,`append`).option(`--mode <mode>`,`Execution mode: lite|full|auto`,`full`).option(`--session-dir <path>`,`Custom session directory relative to project root`).option(`--json`,`Output JSON`).action(async e=>{await this.execute(e)})}async execute(e){try{let t=await I({projectPath:Z(e.project)}),n=await t.skillRun.initAssets({skillPath:e.skillPath,agentsPath:e.agentsPath,agentsMode:e.agentsMode,mode:e.mode,sessionDir:e.sessionDir});if(await t.close(),e.json){console.log(JSON.stringify(n,null,2));return}console.log(B.green(`Codex longrun assets initialized.`)),console.log(B.gray(` AGENTS: ${n.paths.agentsPath}`)),console.log(B.gray(` SKILL : ${n.paths.skillPath}`)),console.log(B.gray(` Session: ${n.paths.sessionDir}`)),n.created.length>0&&console.log(B.green(` Created: ${n.created.join(`, `)}`)),n.updated.length>0&&console.log(B.yellow(` Updated: ${n.updated.join(`, `)}`))}catch(e){X(e,{skipExit:!0}),process.exit(1)}}},li=class extends G{constructor(){super(`run`),this.alias(`start`),this.description(`Run long-horizon codex execution with Taskmaster task scheduling`).option(`-p, --project <path>`,`Project root directory`).option(`-t, --tag <tag>`,`Tag context for tasks`).option(`--max-retries <n>`,`Retries before marking a task blocked`,`3`).option(`--skill-path <path>`,`Custom SKILL.md path relative to project root`).option(`--agents-path <path>`,`Custom AGENTS.md path relative to project root`).option(`--agents-mode <mode>`,`How to handle existing AGENTS without hook: append|skip|fail`,`append`).option(`--mode <mode>`,`Execution mode: lite|full|auto`,`full`).option(`--session-dir <path>`,`Custom session directory relative to project root`).option(`-e, --executor <cmd>`,`Executor command`,`codex`).option(`-m, --model <model>`,`Model for codex exec`).option(`--reasoning-effort <level>`,`low|medium|high|xhigh`).option(`--exec-idle-timeout-ms <ms>`,`Per-task idle timeout in milliseconds (0 to disable)`).option(`--exec-hard-timeout-ms <ms>`,`Per-task hard timeout in milliseconds (0 to disable)`).option(`--exec-timeout-ms <ms>`,`[Deprecated] Alias of --exec-hard-timeout-ms`).option(`--no-terminate-on-result`,`Do not terminate executor after TM_RESULT is detected`).option(`--no-full-auto`,`Disable --full-auto for codex exec`).option(`--no-skip-git-repo-check`,`Disable --skip-git-repo-check for codex exec`).option(`--max-tasks <n>`,`Stop after N execution attempts`).option(`--no-continue-on-failure`,`Stop when one task fails`).option(`--json`,`Output JSON summary`).action(async e=>{await this.execute(e)})}async execute(e){try{let t=await I({projectPath:Z(e.project)});console.log(B.cyan(`Starting Codex longrun execution...`));let n=await t.skillRun.run({tag:e.tag,maxRetries:Number.parseInt(e.maxRetries||`3`,10),skillPath:e.skillPath,agentsPath:e.agentsPath,agentsMode:e.agentsMode,mode:e.mode,sessionDir:e.sessionDir,executor:e.executor,model:e.model,reasoningEffort:e.reasoningEffort,execIdleTimeoutMs:this.parseOptionalInteger(e.execIdleTimeoutMs),execHardTimeoutMs:this.parseOptionalInteger(e.execHardTimeoutMs),execTimeoutMs:this.parseOptionalInteger(e.execTimeoutMs),terminateOnResult:e.terminateOnResult,fullAuto:e.fullAuto,skipGitRepoCheck:e.skipGitRepoCheck,maxTasks:e.maxTasks?Number.parseInt(e.maxTasks,10):void 0,continueOnFailure:e.continueOnFailure,callbacks:{onTaskStart:(e,t)=>{console.log(B.white(`\n[Task ${e.id}] ${e.title} (attempt ${t})`))},onTaskEnd:e=>{console.log(B.gray(`[${e.status}] ${e.taskId} exit=${e.exitCode} duration=${e.durationMs}ms log=${e.logFile}`))}}});if(await t.close(),e.json){console.log(JSON.stringify(n,null,2));return}console.log(`
|
|
248
|
+
`+B.bold(`Longrun Summary`)),console.log(B.gray(` Final status: ${n.finalStatus}`)),console.log(B.gray(` Completed: ${n.completedTaskIds.length}`)),console.log(B.gray(` Blocked: ${n.blockedTaskIds.length}`)),console.log(B.gray(` Total runs: ${n.totalRuns}`))}catch(e){X(e,{skipExit:!0}),process.exit(1)}}parseOptionalInteger(e){if(typeof e!=`string`||e.trim().length===0)return;let t=Number.parseInt(e,10);return Number.isNaN(t)?void 0:t}},ui=class e extends G{constructor(){super(`codex`),this.description(`Codex native extension commands (skill init/run)`),this.alias(`skill-run`),this.addCommand(new ci),this.addCommand(new li)}static register(t){let n=new e;return t.addCommand(n),n}},di=class{constructor(e){this.useJson=e}output(e){this.useJson?console.log(JSON.stringify(e,null,2)):this.outputText(e)}outputText(e){for(let[t,n]of Object.entries(e))typeof n==`object`&&n?(console.log(B.cyan(`${t}:`)),this.outputObject(n,` `)):console.log(B.white(`${t}: ${n}`))}outputObject(e,t){for(let[n,r]of Object.entries(e))typeof r==`object`&&r?(console.log(B.cyan(`${t}${n}:`)),this.outputObject(r,t+` `)):console.log(B.gray(`${t}${n}: ${r}`))}error(e,t){if(this.useJson)console.error(JSON.stringify({error:e,...t},null,2));else if(console.error(B.red(`Error: ${e}`)),t)for(let[e,n]of Object.entries(t))console.error(B.gray(` ${e}: ${n}`))}success(e,t){this.useJson?console.log(JSON.stringify({success:!0,message:e,...t},null,2)):(console.log(B.green(`✓ ${e}`)),t&&this.output(t))}warning(e){this.useJson?console.warn(JSON.stringify({warning:e},null,2)):console.warn(B.yellow(`⚠️ ${e}`))}info(e){this.useJson||console.log(B.blue(`ℹ ${e}`))}},fi=class extends G{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 di(e.json||t?.json||!1);try{let i=Z(e.projectRoot||t?.projectRoot);n={...n,projectRoot:i};let a=await I({projectPath:i});if(!await a.workflow.hasWorkflow()){r.warning(`No active workflow to abort`);return}await a.workflow.resume();let o=a.workflow.getStatus();if(!n.force&&!n.json){let{confirmed:e}=await q.prompt([{type:`confirm`,name:`confirmed`,message:`This will abort the workflow for task ${o.taskId}. Progress: ${o.progress?.completed||0}/${o.progress?.total||0} subtasks completed. Continue?`,default:!1}]);if(!e){r.info(`Abort cancelled`);return}}await a.workflow.abort(),r.success(`Workflow aborted`,{taskId:o.taskId,branchName:o.branchName,progress:o.progress,lastSubtask:o.currentSubtask?{id:o.currentSubtask.id,title:o.currentSubtask.title}:null,note:`Branch and commits remain. Clean up manually if needed.`})}catch(e){r.error(e.message),n.verbose&&console.error(e.stack),process.exit(1)}}},pi=class extends G{constructor(){super(`commit`),this.description(`Create a commit for the completed GREEN phase`).action(async e=>{await this.execute(e)})}async execute(e){let t=this.parent?.opts(),n={...t,...e,projectRoot:Z(e.projectRoot||t?.projectRoot)},r=new di(n.json||!1);try{let e=n.projectRoot,t=await I({projectPath:e});await t.workflow.hasWorkflow()||(r.error(`No active workflow`,{suggestion:`Start a workflow with: autopilot start <taskId>`}),process.exit(1)),await t.workflow.resume();let i=t.workflow.getStatus(),a=t.workflow.getContext();i.tddPhase!==`COMMIT`&&(r.error(`Not in COMMIT phase`,{currentPhase:i.tddPhase||i.phase,suggestion:`Complete RED and GREEN phases first`}),process.exit(1)),i.currentSubtask||(r.error(`No current subtask`),process.exit(1));let o=new Oe(e);await o.ensureGitRepository(),await o.hasStagedChanges()||(r.info(`No staged changes, staging all changes...`),await o.stageFiles([`.`]));let s=await o.getStatus(),c=[...s.staged,...s.modified],l=new oe,u=a.lastTestResults,d=l.generateMessage({type:`feat`,description:i.currentSubtask.title,changedFiles:c,taskId:i.taskId,phase:i.tddPhase,tag:a.metadata.tag||void 0,testsPassing:u?.passed,testsFailing:u?.failed,coveragePercent:void 0});await o.createCommit(d,{metadata:{taskId:i.taskId,subtaskId:i.currentSubtask.id,phase:`COMMIT`,tddCycle:`complete`}});let f=await o.getLastCommit(),p=await t.workflow.commit(),m=p.phase===`COMPLETE`;r.success(`Commit created`,{commitHash:f.hash.substring(0,7),message:d.split(`
|
|
249
|
+
`)[0],subtask:{id:i.currentSubtask.id,title:i.currentSubtask.title},progress:p.progress,nextAction:m?`All subtasks complete. Run: autopilot status`:`Start next subtask with RED phase`})}catch(e){r.error(e.message),n.verbose&&console.error(e.stack),process.exit(1)}}},mi=class extends G{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:Z(e.projectRoot||t?.projectRoot)},r=new di(n.json||!1);try{let e=n.projectRoot,t=await I({projectPath:e});await t.workflow.hasWorkflow()||(r.error(`No active workflow`,{suggestion:`Start a workflow with: autopilot start <taskId>`}),process.exit(1)),await t.workflow.resume();let i=t.workflow.getStatus(),a=i.tddPhase,o=i.currentSubtask;if(a||(r.error(`Not in a TDD phase`,{phase:i.phase}),process.exit(1)),a===`RED`||a===`GREEN`){n.results||(r.error(`Test results required for RED/GREEN phase`,{usage:`--results '{"total":10,"passed":9,"failed":1,"skipped":0}'`}),process.exit(1));let e;try{let t=JSON.parse(n.results);e={total:t.total||0,passed:t.passed||0,failed:t.failed||0,skipped:t.skipped||0,phase:a}}catch(e){r.error(`Invalid test results JSON`,{error:e.message}),process.exit(1)}a===`RED`&&e.failed===0&&(r.error(`RED phase validation failed`,{reason:`At least one test must be failing`,actual:{passed:e.passed,failed:e.failed}}),process.exit(1)),a===`GREEN`&&e.failed!==0&&(r.error(`GREEN phase validation failed`,{reason:`All tests must pass`,actual:{passed:e.passed,failed:e.failed}}),process.exit(1));let i=await t.workflow.completePhase(e);a===`RED`?r.success(`RED phase completed`,{nextPhase:i.tddPhase||`GREEN`,testResults:e,subtask:o?.title}):r.success(`GREEN phase completed`,{nextPhase:i.tddPhase||`COMMIT`,testResults:e,subtask:o?.title,suggestion:`Run: autopilot commit`})}else a===`COMMIT`&&(r.error(`Use "autopilot commit" to complete COMMIT phase`),process.exit(1))}catch(e){r.error(e.message),n.verbose&&console.error(e.stack),process.exit(1)}}},hi=class extends G{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 di(e.json||t?.json||!1);try{let i=Z(e.projectRoot||t?.projectRoot);n={...n,projectRoot:i};let a=await I({projectPath:i});await a.workflow.hasWorkflow()||(r.error(`No active workflow`,{suggestion:`Start a workflow with: autopilot start <taskId>`}),process.exit(1)),await a.workflow.resume();let o=a.workflow.getStatus();o.phase!==`FINALIZE`&&(r.error(`Cannot finalize: workflow is in ${o.phase} phase`,{suggestion:`Complete all subtasks first`}),process.exit(1)),r.info(`Validating working tree and finalizing workflow...`);let s=await a.workflow.finalize();r.success(`Workflow completed`,{taskId:s.taskId,phase:s.phase,branchName:s.branchName,progress:s.progress})}catch(e){r.error(e.message),n.verbose&&console.error(e.stack),process.exit(1)}}},gi=class extends G{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 di(e.json||t?.json||!1);try{let i=Z(e.projectRoot||t?.projectRoot);n={...n,projectRoot:i};let a=await I({projectPath:i});await a.workflow.hasWorkflow()||(r.error(`No active workflow`,{suggestion:`Start a workflow with: autopilot start <taskId>`}),process.exit(1)),await a.workflow.resume();let o=a.workflow.getStatus(),s=a.workflow.getNextAction(),c=a.workflow.getContext(),l=this.resolveExecutor(a,n.executor),u=o.phase,d=o.tddPhase,f=o.currentSubtask;if(u===`COMPLETE`){r.success(`Workflow complete`,{message:`All subtasks have been completed`,taskId:o.taskId});return}let p=await this.buildExecutionHint(a,o.taskId,o.phase,o.tddPhase,o.currentSubtask?.id,l),m=p?.command?`${s.nextSteps}\n\nLaunch coding agent:\n${p.command}`:s.nextSteps,h={action:s.action,description:s.description,phase:u,tddPhase:d,taskId:o.taskId,branchName:o.branchName,subtask:f?{id:f.id,title:f.title,attempts:f.attempts}:null,nextSteps:m,lastTestResults:c.lastTestResults,execution:p??{executor:l}};n.json?r.output(h):r.success(`Next action`,h)}catch(e){r.error(e.message),n.verbose&&console.error(e.stack),process.exit(1)}}async buildExecutionHint(e,t,n,r,i,a){if(n!==`SUBTASK_LOOP`||!i)return null;if(r!==`RED`&&r!==`GREEN`)return{executor:a};let o=this.composeWorkItemId(t,i),s=await e.tasks.start(o,{dryRun:!0,force:!0,updateStatus:!1,executor:a});return{executor:a,workItemId:o,command:s.command?this.buildShellCommand(s.command.executable,s.command.args):void 0}}composeWorkItemId(e,t){let n=String(t);return n.includes(`.`)?n:`${e}.${n}`}buildShellCommand(e,t){return[e,...t.map(e=>this.shellEscapeArg(e))].join(` `)}shellEscapeArg(e){return e?`'${e.replace(/'/g,`'"'"'`)}'`:`''`}resolveExecutor(e,t){let n=this.getConfiguredExecutor(e),r=this.inferExecutorFromConfig(e),i=t??process.env.TASKMASTER_EXECUTOR??n??r??`claude`,a=i.toLowerCase();if(a===`claude`||a===`codex`)return a;throw Error(`Invalid executor "${i}". Supported values: claude, codex.`)}getConfiguredExecutor(e){let t=e.config.getConfig().custom?.executor;return typeof t==`string`?t:void 0}inferExecutorFromConfig(e){let t=e.config.getConfig();if(this.isCodexProvider(t.aiProvider))return`codex`;let n=this.asObject(t.models);if(this.isCodexModelConfig(n?.main)||this.isNonEmptyObject(t.codexCli))return`codex`}isCodexModelConfig(e){if(typeof e==`string`)return this.isCodexModelId(e);let t=this.asObject(e);return t?this.isCodexProvider(t.provider)||this.isCodexModelId(t.modelId):!1}isCodexProvider(e){if(typeof e!=`string`)return!1;let t=e.trim().toLowerCase();return t===`codex`||t===`codex-cli`||t===`codex-lb`}isCodexModelId(e){return typeof e==`string`&&e.toLowerCase().includes(`codex`)}asObject(e){if(typeof e==`object`&&e)return e}isNonEmptyObject(e){let t=this.asObject(e);return!!(t&&Object.keys(t).length>0)}},_i=class extends G{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:Z(e.projectRoot||t?.projectRoot)},r=new di(n.json||!1);try{let e=n.projectRoot,t=await I({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)}}},vi=class extends G{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:Z(t.projectRoot||n?.projectRoot)},i=new di(r.json||!1);try{let t=ae.safeParse(e);t.success||(i.error(`Invalid task ID format`,{taskId:e,error:t.error.issues[0]?.message}),process.exit(1));let n=t.data,a=r.projectRoot,o=await I({projectPath:a});await o.workflow.hasWorkflow()&&!r.force&&(i.error(`Workflow state already exists. Use --force to overwrite or resume with "autopilot resume"`),process.exit(1));let s=o.config.getActiveTag(),c=o.auth.getContext()?.orgSlug;i.info(`Loading task ${n}...`);let{task:l}=await o.tasks.get(n);l||(i.error(`Task not found`,{taskId:n}),process.exit(1)),(!l.subtasks||l.subtasks.length===0)&&(i.error(`Task has no subtasks. Expand task first.`,{taskId:n,suggestion:`Run: task-master expand --id=${n}`}),process.exit(1));let u=parseInt(r.maxAttempts||`3`,10);i.info(`Starting TDD workflow...`);let d=await o.workflow.start({taskId:n,taskTitle:l.title,subtasks:l.subtasks.map(e=>({id:e.id,title:e.title,status:e.status,maxAttempts:u})),maxAttempts:u,force:r.force,tag:s,orgSlug:c});i.success(`TDD workflow started`,{taskId:d.taskId,title:l.title,phase:d.phase,tddPhase:d.tddPhase,branchName:d.branchName,subtasks:l.subtasks.length,currentSubtask:d.currentSubtask?.title})}catch(e){i.error(e.message),r.verbose&&console.error(e.stack),process.exit(1)}}},yi=class extends G{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:Z(e.projectRoot||t?.projectRoot)},r=new di(n.json||!1);try{let e=n.projectRoot,t=await I({projectPath:e});if(!await t.workflow.hasWorkflow()){n.json?r.output({active:!1,message:`No active workflow`}):(r.info(`No active workflow`),console.log(`Start a workflow with: autopilot start <taskId>`));return}await t.workflow.resume();let i=t.workflow.getStatus(),a=t.workflow.getContext(),o={taskId:i.taskId,phase:i.phase,tddPhase:i.tddPhase,branchName:i.branchName,progress:i.progress,currentSubtask:i.currentSubtask?{id:i.currentSubtask.id,title:i.currentSubtask.title,attempts:i.currentSubtask.attempts,maxAttempts:i.currentSubtask.maxAttempts}:null,subtasks:a.subtasks.map(e=>({id:e.id,title:e.title,status:e.status,attempts:e.attempts})),errors:a.errors&&a.errors.length>0?a.errors:void 0,metadata:a.metadata};n.json?r.output(o):r.success(`Workflow status`,o)}catch(e){r.error(e.message),n.verbose&&console.error(e.stack),process.exit(1)}}},bi=class e extends G{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(`-e, --executor <executor>`,`Execution backend (claude|codex)`).option(`-p, --project-root <path>`,`Project root directory (auto-detected if not specified)`),this.registerSubcommands()}registerSubcommands(){this.addCommand(new vi),this.addCommand(new _i),this.addCommand(new gi),this.addCommand(new mi),this.addCommand(new pi),this.addCommand(new yi),this.addCommand(new hi),this.addCommand(new fi)}static register(t){let n=new e;return t.addCommand(n),n}},xi=class e extends G{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 .taskmaster/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=Z(e.project);await this.initializeCore(t);let n=await this.generateFiles(t,e);this.lastResult=n,this.displayResults(n,e)}catch(e){t=!0,X(e,{skipExit:!0})}finally{await this.cleanup()}t&&process.exit(1)}validateOptions(e){if(e.format&&![`text`,`json`].includes(e.format))throw Error(`Invalid format: ${e.format}. Valid formats are: text, json`)}async initializeCore(e){this.tmCore||=await I({projectPath:We.resolve(e)})}async generateFiles(e,t){if(!this.tmCore)throw Error(`TmCore not initialized`);let n=t.output?We.resolve(e,t.output):void 0;return this.tmCore.tasks.generateTaskFiles({tag:t.tag,outputDir:n})}displayResults(e,t){switch(t.format||`text`){case`json`:this.displayJson(e);break;case`text`:default:this.displayText(e,t);break}}displayJson(e){console.log(JSON.stringify(e,null,2))}displayText(e,t){if(this.tmCore){let e=this.tmCore.tasks.getStorageType(),n=t.tag||this.tmCore.config.getActiveTag();Pn(this.tmCore,{tag:n,storageType:e})}if(!e.success){console.log(W(B.red(`Error: ${e.error||`Unknown error`}`),{padding:1,borderStyle:`round`,borderColor:`red`,title:`❌ GENERATION FAILED`,titleAlignment:`center`}));return}if(e.count===0){console.log(W(B.yellow(`No tasks found to generate files for.`),{padding:1,borderStyle:`round`,borderColor:`yellow`,title:`⚠️ NO TASKS`,titleAlignment:`center`}));return}let n=`${B.green(`✓`)} Generated ${B.cyan(e.count)} task file(s)`;n+=`\n\n${B.dim(`Output directory:`)} ${e.directory}`,e.orphanedFilesRemoved>0&&(n+=`\n${B.dim(`Orphaned files removed:`)} ${e.orphanedFilesRemoved}`),console.log(W(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}},Si=class e extends G{authCommand;constructor(e){super(e||`login`),this.authCommand=new er,this.description(`Login to Hamster (alias for "auth login")`),this.argument(`[token]`,`Authentication token (optional, for SSH/remote environments)`),this.option(`-y, --yes`,`Skip interactive prompts`),this.addHelpText(`after`,`
|
|
246
250
|
Examples:
|
|
247
251
|
$ tm login # Browser-based OAuth flow (interactive)
|
|
248
252
|
$ tm login <token> # Token-based authentication
|
|
249
253
|
$ tm login <token> -y # Non-interactive token auth (for scripts)
|
|
250
|
-
`),this.action(async(e,t)=>{await this.authCommand.executeLogin(e,t?.yes,!0)})}static register(t){let n=new e;return t.addCommand(n),n}},
|
|
254
|
+
`),this.action(async(e,t)=>{await this.authCommand.executeLogin(e,t?.yes,!0)})}static register(t){let n=new e;return t.addCommand(n),n}},Ci=class e extends G{authCommand;constructor(e){super(e||`logout`),this.authCommand=new er,this.description(`Logout from Hamster (alias for "auth logout")`),this.addHelpText(`after`,`
|
|
251
255
|
Examples:
|
|
252
256
|
$ tm logout # Clear credentials and logout
|
|
253
|
-
`),this.action(async()=>{await this.authCommand.executeLogout()})}static register(t){let n=new e;return t.addCommand(n),n}},xi=class{static commands=[{name:`list`,description:`List all tasks with filtering and status overview`,commandClass:In,category:`task`},{name:`show`,description:`Display detailed information about a specific task`,commandClass:Ln,category:`task`},{name:`next`,description:`Find the next available task to work on`,commandClass:Rn,category:`task`},{name:`start`,description:`Start working on a task with a coding agent CLI`,commandClass:tr,category:`task`},{name:`set-status`,description:`Update the status of one or more tasks`,commandClass:rr,category:`task`},{name:`export`,description:`Export tasks to Hamster by creating a new brief`,commandClass:mr,category:`task`},{name:`export-tag`,description:`Export a specific tag to Hamster`,commandClass:hr,category:`task`},{name:`sync`,description:`Sync local tasks to an existing Hamster brief`,commandClass:gr,category:`task`},{name:`autopilot`,description:`AI agent orchestration for TDD workflow (start, resume, next, complete, commit, status, abort)`,commandClass:_i,category:`development`},{name:`loop`,description:`Run coding agent CLI in a loop, one task per iteration`,commandClass:si,category:`development`},{name:`auth`,description:`Manage authentication with tryhamster.com`,commandClass:er,category:`auth`},{name:`login`,description:`Login to Hamster (alias for "auth login")`,commandClass:yi,category:`auth`},{name:`logout`,description:`Logout from Hamster (alias for "auth logout")`,commandClass:bi,category:`auth`},{name:`context`,description:`Manage workspace context (organization/brief)`,commandClass:$n,category:`auth`},{name:`tags`,description:`Manage tags for task organization`,commandClass:ai,category:`task`},{name:`briefs`,description:`Manage briefs (Hamster only)`,commandClass:oi,category:`task`},{name:`generate`,description:`Generate individual task files from tasks.json`,commandClass:vi,category:`utility`}];static registerAll(e){for(let t of this.commands)this.registerCommand(e,t)}static registerByCategory(e,t){let n=this.commands.filter(e=>e.category===t);for(let t of n)this.registerCommand(e,t)}static registerByName(e,t){let n=this.commands.find(e=>e.name===t);if(n)this.registerCommand(e,n);else throw Error(`Command '${t}' not found in registry`)}static registerCommand(e,t){let n=t.commandClass;if(n.registerOn)n.registerOn(e);else if(n.register)n.register(e);else{let t=new n;e.addCommand(t)}}static getCommandNames(){return this.commands.map(e=>e.name)}static getCommandsByCategory(e){return this.commands.filter(t=>t.category===e)}static addCommand(e){if(this.commands.some(t=>t.name===e.name))throw Error(`Command '${e.name}' already exists in registry`);this.commands.push(e)}static removeCommand(e){let t=this.commands.findIndex(t=>t.name===e);return t>=0?(this.commands.splice(t,1),!0):!1}static getCommand(e){return this.commands.find(t=>t.name===e)}static hasCommand(e){return this.commands.some(t=>t.name===e)}static getFormattedCommandList(){let e={task:`Task Management`,auth:`Authentication & Context`,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 Si(e){xi.registerAll(e)}async function Ci(){return new Promise(e=>{let t=pt.request({hostname:`openrouter.ai`,path:`/api/v1/models`,method:`GET`,headers:{Accept:`application/json`}},t=>{let n=``;t.on(`data`,e=>{n+=e}),t.on(`end`,()=>{if(t.statusCode===200)try{e({success:!0,data:JSON.parse(n).data||[]})}catch{e({success:!1,error:`Failed to parse OpenRouter response`})}else e({success:!1,error:`OpenRouter API returned status ${t.statusCode}`})})});t.on(`error`,t=>{e({success:!1,error:`Failed to fetch OpenRouter models: ${t.message}`})}),t.end()})}async function wi(e=`http://localhost:11434/api`){return new Promise(t=>{try{let n=new URL(e),r=n.protocol===`https:`,i=n.port||(r?443:80),a=n.pathname.endsWith(`/`)?n.pathname.slice(0,-1):n.pathname,o={hostname:n.hostname,port:parseInt(String(i),10),path:`${a}/tags`,method:`GET`,headers:{Accept:`application/json`}},s=(r?pt:ht).request(o,e=>{let n=``;e.on(`data`,e=>{n+=e}),e.on(`end`,()=>{if(e.statusCode===200)try{t({success:!0,data:JSON.parse(n).models||[]})}catch{t({success:!1,error:`Failed to parse Ollama response`})}else t({success:!1,error:`Ollama API returned status ${e.statusCode}`})})});s.on(`error`,e=>{t({success:!1,error:`Failed to connect to Ollama: ${e.message}`})}),s.end()}catch(e){t({success:!1,error:`Invalid Ollama base URL: ${e instanceof Error?e.message:`Unknown error`}`})}})}async function Ti(e){let t=await Ci();return!t.success||!t.data?!1:t.data.some(t=>t.id===e)}async function Ei(e,t){let n=await wi(t);return!n.success||!n.data?!1:n.data.some(t=>t.model===e)}const Di=`The configuration file is missing. Run "task-master init" to create it.`;function Oi(){return new Promise(e=>{let t=pt.request({hostname:`openrouter.ai`,path:`/api/v1/models`,method:`GET`,headers:{Accept:`application/json`}},t=>{let n=``;t.on(`data`,e=>{n+=e}),t.on(`end`,()=>{if(t.statusCode===200)try{e(JSON.parse(n).data||[])}catch(t){console.error(`Error parsing OpenRouter response:`,t),e(null)}else console.error(`OpenRouter API request failed with status code: ${t.statusCode}`),e(null)})});t.on(`error`,t=>{console.error(`Error fetching OpenRouter models:`,t),e(null)}),t.end()})}function ki(e=`http://localhost:11434/api`){return new Promise(t=>{try{let n=new URL(e),r=n.protocol===`https:`,i=n.port||(r?443:80),a=n.pathname.endsWith(`/`)?n.pathname.slice(0,-1):n.pathname,o={hostname:n.hostname,port:parseInt(i,10),path:`${a}/tags`,method:`GET`,headers:{Accept:`application/json`}},s=(r?pt:ht).request(o,e=>{let n=``;e.on(`data`,e=>{n+=e}),e.on(`end`,()=>{if(e.statusCode===200)try{t(JSON.parse(n).models||[])}catch(e){console.error(`Error parsing Ollama response:`,e),t(null)}else console.error(`Ollama API request failed with status code: ${e.statusCode}`),t(null)})});s.on(`error`,e=>{console.error(`Error fetching Ollama models:`,e),t(null)}),s.end()}catch(e){console.error(`Error parsing Ollama base URL:`,e),t(null)}})}async function Ai(e={}){let{mcpLog:t,projectRoot:n,session:r}=e,i=(e,...n)=>{t&&typeof t[e]==`function`&&t[e](...n)};if(!n)throw Error(`Project root is required but not found.`);let a=T(null,{projectRoot:n}),o=s(n);if(z(`debug`,`Checking for config file using findConfigPath, found: ${a}`),z(`debug`,`Checking config file using isConfigFilePresent(), exists: ${o}`),!o)throw Error(Di);try{let e=Re(n),t=l(n),i=Te(`main`,n),a=g(n),o=he(n),s=Te(`research`,n),c=Ve(n),u=Ie(n),d=Te(`fallback`,n),f=Ue(e,r,n),p=S(e,n),m=Ue(a,r,n),h=S(a,n),_=c?Ue(c,r,n):!0,v=c?S(c,n):!0,y=pe(n),b=y.find(e=>e.id===t),x=y.find(e=>e.id===o),C=u?y.find(e=>e.id===u):null;return{success:!0,data:{activeModels:{main:{provider:e,modelId:t,baseURL:i,sweScore:b?.swe_score||null,cost:b?.cost_per_1m_tokens||null,keyStatus:{cli:f,mcp:p}},research:{provider:a,modelId:o,baseURL:s,sweScore:x?.swe_score||null,cost:x?.cost_per_1m_tokens||null,keyStatus:{cli:m,mcp:h}},fallback:c?{provider:c,modelId:u,baseURL:d,sweScore:C?.swe_score||null,cost:C?.cost_per_1m_tokens||null,keyStatus:{cli:_,mcp:v}}:null},message:`Successfully retrieved current model configuration`}}}catch(e){return i(`error`,`Error getting model configuration: ${e.message}`),{success:!1,error:{code:`CONFIG_ERROR`,message:e.message}}}}async function ji(e={}){let{mcpLog:t,projectRoot:n}=e,r=(e,...n)=>{t&&typeof t[e]==`function`&&t[e](...n)};if(!n)throw Error(`Project root is required but not found.`);let i=T(null,{projectRoot:n}),a=s(n);if(z(`debug`,`Checking for config file using findConfigPath, found: ${i}`),z(`debug`,`Checking config file using isConfigFilePresent(), exists: ${a}`),!a)throw Error(Di);try{let e=pe(n);if(!e||e.length===0)return{success:!0,data:{models:[],message:`No available models found`}};[l(n),he(n),Ie(n)].filter(Boolean);let t=e.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:t,message:`Successfully retrieved ${t.length} available models`}}}catch(e){return r(`error`,`Error getting available models: ${e.message}`),{success:!1,error:{code:`MODELS_LIST_ERROR`,message:e.message}}}}async function Mi(e,t,n={}){let{mcpLog:r,projectRoot:i,providerHint:a,baseURL:o}=n,c=o,l=(e,...t)=>{r&&typeof r[e]==`function`&&r[e](...t)};if(!i)throw Error(`Project root is required but not found.`);let u=T(null,{projectRoot:i}),d=s(i);if(z(`debug`,`Checking for config file using findConfigPath, found: ${u}`),z(`debug`,`Checking config file using isConfigFilePresent(), exists: ${d}`),!d)throw Error(Di);if(![`main`,`research`,`fallback`].includes(e))return{success:!1,error:{code:`INVALID_ROLE`,message:`Invalid role: ${e}. Must be one of: main, research, fallback.`}};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=pe(i),r=De(i),s=null,u=null,d;if(d=a?n.find(e=>e.id===t&&e.provider===a):n.find(e=>e.id===t),a)if(d&&d.provider===a)s=a,l(`info`,`Model ${t} found internally with provider ${s}.`);else if(a===R.OPENROUTER){l(`info`,`Checking OpenRouter for ${t} (as hinted)...`);let e=await Oi();if(e&&e.some(e=>e.id===t))s=R.OPENROUTER,u=t.endsWith(`:free`)?`Warning: OpenRouter free model '${t}' selected. Free models have significant limitations including lower context windows, reduced rate limits, and may not support advanced features like tool_use. Consider using the paid version '${t.replace(`:free`,``)}' for full functionality.`:`Warning: Custom OpenRouter model '${t}' set. This model is not officially validated by Taskmaster and may not function as expected.`,l(`warn`,u);else throw Error(`Model ID "${t}" not found in the live OpenRouter model list. Please verify the ID and ensure it's available on OpenRouter.`)}else if(a===R.OLLAMA){l(`info`,`Checking Ollama for ${t} (as hinted)...`);let n;e===`main`?n=Re(i):e===`research`?n=g(i):e===`fallback`&&(n=Ve(i));let r=n===R.OLLAMA?Te(e,i):null,a=o||r||`http://localhost:11434/api`,d=await ki(a);if(d===null)throw Error(`Unable to connect to Ollama server at ${a}. Please ensure Ollama is running and try again.`);if(d.some(e=>e.model===t))s=R.OLLAMA,u=`Warning: Custom Ollama model '${t}' set. Ensure your Ollama server is running and has pulled this model. Taskmaster cannot guarantee compatibility.`,l(`warn`,u),c=a;else{let e=`${a}/tags`;throw Error(`Model ID "${t}" not found in the Ollama instance. Please verify the model is pulled and available. You can check available models with: curl ${e}`)}}else if(a===R.BEDROCK)s=R.BEDROCK,u=`Warning: Custom Bedrock model '${t}' set. Please ensure the model ID is valid and accessible in your AWS account.`,l(`warn`,u);else if(a===R.CLAUDE_CODE){s=R.CLAUDE_CODE;let e=n.filter(e=>e.provider===`claude-code`).find(e=>e.id===t);e?(d=e,l(`info`,`Setting Claude Code model '${t}'.`)):(u=`Warning: Claude Code model '${t}' not found in supported models. Setting without validation.`,l(`warn`,u))}else if(a===R.AZURE){s=R.AZURE;let n;e===`main`?n=Re(i):e===`research`?n=g(i):e===`fallback`&&(n=Ve(i));let r=n===R.AZURE?Te(e,i):null,a=o||r;if(!a)throw Error(`Base URL is required for Azure providers. Please provide a baseURL or set global.azureBaseURL in config.`);u=`Warning: Custom Azure model '${t}' set with base URL '${a}'. Please ensure the model deployment is valid and accessible in your Azure account.`,l(`warn`,u),c=a}else if(a===R.VERTEX)s=R.VERTEX,u=`Warning: Custom Vertex AI model '${t}' set. Please ensure the model is valid and accessible in your Google Cloud project.`,l(`warn`,u);else if(a===R.GEMINI_CLI){s=R.GEMINI_CLI;let e=n.filter(e=>e.provider===`gemini-cli`).find(e=>e.id===t);e?(d=e,l(`info`,`Setting Gemini CLI model '${t}'.`)):(u=`Warning: Gemini CLI model '${t}' not found in supported models. Setting without validation.`,l(`warn`,u))}else if(a===R.CODEX_CLI){s=R.CODEX_CLI;let e=n.filter(e=>e.provider===`codex-cli`).find(e=>e.id===t);e?(d=e,l(`info`,`Setting Codex CLI model '${t}'.`)):(u=`Warning: Codex CLI model '${t}' not found in supported models. Setting without validation.`,l(`warn`,u))}else if(a===R.LMSTUDIO){s=R.LMSTUDIO;let n;e===`main`?n=Re(i):e===`research`?n=g(i):e===`fallback`&&(n=Ve(i));let r=n===R.LMSTUDIO?Te(e,i):null,a=o||r||`http://localhost:1234/v1`;u=`Warning: Custom LM Studio model '${t}' set with base URL '${a}'. Please ensure LM Studio server is running and has loaded this model. Taskmaster cannot guarantee compatibility.`,l(`warn`,u),c=a}else if(a===R.OPENAI_COMPATIBLE){s=R.OPENAI_COMPATIBLE;let n;e===`main`?n=Re(i):e===`research`?n=g(i):e===`fallback`&&(n=Ve(i));let r=n===R.OPENAI_COMPATIBLE?Te(e,i):null,a=o||r;if(!a)throw Error(`Base URL is required for OpenAI-compatible providers. Please provide a baseURL.`);u=`Warning: Custom OpenAI-compatible model '${t}' set with base URL '${a}'. Taskmaster cannot guarantee compatibility. Ensure your API endpoint follows the OpenAI API specification.`,l(`warn`,u),c=a}else throw Error(`Invalid provider hint received: ${a}`);else if(d)s=d.provider,l(`info`,`Model ${t} found internally with provider ${s}.`);else return{success:!1,error:{code:`MODEL_NOT_FOUND_NO_HINT`,message:`Model ID "${t}" not found in Taskmaster's supported models. If this is a custom model, please specify the provider using --openrouter, --ollama, --bedrock, --azure, --vertex, --lmstudio, --openai-compatible, --gemini-cli, or --codex-cli.`}};if(!s)return{success:!1,error:{code:`PROVIDER_UNDETERMINED`,message:`Could not determine the provider for model ID "${t}".`}};if(r.models[e]={...r.models[e],provider:s,modelId:t},c&&(s===R.OPENAI_COMPATIBLE||s===R.LMSTUDIO||s===R.OLLAMA||s===R.AZURE)?r.models[e].baseURL=c:delete r.models[e].baseURL,d&&d.max_tokens&&(r.models[e].maxTokens=d.max_tokens),!Ae(r,i))return{success:!1,error:{code:`CONFIG_WRITE_ERROR`,message:`Error writing updated configuration to configuration file`}};let f=`Successfully set ${e} model to ${t} (Provider: ${s})`;return l(`info`,f),{success:!0,data:{role:e,provider:s,modelId:t,message:f,warning:u}}}catch(t){return l(`error`,`Error setting ${e} model: ${t.message}`),{success:!1,error:{code:`SET_MODEL_ERROR`,message:t.message}}}}async function Ni(e={}){let{mcpLog:t,projectRoot:n,session:r}=e,i=(e,...n)=>{t&&typeof t[e]==`function`&&t[e](...n)};try{let e=Ce().filter(e=>e.toLowerCase()!==`ollama`).map(e=>({provider:e,cli:Ue(e,r,n),mcp:S(e,n)}));return i(`info`,`Successfully generated API key status report.`),{success:!0,data:{report:e,message:`API key status report generated.`}}}catch(e){return i(`error`,`Error generating API key status report: ${e.message}`),{success:!1,error:{code:`API_KEY_STATUS_ERROR`,message:e.message}}}}async function Pi(e){return Ai(e)}async function Fi(e,t,n){return Mi(e,t,n)}function Ii(e){return De(e)}function Li(e,t){return Ae(e,t)}function Ri(){return pe()}function zi(e){return N(e)??``}const Bi={OPENROUTER:{id:`__CUSTOM_OPENROUTER__`,name:`* Custom OpenRouter model`,provider:R.OPENROUTER,promptMessage:e=>`Enter the custom OpenRouter Model ID for the ${e} role:`,validate:async e=>{let t=await Ti(e);return t||console.error(B.red(`Error: Model ID "${e}" not found in the live OpenRouter model list. Please check the ID.`)),t}},OLLAMA:{id:`__CUSTOM_OLLAMA__`,name:`* Custom Ollama model`,provider:R.OLLAMA,requiresBaseURL:!0,defaultBaseURL:`http://localhost:11434/api`,promptMessage:e=>`Enter the custom Ollama Model ID for the ${e} role:`,validate:async(e,t)=>{let n=t||`http://localhost:11434/api`,r=await Ei(e,n);return r||(console.error(B.red(`Error: Model ID "${e}" not found in the Ollama instance. Please verify the model is pulled and available.`)),console.log(B.yellow(`You can check available models with: curl ${n}/tags`))),r}},BEDROCK:{id:`__CUSTOM_BEDROCK__`,name:`* Custom Bedrock model`,provider:R.BEDROCK,promptMessage:e=>`Enter the custom Bedrock Model ID for the ${e} role (e.g., anthropic.claude-3-sonnet-20240229-v1:0):`,checkEnvVars:()=>((!process.env.AWS_ACCESS_KEY_ID||!process.env.AWS_SECRET_ACCESS_KEY)&&console.warn(B.yellow(`Warning: AWS_ACCESS_KEY_ID and/or AWS_SECRET_ACCESS_KEY environment variables are missing. Will fallback to system configuration (ex: aws config files or ec2 instance profiles).`)),!0)},AZURE:{id:`__CUSTOM_AZURE__`,name:`* Custom Azure OpenAI model`,provider:R.AZURE,requiresBaseURL:!0,promptMessage:e=>`Enter the Azure deployment name for the ${e} role (e.g., gpt-4o):`,checkEnvVars:()=>process.env.AZURE_OPENAI_API_KEY?!0:(console.error(B.red(`Error: AZURE_OPENAI_API_KEY environment variable is missing. Please set it before using Azure models.`)),!1)},VERTEX:{id:`__CUSTOM_VERTEX__`,name:`* Custom Vertex model`,provider:R.VERTEX,promptMessage:e=>`Enter the custom Vertex AI Model ID for the ${e} role (e.g., gemini-1.5-pro-002):`,checkEnvVars:()=>!process.env.GOOGLE_API_KEY&&!process.env.GOOGLE_APPLICATION_CREDENTIALS?(console.error(B.red(`Error: Either GOOGLE_API_KEY or GOOGLE_APPLICATION_CREDENTIALS environment variable is required. Please set one before using custom Vertex models.`)),!1):!0},LMSTUDIO:{id:`__CUSTOM_LMSTUDIO__`,name:`* Custom LMStudio model`,provider:R.LMSTUDIO,requiresBaseURL:!0,defaultBaseURL:`http://localhost:1234/v1`,promptMessage:e=>`Enter the custom LM Studio Model ID for the ${e} role:`,checkEnvVars:()=>(console.log(B.blue(`Note: LM Studio runs locally. Make sure the LM Studio server is running.`)),!0)},OPENAI_COMPATIBLE:{id:`__CUSTOM_OPENAI_COMPATIBLE__`,name:`* Custom OpenAI-compatible model`,provider:R.OPENAI_COMPATIBLE,promptMessage:e=>`Enter the custom OpenAI-compatible Model ID for the ${e} role:`,requiresBaseURL:!0,checkEnvVars:()=>(console.log(B.blue(`Note: This will configure a generic OpenAI-compatible provider. Make sure your API endpoint is accessible.`)),!0)}};async function Vi(e,t,n=null,r){let i=Object.entries(Bi).find(([t,n])=>n.id===e);if(!i)return console.error(B.red(`Unknown custom provider: ${e}`)),{modelId:null,provider:null,success:!1};let a=i[1];if(a.checkEnvVars&&!a.checkEnvVars())return{modelId:null,provider:null,success:!1};let o=null;if(a.requiresBaseURL){let e;e=n?.provider===a.provider&&n?.baseURL?n.baseURL:a.provider===R.AZURE&&r?zi(r)||``:a.defaultBaseURL||``,o=(await q.prompt([{type:`input`,name:`baseURL`,message:`Enter the base URL for the ${t} role:`,default:e,validate:e=>{if(!e||e.trim()===``)return`Base URL is required for ${a.provider} providers`;try{return new URL(e),!0}catch{return`Please enter a valid URL`}}}])).baseURL}let{customId:s}=await q.prompt([{type:`input`,name:`customId`,message:a.promptMessage(t)}]);if(!s)return console.log(B.yellow(`No custom ID entered. Skipping role.`)),{modelId:null,provider:null,success:!0};if(a.validate){if(!await a.validate(s,o||void 0))return{modelId:null,provider:null,success:!1}}else console.log(B.blue(`Custom ${a.provider} model "${s}" will be used. No validation performed.`));return{modelId:s,provider:a.provider,baseURL:o,success:!0}}function Hi(){return Object.values(Bi).map(e=>({name:e.name,value:e.id,short:e.name}))}function Ui(e,t,n=!1){let r=t[e],i=Ri().filter(e=>!!e.provider).reduce((e,t)=>(e[t.provider]||(e[t.provider]=[]),e[t.provider].push(t),e),{}),a=[],o={name:`⏹ Cancel Model Setup`,value:`__CANCEL__`,short:`Cancel`},s=r?.modelId&&r?.provider?{name:`✔ No change to current ${e} model (${r.provider}/${r.modelId})`,value:`__NO_CHANGE__`,short:`No change`}:null;s&&a.push(s),a.push(o);let c=Object.entries(i).flatMap(([t,n])=>n.filter(t=>t.allowed_roles&&t.allowed_roles.includes(e)).map(e=>{let n=e.name||e.id;return{name:`${t} / ${n} ${e.cost_per_1m_tokens?B.gray(`($${e.cost_per_1m_tokens.input.toFixed(2)} input | $${e.cost_per_1m_tokens.output.toFixed(2)} output)`):``}`,value:{id:e.id,provider:t},short:`${t}/${n}`}})).filter(e=>e!==null),l=-1;r?.modelId&&r?.provider&&(l=c.findIndex(e=>typeof e.value==`object`&&e.value!==null&&`id`in e.value&&e.value.id===r.modelId&&e.value.provider===r.provider));let u=Hi(),d=a.length,f,p;if(n){f=[...a,new dt(`
|
|
257
|
+
`),this.action(async()=>{await this.authCommand.executeLogout()})}static register(t){let n=new e;return t.addCommand(n),n}},wi=class{static commands=[{name:`list`,description:`List all tasks with filtering and status overview`,commandClass:In,category:`task`},{name:`show`,description:`Display detailed information about a specific task`,commandClass:Ln,category:`task`},{name:`next`,description:`Find the next available task to work on`,commandClass:Rn,category:`task`},{name:`start`,description:`Start working on a task with a coding agent CLI`,commandClass:tr,category:`task`},{name:`set-status`,description:`Update the status of one or more tasks`,commandClass:rr,category:`task`},{name:`export`,description:`Export tasks to Hamster by creating a new brief`,commandClass:mr,category:`task`},{name:`export-tag`,description:`Export a specific tag to Hamster`,commandClass:hr,category:`task`},{name:`sync`,description:`Sync local tasks to an existing Hamster brief`,commandClass:gr,category:`task`},{name:`autopilot`,description:`AI agent orchestration for TDD workflow (start, resume, next, complete, commit, status, abort)`,commandClass:bi,category:`development`},{name:`loop`,description:`Run coding agent CLI in a loop, one task per iteration`,commandClass:si,category:`development`},{name:`codex`,description:`Codex native extension commands (skill init/run)`,commandClass:ui,category:`development`},{name:`auth`,description:`Manage authentication with tryhamster.com`,commandClass:er,category:`auth`},{name:`login`,description:`Login to Hamster (alias for "auth login")`,commandClass:Si,category:`auth`},{name:`logout`,description:`Logout from Hamster (alias for "auth logout")`,commandClass:Ci,category:`auth`},{name:`context`,description:`Manage workspace context (organization/brief)`,commandClass:$n,category:`auth`},{name:`tags`,description:`Manage tags for task organization`,commandClass:ai,category:`task`},{name:`briefs`,description:`Manage briefs (Hamster only)`,commandClass:oi,category:`task`},{name:`generate`,description:`Generate individual task files from tasks.json`,commandClass:xi,category:`utility`}];static registerAll(e){for(let t of this.commands)this.registerCommand(e,t)}static registerByCategory(e,t){let n=this.commands.filter(e=>e.category===t);for(let t of n)this.registerCommand(e,t)}static registerByName(e,t){let n=this.commands.find(e=>e.name===t);if(n)this.registerCommand(e,n);else throw Error(`Command '${t}' not found in registry`)}static registerCommand(e,t){let n=t.commandClass;if(n.registerOn)n.registerOn(e);else if(n.register)n.register(e);else{let t=new n;e.addCommand(t)}}static getCommandNames(){return this.commands.map(e=>e.name)}static getCommandsByCategory(e){return this.commands.filter(t=>t.category===e)}static addCommand(e){if(this.commands.some(t=>t.name===e.name))throw Error(`Command '${e.name}' already exists in registry`);this.commands.push(e)}static removeCommand(e){let t=this.commands.findIndex(t=>t.name===e);return t>=0?(this.commands.splice(t,1),!0):!1}static getCommand(e){return this.commands.find(t=>t.name===e)}static hasCommand(e){return this.commands.some(t=>t.name===e)}static getFormattedCommandList(){let e={task:`Task Management`,auth:`Authentication & Context`,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 Ti(e){wi.registerAll(e)}async function Ei(){return new Promise(e=>{let t=pt.request({hostname:`openrouter.ai`,path:`/api/v1/models`,method:`GET`,headers:{Accept:`application/json`}},t=>{let n=``;t.on(`data`,e=>{n+=e}),t.on(`end`,()=>{if(t.statusCode===200)try{e({success:!0,data:JSON.parse(n).data||[]})}catch{e({success:!1,error:`Failed to parse OpenRouter response`})}else e({success:!1,error:`OpenRouter API returned status ${t.statusCode}`})})});t.on(`error`,t=>{e({success:!1,error:`Failed to fetch OpenRouter models: ${t.message}`})}),t.end()})}async function Di(e=`http://localhost:11434/api`){return new Promise(t=>{try{let n=new URL(e),r=n.protocol===`https:`,i=n.port||(r?443:80),a=n.pathname.endsWith(`/`)?n.pathname.slice(0,-1):n.pathname,o={hostname:n.hostname,port:parseInt(String(i),10),path:`${a}/tags`,method:`GET`,headers:{Accept:`application/json`}},s=(r?pt:ht).request(o,e=>{let n=``;e.on(`data`,e=>{n+=e}),e.on(`end`,()=>{if(e.statusCode===200)try{t({success:!0,data:JSON.parse(n).models||[]})}catch{t({success:!1,error:`Failed to parse Ollama response`})}else t({success:!1,error:`Ollama API returned status ${e.statusCode}`})})});s.on(`error`,e=>{t({success:!1,error:`Failed to connect to Ollama: ${e.message}`})}),s.end()}catch(e){t({success:!1,error:`Invalid Ollama base URL: ${e instanceof Error?e.message:`Unknown error`}`})}})}async function Oi(e){let t=await Ei();return!t.success||!t.data?!1:t.data.some(t=>t.id===e)}async function ki(e,t){let n=await Di(t);return!n.success||!n.data?!1:n.data.some(t=>t.model===e)}const Ai=`The configuration file is missing. Run "task-master init" to create it.`;function ji(){return new Promise(e=>{let t=pt.request({hostname:`openrouter.ai`,path:`/api/v1/models`,method:`GET`,headers:{Accept:`application/json`}},t=>{let n=``;t.on(`data`,e=>{n+=e}),t.on(`end`,()=>{if(t.statusCode===200)try{e(JSON.parse(n).data||[])}catch(t){console.error(`Error parsing OpenRouter response:`,t),e(null)}else console.error(`OpenRouter API request failed with status code: ${t.statusCode}`),e(null)})});t.on(`error`,t=>{console.error(`Error fetching OpenRouter models:`,t),e(null)}),t.end()})}function Mi(e=`http://localhost:11434/api`){return new Promise(t=>{try{let n=new URL(e),r=n.protocol===`https:`,i=n.port||(r?443:80),a=n.pathname.endsWith(`/`)?n.pathname.slice(0,-1):n.pathname,o={hostname:n.hostname,port:parseInt(i,10),path:`${a}/tags`,method:`GET`,headers:{Accept:`application/json`}},s=(r?pt:ht).request(o,e=>{let n=``;e.on(`data`,e=>{n+=e}),e.on(`end`,()=>{if(e.statusCode===200)try{t(JSON.parse(n).models||[])}catch(e){console.error(`Error parsing Ollama response:`,e),t(null)}else console.error(`Ollama API request failed with status code: ${e.statusCode}`),t(null)})});s.on(`error`,e=>{console.error(`Error fetching Ollama models:`,e),t(null)}),s.end()}catch(e){console.error(`Error parsing Ollama base URL:`,e),t(null)}})}async function Ni(e={}){let{mcpLog:t,projectRoot:n,session:r}=e,i=(e,...n)=>{t&&typeof t[e]==`function`&&t[e](...n)};if(!n)throw Error(`Project root is required but not found.`);let a=T(null,{projectRoot:n}),o=s(n);if(z(`debug`,`Checking for config file using findConfigPath, found: ${a}`),z(`debug`,`Checking config file using isConfigFilePresent(), exists: ${o}`),!o)throw Error(Ai);try{let e=Re(n),t=l(n),i=Te(`main`,n),a=g(n),o=he(n),s=Te(`research`,n),c=Ve(n),u=Ie(n),d=Te(`fallback`,n),f=Ue(e,r,n),p=S(e,n),m=Ue(a,r,n),h=S(a,n),_=c?Ue(c,r,n):!0,v=c?S(c,n):!0,y=pe(n),b=y.find(e=>e.id===t),x=y.find(e=>e.id===o),C=u?y.find(e=>e.id===u):null;return{success:!0,data:{activeModels:{main:{provider:e,modelId:t,baseURL:i,sweScore:b?.swe_score||null,cost:b?.cost_per_1m_tokens||null,keyStatus:{cli:f,mcp:p}},research:{provider:a,modelId:o,baseURL:s,sweScore:x?.swe_score||null,cost:x?.cost_per_1m_tokens||null,keyStatus:{cli:m,mcp:h}},fallback:c?{provider:c,modelId:u,baseURL:d,sweScore:C?.swe_score||null,cost:C?.cost_per_1m_tokens||null,keyStatus:{cli:_,mcp:v}}:null},message:`Successfully retrieved current model configuration`}}}catch(e){return i(`error`,`Error getting model configuration: ${e.message}`),{success:!1,error:{code:`CONFIG_ERROR`,message:e.message}}}}async function Pi(e={}){let{mcpLog:t,projectRoot:n}=e,r=(e,...n)=>{t&&typeof t[e]==`function`&&t[e](...n)};if(!n)throw Error(`Project root is required but not found.`);let i=T(null,{projectRoot:n}),a=s(n);if(z(`debug`,`Checking for config file using findConfigPath, found: ${i}`),z(`debug`,`Checking config file using isConfigFilePresent(), exists: ${a}`),!a)throw Error(Ai);try{let e=pe(n);if(!e||e.length===0)return{success:!0,data:{models:[],message:`No available models found`}};[l(n),he(n),Ie(n)].filter(Boolean);let t=e.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:t,message:`Successfully retrieved ${t.length} available models`}}}catch(e){return r(`error`,`Error getting available models: ${e.message}`),{success:!1,error:{code:`MODELS_LIST_ERROR`,message:e.message}}}}async function Fi(e,t,n={}){let{mcpLog:r,projectRoot:i,providerHint:a,baseURL:o}=n,c=o,l=(e,...t)=>{r&&typeof r[e]==`function`&&r[e](...t)};if(!i)throw Error(`Project root is required but not found.`);let u=T(null,{projectRoot:i}),d=s(i);if(z(`debug`,`Checking for config file using findConfigPath, found: ${u}`),z(`debug`,`Checking config file using isConfigFilePresent(), exists: ${d}`),!d)throw Error(Ai);if(![`main`,`research`,`fallback`].includes(e))return{success:!1,error:{code:`INVALID_ROLE`,message:`Invalid role: ${e}. Must be one of: main, research, fallback.`}};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=pe(i),r=De(i),s=null,u=null,d;if(d=a?n.find(e=>e.id===t&&e.provider===a):n.find(e=>e.id===t),a)if(d&&d.provider===a)s=a,l(`info`,`Model ${t} found internally with provider ${s}.`);else if(a===R.OPENROUTER){l(`info`,`Checking OpenRouter for ${t} (as hinted)...`);let e=await ji();if(e&&e.some(e=>e.id===t))s=R.OPENROUTER,u=t.endsWith(`:free`)?`Warning: OpenRouter free model '${t}' selected. Free models have significant limitations including lower context windows, reduced rate limits, and may not support advanced features like tool_use. Consider using the paid version '${t.replace(`:free`,``)}' for full functionality.`:`Warning: Custom OpenRouter model '${t}' set. This model is not officially validated by Taskmaster and may not function as expected.`,l(`warn`,u);else throw Error(`Model ID "${t}" not found in the live OpenRouter model list. Please verify the ID and ensure it's available on OpenRouter.`)}else if(a===R.OLLAMA){l(`info`,`Checking Ollama for ${t} (as hinted)...`);let n;e===`main`?n=Re(i):e===`research`?n=g(i):e===`fallback`&&(n=Ve(i));let r=n===R.OLLAMA?Te(e,i):null,a=o||r||`http://localhost:11434/api`,d=await Mi(a);if(d===null)throw Error(`Unable to connect to Ollama server at ${a}. Please ensure Ollama is running and try again.`);if(d.some(e=>e.model===t))s=R.OLLAMA,u=`Warning: Custom Ollama model '${t}' set. Ensure your Ollama server is running and has pulled this model. Taskmaster cannot guarantee compatibility.`,l(`warn`,u),c=a;else{let e=`${a}/tags`;throw Error(`Model ID "${t}" not found in the Ollama instance. Please verify the model is pulled and available. You can check available models with: curl ${e}`)}}else if(a===R.BEDROCK)s=R.BEDROCK,u=`Warning: Custom Bedrock model '${t}' set. Please ensure the model ID is valid and accessible in your AWS account.`,l(`warn`,u);else if(a===R.CLAUDE_CODE){s=R.CLAUDE_CODE;let e=n.filter(e=>e.provider===`claude-code`).find(e=>e.id===t);e?(d=e,l(`info`,`Setting Claude Code model '${t}'.`)):(u=`Warning: Claude Code model '${t}' not found in supported models. Setting without validation.`,l(`warn`,u))}else if(a===R.AZURE){s=R.AZURE;let n;e===`main`?n=Re(i):e===`research`?n=g(i):e===`fallback`&&(n=Ve(i));let r=n===R.AZURE?Te(e,i):null,a=o||r;if(!a)throw Error(`Base URL is required for Azure providers. Please provide a baseURL or set global.azureBaseURL in config.`);u=`Warning: Custom Azure model '${t}' set with base URL '${a}'. Please ensure the model deployment is valid and accessible in your Azure account.`,l(`warn`,u),c=a}else if(a===R.VERTEX)s=R.VERTEX,u=`Warning: Custom Vertex AI model '${t}' set. Please ensure the model is valid and accessible in your Google Cloud project.`,l(`warn`,u);else if(a===R.GEMINI_CLI){s=R.GEMINI_CLI;let e=n.filter(e=>e.provider===`gemini-cli`).find(e=>e.id===t);e?(d=e,l(`info`,`Setting Gemini CLI model '${t}'.`)):(u=`Warning: Gemini CLI model '${t}' not found in supported models. Setting without validation.`,l(`warn`,u))}else if(a===R.CODEX_CLI){s=R.CODEX_CLI;let e=n.filter(e=>e.provider===`codex-cli`).find(e=>e.id===t);e?(d=e,l(`info`,`Setting Codex CLI model '${t}'.`)):(u=`Warning: Codex CLI model '${t}' not found in supported models. Setting without validation.`,l(`warn`,u))}else if(a===R.LMSTUDIO){s=R.LMSTUDIO;let n;e===`main`?n=Re(i):e===`research`?n=g(i):e===`fallback`&&(n=Ve(i));let r=n===R.LMSTUDIO?Te(e,i):null,a=o||r||`http://localhost:1234/v1`;u=`Warning: Custom LM Studio model '${t}' set with base URL '${a}'. Please ensure LM Studio server is running and has loaded this model. Taskmaster cannot guarantee compatibility.`,l(`warn`,u),c=a}else if(a===R.OPENAI_COMPATIBLE){s=R.OPENAI_COMPATIBLE;let n;e===`main`?n=Re(i):e===`research`?n=g(i):e===`fallback`&&(n=Ve(i));let r=n===R.OPENAI_COMPATIBLE?Te(e,i):null,a=o||r;if(!a)throw Error(`Base URL is required for OpenAI-compatible providers. Please provide a baseURL.`);u=`Warning: Custom OpenAI-compatible model '${t}' set with base URL '${a}'. Taskmaster cannot guarantee compatibility. Ensure your API endpoint follows the OpenAI API specification.`,l(`warn`,u),c=a}else throw Error(`Invalid provider hint received: ${a}`);else if(d)s=d.provider,l(`info`,`Model ${t} found internally with provider ${s}.`);else return{success:!1,error:{code:`MODEL_NOT_FOUND_NO_HINT`,message:`Model ID "${t}" not found in Taskmaster's supported models. If this is a custom model, please specify the provider using --openrouter, --ollama, --bedrock, --azure, --vertex, --lmstudio, --openai-compatible, --gemini-cli, or --codex-cli.`}};if(!s)return{success:!1,error:{code:`PROVIDER_UNDETERMINED`,message:`Could not determine the provider for model ID "${t}".`}};if(r.models[e]={...r.models[e],provider:s,modelId:t},c&&(s===R.OPENAI_COMPATIBLE||s===R.LMSTUDIO||s===R.OLLAMA||s===R.AZURE)?r.models[e].baseURL=c:delete r.models[e].baseURL,d&&d.max_tokens&&(r.models[e].maxTokens=d.max_tokens),!Ae(r,i))return{success:!1,error:{code:`CONFIG_WRITE_ERROR`,message:`Error writing updated configuration to configuration file`}};let f=`Successfully set ${e} model to ${t} (Provider: ${s})`;return l(`info`,f),{success:!0,data:{role:e,provider:s,modelId:t,message:f,warning:u}}}catch(t){return l(`error`,`Error setting ${e} model: ${t.message}`),{success:!1,error:{code:`SET_MODEL_ERROR`,message:t.message}}}}async function Ii(e={}){let{mcpLog:t,projectRoot:n,session:r}=e,i=(e,...n)=>{t&&typeof t[e]==`function`&&t[e](...n)};try{let e=Ce().filter(e=>e.toLowerCase()!==`ollama`).map(e=>({provider:e,cli:Ue(e,r,n),mcp:S(e,n)}));return i(`info`,`Successfully generated API key status report.`),{success:!0,data:{report:e,message:`API key status report generated.`}}}catch(e){return i(`error`,`Error generating API key status report: ${e.message}`),{success:!1,error:{code:`API_KEY_STATUS_ERROR`,message:e.message}}}}async function Li(e){return Ni(e)}async function Ri(e,t,n){return Fi(e,t,n)}function zi(e){return De(e)}function Bi(e,t){return Ae(e,t)}function Vi(){return pe()}function Hi(e){return N(e)??``}const Ui={OPENROUTER:{id:`__CUSTOM_OPENROUTER__`,name:`* Custom OpenRouter model`,provider:R.OPENROUTER,promptMessage:e=>`Enter the custom OpenRouter Model ID for the ${e} role:`,validate:async e=>{let t=await Oi(e);return t||console.error(B.red(`Error: Model ID "${e}" not found in the live OpenRouter model list. Please check the ID.`)),t}},OLLAMA:{id:`__CUSTOM_OLLAMA__`,name:`* Custom Ollama model`,provider:R.OLLAMA,requiresBaseURL:!0,defaultBaseURL:`http://localhost:11434/api`,promptMessage:e=>`Enter the custom Ollama Model ID for the ${e} role:`,validate:async(e,t)=>{let n=t||`http://localhost:11434/api`,r=await ki(e,n);return r||(console.error(B.red(`Error: Model ID "${e}" not found in the Ollama instance. Please verify the model is pulled and available.`)),console.log(B.yellow(`You can check available models with: curl ${n}/tags`))),r}},BEDROCK:{id:`__CUSTOM_BEDROCK__`,name:`* Custom Bedrock model`,provider:R.BEDROCK,promptMessage:e=>`Enter the custom Bedrock Model ID for the ${e} role (e.g., anthropic.claude-3-sonnet-20240229-v1:0):`,checkEnvVars:()=>((!process.env.AWS_ACCESS_KEY_ID||!process.env.AWS_SECRET_ACCESS_KEY)&&console.warn(B.yellow(`Warning: AWS_ACCESS_KEY_ID and/or AWS_SECRET_ACCESS_KEY environment variables are missing. Will fallback to system configuration (ex: aws config files or ec2 instance profiles).`)),!0)},AZURE:{id:`__CUSTOM_AZURE__`,name:`* Custom Azure OpenAI model`,provider:R.AZURE,requiresBaseURL:!0,promptMessage:e=>`Enter the Azure deployment name for the ${e} role (e.g., gpt-4o):`,checkEnvVars:()=>process.env.AZURE_OPENAI_API_KEY?!0:(console.error(B.red(`Error: AZURE_OPENAI_API_KEY environment variable is missing. Please set it before using Azure models.`)),!1)},VERTEX:{id:`__CUSTOM_VERTEX__`,name:`* Custom Vertex model`,provider:R.VERTEX,promptMessage:e=>`Enter the custom Vertex AI Model ID for the ${e} role (e.g., gemini-1.5-pro-002):`,checkEnvVars:()=>!process.env.GOOGLE_API_KEY&&!process.env.GOOGLE_APPLICATION_CREDENTIALS?(console.error(B.red(`Error: Either GOOGLE_API_KEY or GOOGLE_APPLICATION_CREDENTIALS environment variable is required. Please set one before using custom Vertex models.`)),!1):!0},LMSTUDIO:{id:`__CUSTOM_LMSTUDIO__`,name:`* Custom LMStudio model`,provider:R.LMSTUDIO,requiresBaseURL:!0,defaultBaseURL:`http://localhost:1234/v1`,promptMessage:e=>`Enter the custom LM Studio Model ID for the ${e} role:`,checkEnvVars:()=>(console.log(B.blue(`Note: LM Studio runs locally. Make sure the LM Studio server is running.`)),!0)},OPENAI_COMPATIBLE:{id:`__CUSTOM_OPENAI_COMPATIBLE__`,name:`* Custom OpenAI-compatible model`,provider:R.OPENAI_COMPATIBLE,promptMessage:e=>`Enter the custom OpenAI-compatible Model ID for the ${e} role:`,requiresBaseURL:!0,checkEnvVars:()=>(console.log(B.blue(`Note: This will configure a generic OpenAI-compatible provider. Make sure your API endpoint is accessible.`)),!0)}};async function Wi(e,t,n=null,r){let i=Object.entries(Ui).find(([t,n])=>n.id===e);if(!i)return console.error(B.red(`Unknown custom provider: ${e}`)),{modelId:null,provider:null,success:!1};let a=i[1];if(a.checkEnvVars&&!a.checkEnvVars())return{modelId:null,provider:null,success:!1};let o=null;if(a.requiresBaseURL){let e;e=n?.provider===a.provider&&n?.baseURL?n.baseURL:a.provider===R.AZURE&&r?Hi(r)||``:a.defaultBaseURL||``,o=(await q.prompt([{type:`input`,name:`baseURL`,message:`Enter the base URL for the ${t} role:`,default:e,validate:e=>{if(!e||e.trim()===``)return`Base URL is required for ${a.provider} providers`;try{return new URL(e),!0}catch{return`Please enter a valid URL`}}}])).baseURL}let{customId:s}=await q.prompt([{type:`input`,name:`customId`,message:a.promptMessage(t)}]);if(!s)return console.log(B.yellow(`No custom ID entered. Skipping role.`)),{modelId:null,provider:null,success:!0};if(a.validate){if(!await a.validate(s,o||void 0))return{modelId:null,provider:null,success:!1}}else console.log(B.blue(`Custom ${a.provider} model "${s}" will be used. No validation performed.`));return{modelId:s,provider:a.provider,baseURL:o,success:!0}}function Gi(){return Object.values(Ui).map(e=>({name:e.name,value:e.id,short:e.name}))}function Ki(e,t,n=!1){let r=t[e],i=Vi().filter(e=>!!e.provider).reduce((e,t)=>(e[t.provider]||(e[t.provider]=[]),e[t.provider].push(t),e),{}),a=[],o={name:`⏹ Cancel Model Setup`,value:`__CANCEL__`,short:`Cancel`},s=r?.modelId&&r?.provider?{name:`✔ No change to current ${e} model (${r.provider}/${r.modelId})`,value:`__NO_CHANGE__`,short:`No change`}:null;s&&a.push(s),a.push(o);let c=Object.entries(i).flatMap(([t,n])=>n.filter(t=>t.allowed_roles&&t.allowed_roles.includes(e)).map(e=>{let n=e.name||e.id;return{name:`${t} / ${n} ${e.cost_per_1m_tokens?B.gray(`($${e.cost_per_1m_tokens.input.toFixed(2)} input | $${e.cost_per_1m_tokens.output.toFixed(2)} output)`):``}`,value:{id:e.id,provider:t},short:`${t}/${n}`}})).filter(e=>e!==null),l=-1;r?.modelId&&r?.provider&&(l=c.findIndex(e=>typeof e.value==`object`&&e.value!==null&&`id`in e.value&&e.value.id===r.modelId&&e.value.provider===r.provider));let u=Gi(),d=a.length,f,p;if(n){f=[...a,new dt(`
|
|
254
258
|
── Standard Models ──`),{name:`⚪ None (disable)`,value:null,short:`None`},...c,new dt(`
|
|
255
259
|
── Custom Providers ──`),...u];let e=d+1;p=l===-1?e:l+d+2}else f=[...a,new dt(`
|
|
256
260
|
── Standard Models ──`),...c,new dt(`
|
|
257
|
-
── Custom Providers ──`),...u],p=l===-1?s?1:0:l+d+1;return(p<0||p>=f.length)&&(p=0,console.warn(`Warning: Could not determine default model for role '${e}'. Defaulting to 'Cancel'.`)),{choices:f,default:p}}function
|
|
261
|
+
── Custom Providers ──`),...u],p=l===-1?s?1:0:l+d+1;return(p<0||p>=f.length)&&(p=0,console.warn(`Warning: Could not determine default model for role '${e}'. Defaulting to 'Cancel'.`)),{choices:f,default:p}}function qi(e,t){return(t=``)=>{let n=e.filter(e=>{if(e instanceof dt)return!0;let n=e;return`${n.name||``} ${typeof n.value==`object`&&n.value!==null&&`id`in n.value?n.value.id:``}`.toLowerCase().includes(t.toLowerCase())});return Promise.resolve(n.map(e=>{if(e instanceof dt)return e;let t=e;return{name:t.name,value:t.value,short:t.short}}))}}function Ji(){console.log(B.cyan(`
|
|
258
262
|
🎯 Interactive Model Setup`)),console.log(B.gray(`━`.repeat(50))),console.log(B.yellow(`💡 Navigation tips:`)),console.log(B.gray(` • Type to search and filter options`)),console.log(B.gray(` • Use ↑↓ arrow keys to navigate results`)),console.log(B.gray(` • Standard models are listed first, custom providers at bottom`)),console.log(B.gray(` • Press Enter to select
|
|
259
|
-
`))}async function
|
|
263
|
+
`))}async function Yi(e,t){return await ut({message:`Select the ${{main:`main model for generation/updates`,research:`research model`,fallback:`fallback model (optional)`}[e]}:`,source:qi(t.choices,t.default),pageSize:15})}function Xi(e){return typeof e==`string`?Object.values(Ui).some(t=>t.id===e):!1}async function Zi(e,t,n,r){let i=n?.modelId??null,a=n?.provider??null,o=n?.baseURL??null;if(t===`__CANCEL__`)return console.log(B.yellow(`\nSetup canceled during ${e} model selection.`)),{success:!1,modified:!1};if(t===`__NO_CHANGE__`)return console.log(B.gray(`No change selected for ${e} model.`)),{success:!0,modified:!1};let s=null,c=null,l=null;if(Xi(t)){let i=await Wi(t,e,n,r);if(!i.success)return{success:!1,modified:!1};if(!i.modelId)return{success:!0,modified:!1};s=i.modelId,c=i.provider,l=i.baseURL||null}else if(t&&typeof t==`object`&&`id`in t)s=t.id,c=t.provider;else if(t===null&&e===`fallback`)s=null,c=null;else if(t)return console.error(B.red(`Internal Error: Unexpected selection value for ${e}: ${JSON.stringify(t)}`)),{success:!1,modified:!1};if(s===i&&(c??null)===a&&(l??null)===o)return{success:!0,modified:!1};if(s){let t=await Ri(e,s,{projectRoot:r,providerHint:c||void 0,baseURL:l||void 0});return t.success?(console.log(B.blue(`Set ${e} model: ${t.data?.provider} / ${t.data?.modelId}`)),t.data?.warning&&console.log(B.yellow(t.data?.warning)),{success:!0,modified:!0}):(console.error(B.red(`Error setting ${e} model: ${t.error?.message||`Unknown`}`)),{success:!1,modified:!1})}else if(e===`fallback`){let e=zi(r);return e?.models?.fallback?.modelId?(e.models.fallback={...e.models.fallback,provider:void 0,modelId:void 0},Bi(e,r)?(console.log(B.blue(`Fallback model disabled.`)),{success:!0,modified:!0}):(console.error(B.red(`Failed to disable fallback model in config file.`)),{success:!1,modified:!1})):(console.log(B.blue(`Fallback model was already disabled.`)),{success:!0,modified:!1})}return{success:!0,modified:!1}}async function Qi(e){e||(console.error(B.red(`Error: Could not determine project root for interactive setup.`)),process.exit(1));let t=await Li({projectRoot:e}),n=t.success&&t.data?{main:t.data.activeModels.main?{modelId:t.data.activeModels.main.modelId,provider:t.data.activeModels.main.provider,baseURL:t.data.activeModels.main.baseURL}:null,research:t.data.activeModels.research?{modelId:t.data.activeModels.research.modelId,provider:t.data.activeModels.research.provider,baseURL:t.data.activeModels.research.baseURL}:null,fallback:t.data.activeModels.fallback?{modelId:t.data.activeModels.fallback.modelId,provider:t.data.activeModels.fallback.provider,baseURL:t.data.activeModels.fallback.baseURL}:null}:{main:null,research:null,fallback:null};!t.success&&t.error?.code!==`CONFIG_MISSING`&&console.warn(B.yellow(`Warning: Could not load current model configuration: ${t.error?.message||`Unknown error`}. Proceeding with defaults.`));let r=Ki(`main`,n),i=Ki(`research`,n),a=Ki(`fallback`,n,!0);Ji();let o=await Yi(`main`,r);if(o===`__CANCEL__`)return!1;let s=await Yi(`research`,i);if(s===`__CANCEL__`)return!1;let c=await Yi(`fallback`,a);if(c===`__CANCEL__`)return!1;let l=!0,u=!1,d=await Zi(`main`,o,n.main,e);d.success||(l=!1),d.modified&&(u=!0);let f=await Zi(`research`,s,n.research,e);f.success||(l=!1),f.modified&&(u=!0);let p=await Zi(`fallback`,c,n.fallback,e);return p.success||(l=!1),p.modified&&(u=!0),l&&u?console.log(B.green.bold(`
|
|
260
264
|
Model setup complete!`)):l&&!u?console.log(B.yellow(`
|
|
261
265
|
No changes made to model configuration.`)):console.error(B.red(`
|
|
262
|
-
Errors occurred during model selection. Please review and try again.`)),l}const
|
|
266
|
+
Errors occurred during model selection. Please review and try again.`)),l}const $i=[`pending`,`done`,`in-progress`,`review`,`deferred`,`cancelled`];function ea(e){return $i.includes(e)}const ta=`unknown`;function na(e){if(!e||typeof e!=`object`)return!1;let t=e.bin;return!t||typeof t!=`object`?!1:Object.prototype.hasOwnProperty.call(t,`task-master`)||Object.prototype.hasOwnProperty.call(t,`task-master-ai`)}function ra(e){try{return JSON.parse(Je.readFileSync(e,`utf8`))}catch{return null}}function ia(e=We.dirname(Ye(import.meta.url))){let t=e;for(;;){let e=We.join(t,`package.json`);if(Je.existsSync(e)&&na(ra(e)))return e;let n=We.dirname(t);if(n===t)return null;t=n}}function aa(){let e=ia();if(!e)return process.env.npm_package_version||ta;let t=ra(e);if(!t||typeof t.version!=`string`)return process.env.npm_package_version||ta;let n=t.version.trim();return n.length>0?n:process.env.npm_package_version||ta}async function oa(e,t,n=null,r=null,i=!1,a={}){let{projectRoot:o,tag:s}=a;try{z(`info`,`Adding subtask to parent task ${t}...`);let i=w(e,o,s);if(!i||!i.tasks)throw Error(`Invalid or missing tasks file at ${e}`);let a=parseInt(t,10),c=i.tasks.find(e=>e.id===a);if(!c)throw Error(`Parent task with ID ${a} not found`);c.subtasks||=[];let l;if(n!==null){let e=parseInt(n,10),t=i.tasks.findIndex(t=>t.id===e);if(t===-1)throw Error(`Task with ID ${e} not found`);let r=i.tasks[t];if(r.parentTaskId)throw Error(`Task ${e} is already a subtask of task ${r.parentTaskId}`);if(e===a)throw Error(`Cannot make a task a subtask of itself`);if(io(i.tasks,c,e))throw Error(`Cannot create circular dependency: task ${a} is already a subtask or dependent of task ${e}`);let o=(c.subtasks.length>0?Math.max(...c.subtasks.map(e=>e.id)):0)+1;l={...r,id:o,parentTaskId:a},c.subtasks.push(l),i.tasks.splice(t,1),z(`info`,`Converted task ${e} to subtask ${a}.${o}`)}else if(r){let e=(c.subtasks.length>0?Math.max(...c.subtasks.map(e=>e.id)):0)+1;l={id:e,title:r.title,description:r.description||``,details:r.details||``,status:r.status||`pending`,dependencies:r.dependencies||[],parentTaskId:a},c.subtasks.push(l),z(`info`,`Created new subtask ${a}.${e}`)}else throw Error(`Either existingTaskId or newSubtaskData must be provided`);return _(e,i,o,s),l}catch(e){throw z(`error`,`Error adding subtask: ${e.message}`),e}}var sa=oa;const ca=[`high`,`medium`,`low`],la=`medium`;function ua(e){return ca.includes(e?.toLowerCase())}function da(e){if(!e)return null;let t=e.toLowerCase();return ua(t)?t:null}const fa=U.object({title:U.string().describe(`Clear, concise title for the task`),description:U.string().describe(`A one or two sentence description of the task`),details:U.string().describe(`In-depth implementation details, considerations, and guidance`),testStrategy:U.string().describe(`Detailed approach for verifying task completion`),dependencies:U.array(U.number()).nullable().describe(`Array of task IDs that this task depends on (must be completed before this task can start)`)}).strict(),pa=U.object({taskId:U.number().int().positive(),taskTitle:U.string(),complexityScore:U.number().min(1).max(10),recommendedSubtasks:U.number().int().nonnegative(),expansionPrompt:U.string(),reasoning:U.string()}).strict(),ma=U.object({complexityAnalysis:U.array(pa)}).strict(),ha=U.enum([`pending`,`in-progress`,`blocked`,`done`,`cancelled`,`deferred`]),ga=U.object({id:U.number().int().positive(),title:U.string().min(1).max(200),description:U.string().min(1),status:ha,dependencies:U.array(U.union([U.number().int().positive(),U.string()])),priority:U.enum([`low`,`medium`,`high`,`critical`]).nullable(),details:U.string().nullable(),testStrategy:U.string().nullable()}).strict(),_a=U.object({id:U.number().int().positive(),title:U.string().min(5).max(200),description:U.string().min(10),dependencies:U.array(U.number().int().positive()),details:U.string().min(20),status:U.enum([`pending`,`done`,`completed`]),testStrategy:U.string().nullable()}).strict(),va=U.object({subtasks:U.array(_a)}).strict(),ya=U.object({id:U.number().int().positive(),title:U.string().min(1),description:U.string().min(1),details:U.string().nullable(),testStrategy:U.string().nullable(),priority:U.enum([`high`,`medium`,`low`]).nullable(),dependencies:U.array(U.number().int().positive()).nullable(),status:U.string().nullable()}).strict(),ba=U.object({tasks:U.array(ya)}).strict(),xa=U.object({subtask:_a}).strict(),Sa=ga.extend({subtasks:U.array(_a).nullable()}).strict(),Ca=U.object({tasks:U.array(Sa)}).strict(),wa=U.object({task:Sa}),Ta={"update-tasks":Ca,"expand-task":va,"analyze-complexity":ma,"update-subtask-by-id":xa,"update-task-by-id":wa,"add-task":fa,"parse-prd":ba};var Ea={id:`add-task`,version:`1.0.0`,description:`Generate a new task based on description`,metadata:{author:`system`,created:`2024-01-01T00:00:00Z`,updated:`2024-01-01T00:00:00Z`,tags:[`task-creation`,`generation`]},parameters:{prompt:{type:`string`,required:!0,description:`User's task description`},newTaskId:{type:`number`,required:!0,description:`ID for the new task`},existingTasks:{type:`array`,description:`List of existing tasks for context`},gatheredContext:{type:`string`,description:`Context gathered from codebase analysis`},contextFromArgs:{type:`string`,description:`Additional context from manual args`},priority:{type:`string`,default:`medium`,enum:[`high`,`medium`,`low`],description:`Task priority`},dependencies:{type:`array`,description:`Task dependency IDs`},useResearch:{type:`boolean`,default:!1,description:`Use research mode`},hasCodebaseAnalysis:{type:`boolean`,required:!1,default:!1,description:`Whether codebase analysis is available`},projectRoot:{type:`string`,required:!1,default:``,description:`Project root path for context`}},prompts:{default:{system:`You are a helpful assistant that creates well-structured tasks for a software development project. Generate a single new task based on the user's description, adhering strictly to the provided JSON schema.
|
|
263
267
|
|
|
264
268
|
IMPORTANT: Your response MUST be a JSON object with the following structure (no wrapper property, just these fields directly):
|
|
265
269
|
{
|
|
@@ -327,7 +331,7 @@ Project Root: {{projectRoot}}
|
|
|
327
331
|
}
|
|
328
332
|
|
|
329
333
|
Make sure the details and test strategy are comprehensive and specific{{#if useResearch}}, incorporating current best practices from your research{{/if}}. DO NOT include the task ID in the title.
|
|
330
|
-
{{#if contextFromArgs}}{{contextFromArgs}}{{/if}}`}}},
|
|
334
|
+
{{#if contextFromArgs}}{{contextFromArgs}}{{/if}}`}}},Da={id:`analyze-complexity`,version:`1.0.0`,description:`Analyze task complexity and generate expansion recommendations`,metadata:{author:`system`,created:`2024-01-01T00:00:00Z`,updated:`2024-01-01T00:00:00Z`,tags:[`analysis`,`complexity`,`expansion`,`recommendations`]},parameters:{tasks:{type:`array`,required:!0,description:`Array of tasks to analyze`},gatheredContext:{type:`string`,default:``,description:`Additional project context`},threshold:{type:`number`,default:5,min:1,max:10,description:`Complexity threshold for expansion recommendation`},useResearch:{type:`boolean`,default:!1,description:`Use research mode for deeper analysis`},hasCodebaseAnalysis:{type:`boolean`,default:!1,description:`Whether codebase analysis is available`},projectRoot:{type:`string`,default:``,description:`Project root path for context`}},prompts:{default:{system:`You are an expert software architect and project manager analyzing task complexity. Your analysis should consider implementation effort, technical challenges, dependencies, and testing requirements.
|
|
331
335
|
|
|
332
336
|
IMPORTANT: For each task, provide an analysis object with ALL of the following fields:
|
|
333
337
|
- taskId: The ID of the task being analyzed (positive integer)
|
|
@@ -373,7 +377,7 @@ Tasks:
|
|
|
373
377
|
|
|
374
378
|
{{gatheredContext}}
|
|
375
379
|
{{/if}}
|
|
376
|
-
`}}},
|
|
380
|
+
`}}},Oa={id:`expand-task`,version:`1.0.0`,description:`Break down a task into detailed subtasks`,metadata:{author:`system`,created:`2024-01-01T00:00:00Z`,updated:`2024-01-01T00:00:00Z`,tags:[`expansion`,`subtasks`,`breakdown`]},parameters:{subtaskCount:{type:`number`,required:!0,description:`Number of subtasks to generate`},task:{type:`object`,required:!0,description:`The task to expand`},nextSubtaskId:{type:`number`,required:!0,description:`Starting ID for new subtasks`},useResearch:{type:`boolean`,default:!1,description:`Use research mode`},expansionPrompt:{type:`string`,required:!1,description:`Expansion prompt from complexity report`},additionalContext:{type:`string`,required:!1,default:``,description:`Additional context for task expansion`},complexityReasoningContext:{type:`string`,required:!1,default:``,description:`Complexity analysis reasoning context`},gatheredContext:{type:`string`,required:!1,default:``,description:`Gathered project context`},hasCodebaseAnalysis:{type:`boolean`,required:!1,default:!1,description:`Whether codebase analysis is available`},projectRoot:{type:`string`,required:!1,default:``,description:`Project root path for context`}},prompts:{"complexity-report":{condition:`expansionPrompt`,system:`You are an AI assistant helping with task breakdown. Generate {{#if (gt subtaskCount 0)}}exactly {{subtaskCount}}{{else}}an appropriate number of{{/if}} subtasks based on the provided prompt and context.
|
|
377
381
|
|
|
378
382
|
IMPORTANT: Your response MUST be a JSON object with a "subtasks" property containing an array of subtask objects. Each subtask must include ALL of the following fields:
|
|
379
383
|
- id: MUST be sequential integers starting EXACTLY from {{nextSubtaskId}}. First subtask id={{nextSubtaskId}}, second id={{nextSubtaskId}}+1, etc. DO NOT use any other numbering pattern!
|
|
@@ -501,7 +505,7 @@ Complexity Analysis Reasoning: {{complexityReasoningContext}}{{/if}}{{#if gather
|
|
|
501
505
|
|
|
502
506
|
{{gatheredContext}}{{/if}}
|
|
503
507
|
|
|
504
|
-
CRITICAL: You MUST use sequential IDs starting from {{nextSubtaskId}}. The first subtask MUST have id={{nextSubtaskId}}, the second MUST have id={{nextSubtaskId}}+1, and so on. Do NOT use parent task ID in subtask numbering!`}}},
|
|
508
|
+
CRITICAL: You MUST use sequential IDs starting from {{nextSubtaskId}}. The first subtask MUST have id={{nextSubtaskId}}, the second MUST have id={{nextSubtaskId}}+1, and so on. Do NOT use parent task ID in subtask numbering!`}}},ka={id:`parse-prd`,version:`1.0.0`,description:`Parse a Product Requirements Document into structured tasks`,metadata:{author:`system`,created:`2024-01-01T00:00:00Z`,updated:`2024-01-01T00:00:00Z`,tags:[`prd`,`parsing`,`initialization`]},parameters:{numTasks:{type:`number`,required:!0,description:`Target number of tasks to generate`},nextId:{type:`number`,required:!0,description:`Starting ID for tasks`},research:{type:`boolean`,default:!1,description:`Enable research mode for latest best practices`},prdContent:{type:`string`,required:!0,description:`Content of the PRD file`},prdPath:{type:`string`,required:!0,description:`Path to the PRD file`},defaultTaskPriority:{type:`string`,required:!1,default:`medium`,enum:[`high`,`medium`,`low`],description:`Default priority for generated tasks`},hasCodebaseAnalysis:{type:`boolean`,required:!1,default:!1,description:`Whether codebase analysis is available`},projectRoot:{type:`string`,required:!1,default:``,description:`Project root path for context`}},prompts:{default:{system:`You are an AI assistant specialized in analyzing Product Requirements Documents (PRDs) and generating a structured, logically ordered, dependency-aware and sequenced list of development tasks in JSON format.{{#if research}}
|
|
505
509
|
Before breaking down the PRD into tasks, you will:
|
|
506
510
|
1. Research and analyze the latest technologies, libraries, frameworks, and best practices that would be appropriate for this project
|
|
507
511
|
2. Identify any potential technical challenges, security concerns, or scalability issues not explicitly mentioned in the PRD without discarding any explicit requirements or going overboard with complexity -- always aim to provide the most direct path to implementation, avoiding over-engineering or roundabout approaches
|
|
@@ -573,7 +577,7 @@ Remember to thoroughly research current best practices and technologies before t
|
|
|
573
577
|
|
|
574
578
|
{{prdContent}}
|
|
575
579
|
|
|
576
|
-
IMPORTANT: Your response must be a JSON object with a "tasks" property containing an array of task objects. You may optionally include a "metadata" object. Do not include any other properties.`}}},
|
|
580
|
+
IMPORTANT: Your response must be a JSON object with a "tasks" property containing an array of task objects. You may optionally include a "metadata" object. Do not include any other properties.`}}},Aa={id:`research`,version:`1.0.0`,description:`Perform AI-powered research with project context`,metadata:{author:`system`,created:`2024-01-01T00:00:00Z`,updated:`2024-01-01T00:00:00Z`,tags:[`research`,`context-aware`,`information-gathering`]},parameters:{query:{type:`string`,required:!0,description:`Research query`},gatheredContext:{type:`string`,default:``,description:`Gathered project context`},detailLevel:{type:`string`,enum:[`low`,`medium`,`high`],default:`medium`,description:`Level of detail for the response`},projectInfo:{type:`object`,description:`Project information`,properties:{root:{type:`string`,description:`Project root path`},taskCount:{type:`number`,description:`Number of related tasks`},fileCount:{type:`number`,description:`Number of related files`}}}},prompts:{default:{system:`You are an expert AI research assistant helping with a software development project. You have access to project context including tasks, files, and project structure.
|
|
577
581
|
|
|
578
582
|
Your role is to provide comprehensive, accurate, and actionable research responses based on the user's query and the provided project context.
|
|
579
583
|
{{#if (eq detailLevel "low")}}
|
|
@@ -623,7 +627,7 @@ Your role is to provide comprehensive, accurate, and actionable research respons
|
|
|
623
627
|
|
|
624
628
|
# Instructions
|
|
625
629
|
|
|
626
|
-
Please research and provide a {{detailLevel}}-detail response to the query above. Consider the project context provided and make your response as relevant and actionable as possible for this specific project.`}}},
|
|
630
|
+
Please research and provide a {{detailLevel}}-detail response to the query above. Consider the project context provided and make your response as relevant and actionable as possible for this specific project.`}}},ja={id:`update-subtask`,version:`1.0.0`,description:`Append information to a subtask by generating only new content`,metadata:{author:`system`,created:`2024-01-01T00:00:00Z`,updated:`2024-01-01T00:00:00Z`,tags:[`update`,`subtask`,`append`,`logging`]},parameters:{parentTask:{type:`object`,required:!0,description:`The parent task context`},prevSubtask:{type:`object`,required:!1,description:`The previous subtask if any`},nextSubtask:{type:`object`,required:!1,description:`The next subtask if any`},currentDetails:{type:`string`,required:!0,default:`(No existing details)`,description:`Current subtask details`},updatePrompt:{type:`string`,required:!0,description:`User request for what to add`},useResearch:{type:`boolean`,default:!1,description:`Use research mode`},gatheredContext:{type:`string`,default:``,description:`Additional project context`},hasCodebaseAnalysis:{type:`boolean`,required:!1,default:!1,description:`Whether codebase analysis is available`},projectRoot:{type:`string`,required:!1,default:``,description:`Project root path for context`}},prompts:{default:{system:`You are an AI assistant helping to update a subtask. You will be provided with the subtask's existing details, context about its parent and sibling tasks, and a user request string.{{#if useResearch}} You have access to current best practices and latest technical information to provide research-backed updates.{{/if}}
|
|
627
631
|
|
|
628
632
|
Your Goal: Based *only* on the user's request and all the provided context (including existing details if relevant to the request), GENERATE the new text content that should be added to the subtask's details.
|
|
629
633
|
Focus *only* on generating the substance of the update.
|
|
@@ -675,7 +679,7 @@ User Request: "{{updatePrompt}}"
|
|
|
675
679
|
# Additional Project Context
|
|
676
680
|
|
|
677
681
|
{{gatheredContext}}
|
|
678
|
-
{{/if}}`}}},
|
|
682
|
+
{{/if}}`}}},Ma={id:`update-task`,version:`1.0.0`,description:`Update a single task with new information, supporting full updates and append mode`,metadata:{author:`system`,created:`2024-01-01T00:00:00Z`,updated:`2024-01-01T00:00:00Z`,tags:[`update`,`single-task`,`modification`,`append`]},parameters:{task:{type:`object`,required:!0,description:`The task to update`},taskJson:{type:`string`,required:!0,description:`JSON string representation of the task`},updatePrompt:{type:`string`,required:!0,description:`Description of changes to apply`},appendMode:{type:`boolean`,default:!1,description:`Whether to append to details or do full update`},useResearch:{type:`boolean`,default:!1,description:`Use research mode`},currentDetails:{type:`string`,default:`(No existing details)`,description:`Current task details for context`},gatheredContext:{type:`string`,default:``,description:`Additional project context`},hasCodebaseAnalysis:{type:`boolean`,required:!1,default:!1,description:`Whether codebase analysis is available`},projectRoot:{type:`string`,required:!1,default:``,description:`Project root path for context`}},prompts:{default:{system:`You are an AI assistant helping to update a software development task based on new context.{{#if useResearch}} You have access to current best practices and latest technical information to provide research-backed updates.{{/if}}
|
|
679
683
|
You will be given a task and a prompt describing changes or new implementation details.
|
|
680
684
|
Your job is to update the task to reflect these changes, while preserving its basic structure.
|
|
681
685
|
|
|
@@ -789,7 +793,7 @@ Based on the User Request and all the Task Context (including current task detai
|
|
|
789
793
|
# Additional Project Context
|
|
790
794
|
|
|
791
795
|
{{gatheredContext}}
|
|
792
|
-
{{/if}}`}}},
|
|
796
|
+
{{/if}}`}}},Na={id:`update-tasks`,version:`1.0.0`,description:`Update multiple tasks based on new context or changes`,metadata:{author:`system`,created:`2024-01-01T00:00:00Z`,updated:`2024-01-01T00:00:00Z`,tags:[`update`,`bulk`,`context-change`]},parameters:{tasks:{type:`array`,required:!0,description:`Array of tasks to update`},updatePrompt:{type:`string`,required:!0,description:`Description of changes to apply`},useResearch:{type:`boolean`,default:!1,description:`Use research mode`},projectContext:{type:`string`,description:`Additional project context`},hasCodebaseAnalysis:{type:`boolean`,required:!1,default:!1,description:`Whether codebase analysis is available`},projectRoot:{type:`string`,required:!1,default:``,description:`Project root path for context`}},prompts:{default:{system:`You are an AI assistant helping to update software development tasks based on new context.
|
|
793
797
|
You will be given a set of tasks and a prompt describing changes or new implementation details.
|
|
794
798
|
Your job is to update the tasks to reflect these changes, while preserving their basic structure.
|
|
795
799
|
|
|
@@ -839,7 +843,7 @@ IMPORTANT: In the tasks above, any subtasks with "status": "done" or "status": "
|
|
|
839
843
|
|
|
840
844
|
{{projectContext}}{{/if}}
|
|
841
845
|
|
|
842
|
-
IMPORTANT: Your response must be a JSON object with a single property named "tasks" containing the updated array of tasks.`}}},ja={$schema:`http://json-schema.org/draft-07/schema#`,$id:`https://github.com/eyaltoledano/claude-task-master/blob/main/src/prompts/schemas/prompt-template.schema.json`,version:`1.0.0`,title:`Task Master Prompt Template`,description:`Schema for Task Master AI prompt template files`,type:`object`,required:[`id`,`version`,`description`,`prompts`],properties:{id:{type:`string`,pattern:`^[a-z0-9-]+$`,description:`Unique identifier for the prompt template`},version:{type:`string`,pattern:`^\\d+\\.\\d+\\.\\d+$`,description:`Semantic version of the prompt template`},description:{type:`string`,minLength:1,description:`Brief description of what this prompt does`},metadata:{$ref:`#/definitions/metadata`},parameters:{type:`object`,additionalProperties:{$ref:`#/definitions/parameter`}},prompts:{type:`object`,properties:{default:{$ref:`#/definitions/promptVariant`}},additionalProperties:{$ref:`#/definitions/conditionalPromptVariant`}}},definitions:{parameter:{type:`object`,required:[`type`,`description`],properties:{type:{type:`string`,enum:[`string`,`number`,`boolean`,`array`,`object`]},description:{type:`string`,minLength:1},required:{type:`boolean`,default:!1},default:{description:`Default value for optional parameters`},enum:{type:`array`,description:`Valid values for string parameters`},pattern:{type:`string`,description:`Regular expression pattern for string validation`},minimum:{type:`number`,description:`Minimum value for number parameters`},maximum:{type:`number`,description:`Maximum value for number parameters`}}},promptVariant:{type:`object`,required:[`system`,`user`],properties:{system:{type:`string`,minLength:1},user:{type:`string`,minLength:1}}},conditionalPromptVariant:{allOf:[{$ref:`#/definitions/promptVariant`},{type:`object`,properties:{condition:{type:`string`,description:`JavaScript expression for variant selection`}}}]},metadata:{type:`object`,properties:{author:{type:`string`},created:{type:`string`,format:`date-time`},updated:{type:`string`,format:`date-time`},tags:{type:`array`,items:{type:`string`}},category:{type:`string`,enum:[`task`,`analysis`,`research`,`parsing`,`update`,`expansion`]}}}}},Ma=class{constructor(){this.prompts=new Map([[`analyze-complexity`,wa],[`expand-task`,Ta],[`add-task`,Ca],[`research`,Da],[`parse-prd`,Ea],[`update-task`,ka],[`update-tasks`,Aa],[`update-subtask`,Oa]]),this.cache=new Map,this.setupValidation()}setupValidation(){this.ajv=new _t({allErrors:!0,strict:!1}),vt(this.ajv);try{this.validatePrompt=this.ajv.compile(ja),z(`debug`,`✓ JSON schema validation enabled`)}catch(e){z(`warn`,`⚠ Schema validation disabled: ${e.message}`),this.validatePrompt=()=>!0}}loadPrompt(e,t={},n=null){try{let r=`${e}-${JSON.stringify(t)}-${n}`;if(this.cache.has(r))return this.cache.get(r);let i=this.loadTemplate(e);this.validatePrompt&&this.validatePrompt!==!0&&this.validateParameters(i,t);let a=n?{...i.prompts[n],name:n}:this.selectVariant(i,t),o={systemPrompt:this.renderTemplate(a.system,t),userPrompt:this.renderTemplate(a.user,t),metadata:{templateId:i.id,version:i.version,variant:a.name||`default`,parameters:t}};return this.cache.set(r,o),o}catch(t){throw z(`error`,`Failed to load prompt ${e}: ${t.message}`),t}}loadTemplate(e){let t=this.prompts.get(e);if(!t)throw Error(`Prompt template '${e}' not found`);if(this.validatePrompt&&this.validatePrompt!==!0){if(!this.validatePrompt(t)){let e=this.validatePrompt.errors.map(e=>`${e.instancePath||`root`}: ${e.message}`).join(`, `);throw Error(`Schema validation failed: ${e}`)}}else if(!t.id||!t.prompts||!t.prompts.default)throw Error(`Invalid template structure: missing required fields (id, prompts.default)`);return t}validateParameters(e,t){if(!e.parameters)return;let n=[];for(let[r,i]of Object.entries(e.parameters)){let e=t[r];if(i.required&&e===void 0){n.push(`Required parameter '${r}' missing`);continue}e!==void 0&&(this.validateParameterType(e,i.type)||n.push(`Parameter '${r}' expected ${i.type}, got ${typeof e}`),i.enum&&!i.enum.includes(e)&&n.push(`Parameter '${r}' must be one of: ${i.enum.join(`, `)}`),i.pattern&&typeof e==`string`&&(new RegExp(i.pattern).test(e)||n.push(`Parameter '${r}' does not match required pattern: ${i.pattern}`)),typeof e==`number`&&(i.minimum!==void 0&&e<i.minimum&&n.push(`Parameter '${r}' must be >= ${i.minimum}`),i.maximum!==void 0&&e>i.maximum&&n.push(`Parameter '${r}' must be <= ${i.maximum}`)))}if(n.length>0)throw Error(`Parameter validation failed: ${n.join(`; `)}`)}validateParameterType(e,t){switch(t){case`string`:return typeof e==`string`;case`number`:return typeof e==`number`;case`boolean`:return typeof e==`boolean`;case`array`:return Array.isArray(e);case`object`:return typeof e==`object`&&!!e&&!Array.isArray(e);default:return!0}}selectVariant(e,t){for(let[n,r]of Object.entries(e.prompts))if(n!==`default`&&r.condition&&this.evaluateCondition(r.condition,t))return{...r,name:n};return{...e.prompts.default,name:`default`}}evaluateCondition(e,t){try{let n={...t};return Function(...Object.keys(n),`return ${e}`)(...Object.values(n))}catch{return z(`warn`,`Failed to evaluate condition: ${e}`),!1}}renderTemplate(e,t){let n=e;return n=n.replace(/\(eq\s+(\w+(?:\.\w+)*)\s+"([^"]+)"\)/g,(e,n,r)=>this.getNestedValue(t,n)===r?`true`:`false`),n=n.replace(/\(not\s+(\w+(?:\.\w+)*)\)/g,(e,n)=>this.getNestedValue(t,n)?`false`:`true`),n=n.replace(/\(gt\s+(\w+(?:\.\w+)*)\s+(\d+(?:\.\d+)?)\)/g,(e,n,r)=>{let i=this.getNestedValue(t,n);return typeof i==`number`&&i>parseFloat(r)?`true`:`false`}),n=n.replace(/\(gte\s+(\w+(?:\.\w+)*)\s+(\d+(?:\.\d+)?)\)/g,(e,n,r)=>{let i=this.getNestedValue(t,n);return typeof i==`number`&&i>=parseFloat(r)?`true`:`false`}),n=n.replace(/\{\{#if\s+([^}]+)\}\}([\s\S]*?)(?:\{\{else\}\}([\s\S]*?))?\{\{\/if\}\}/g,(e,n,r,i=``)=>{let a;return a=n===`true`?!0:n===`false`?!1:this.getNestedValue(t,n),a?r:i}),n=n.replace(/\{\{#each\s+(\w+(?:\.\w+)*)\}\}([\s\S]*?)\{\{\/each\}\}/g,(e,n,r)=>{let i=this.getNestedValue(t,n);return Array.isArray(i)?i.map((e,n)=>{let a={...t,...e,"@index":n,"@first":n===0,"@last":n===i.length-1};return this.renderTemplate(r,a)}).join(``):``}),n=n.replace(/\{\{\{json\s+(\w+(?:\.\w+)*)\}\}\}/g,(e,n)=>{let r=this.getNestedValue(t,n);return r===void 0?``:JSON.stringify(r,null,2)}),n=n.replace(/\{\{(\w+(?:\.\w+)*)\}\}/g,(e,n)=>{let r=this.getNestedValue(t,n);return r===void 0?``:r}),n}getNestedValue(e,t){return t.split(`.`).reduce((e,t)=>e&&e[t]!==void 0?e[t]:void 0,e)}validateAllPrompts(){let e={total:0,errors:[],valid:[]};for(let[t,n]of this.prompts.entries()){e.total++;try{if(this.validatePrompt&&this.validatePrompt!==!0&&!this.validatePrompt(n)){let e=this.validatePrompt.errors.map(e=>`${e.instancePath||`root`}: ${e.message}`).join(`, `);throw Error(`Schema validation failed: ${e}`)}e.valid.push(t)}catch(n){e.errors.push(`${t}: ${n.message}`)}}return e}listPrompts(){let e=[];for(let[t,n]of this.prompts.entries())try{e.push({id:n.id,description:n.description,version:n.version,parameters:n.parameters,tags:n.metadata?.tags||[]})}catch(e){z(`warn`,`Failed to process template ${t}: ${e.message}`)}return e}validateTemplate(e){try{let t;if(typeof e==`string`){if(t=this.prompts.get(e),!t)return{valid:!1,error:`Template '${e}' not found`}}else t=e;for(let e of[`id`,`version`,`description`,`prompts`])if(!t[e])return{valid:!1,error:`Missing required field: ${e}`};if(!t.prompts.default)return{valid:!1,error:`Missing default prompt variant`};for(let[e,n]of Object.entries(t.prompts))if(!n.system||!n.user)return{valid:!1,error:`Variant '${e}' missing system or user prompt`};return this.validatePrompt&&this.validatePrompt!==!0&&!this.validatePrompt(t)?{valid:!1,error:`Schema validation failed: ${this.validatePrompt.errors.map(e=>`${e.instancePath||`root`}: ${e.message}`).join(`, `)}`}:{valid:!0}}catch(e){return{valid:!1,error:e.message}}}};let Na=null;function Pa(){return Na||=new Ma,Na}const{encode:Fa}=yt;var Ia=class{constructor(e,t){this.projectRoot=e,this.tasksPath=H.join(e,`.taskmaster`,`tasks`,`tasks.json`),this.tag=t,this.allTasks=this._loadAllTasks()}_loadAllTasks(){try{return w(this.tasksPath,this.projectRoot,this.tag)?.tasks||[]}catch(e){return console.warn(`Warning: Could not load tasks for ContextGatherer: ${e.message}`),[]}}countTokens(e){if(!e||typeof e!=`string`)return 0;try{return Fa(e).length}catch{return Math.ceil(e.length/4)}}async gather(e={}){let{tasks:t=[],files:n=[],customContext:r=``,includeProjectTree:i=!1,format:a=`research`,includeTokenCounts:o=!1,semanticQuery:s,maxSemanticResults:c=10,dependencyTasks:l=[]}=e,u=[],d=new Set(t.map(String)),f=null,p=null;if(o&&(p={total:0,customContext:null,tasks:[],files:[],projectTree:null}),s&&this.allTasks.length>0){let e=this._performSemanticSearch(s,c);f=e.analysisData,e.tasks.forEach(e=>{d.add(String(e.id))})}if(l.length>0&&this._buildDependencyGraphs(l).allRelatedTaskIds.forEach(e=>d.add(String(e))),r&&r.trim()){let e=this._formatCustomContext(r,a);u.push(e),o&&(p.customContext={tokens:this.countTokens(e),characters:e.length},p.total+=p.customContext.tokens)}if(d.size>0){let e=await this._gatherTaskContext(Array.from(d),a,o);if(e.context&&(u.push(e.context),o&&e.breakdown)){p.tasks=e.breakdown;let t=e.breakdown.reduce((e,t)=>e+t.tokens,0);p.total+=t}}if(n.length>0){let e=await this._gatherFileContext(n,a,o);if(e.context&&(u.push(e.context),o&&e.breakdown)){p.files=e.breakdown;let t=e.breakdown.reduce((e,t)=>e+t.tokens,0);p.total+=t}}if(i){let e=await this._gatherProjectTreeContext(a,o);e.context&&(u.push(e.context),o&&e.breakdown&&(p.projectTree=e.breakdown,p.total+=e.breakdown.tokens))}let m={context:this._joinContextSections(u,a),analysisData:f,contextSections:u.length,finalTaskIds:Array.from(d)};return o&&(m.tokenBreakdown=p),m}_performSemanticSearch(e,t){let n=new gt(this.allTasks.map(e=>{let t=e.dependencies?.length>0?e.dependencies.map(e=>this.allTasks.find(t=>t.id===e)?.title).filter(Boolean).join(` `):``;return{...e,dependencyTitles:t}}),{includeScore:!0,threshold:.4,keys:[{name:`title`,weight:1.5},{name:`description`,weight:2},{name:`details`,weight:3},{name:`dependencyTitles`,weight:.5}],shouldSort:!0,useExtendedSearch:!0,limit:50}),r=e.toLowerCase().replace(/[^\w\s-]/g,` `).split(/\s+/).filter(e=>e.length>3),i=n.search(e),a=[];for(let e of r)if(e.length>5){let t=n.search(e);t.length>0&&a.push(...t)}let o=[...i];for(let e of a)o.some(t=>t.item.id===e.item.id)||o.push(e);let s=o.filter(e=>e.score<.25).map(e=>e.item),c=o.filter(e=>e.score>=.25&&e.score<.4).map(e=>e.item),l=[...this.allTasks].sort((e,t)=>t.id-e.id).slice(0,5),u=[...s];for(let e of c)u.some(t=>t.id===e.id)||u.push(e);for(let e of l)u.some(t=>t.id===e.id)||u.push(e);return{tasks:u.slice(0,t),analysisData:{highRelevance:s,mediumRelevance:c,recentTasks:l,allRelevantTasks:u}}}_buildDependencyContext(e){let{allRelatedTaskIds:t,graphs:n,depthMap:r}=this._buildDependencyGraphs(e);if(t.size===0)return``;let i=Array.from(t).map(e=>this.allTasks.find(t=>t.id===e)).filter(Boolean).sort((e,t)=>(r.get(e.id)||0)-(r.get(t.id)||0)),a=i.slice(0,8),s=`\nThis task relates to a dependency structure with ${i.length} related tasks in the chain.`,c=this.allTasks.filter(t=>e.includes(t.id));c.length>0&&(s+=`\n\nDirect dependencies:\n${c.map(e=>`- Task ${e.id}: ${e.title} - ${e.description}`).join(`
|
|
846
|
+
IMPORTANT: Your response must be a JSON object with a single property named "tasks" containing the updated array of tasks.`}}},Pa={$schema:`http://json-schema.org/draft-07/schema#`,$id:`https://github.com/eyaltoledano/claude-task-master/blob/main/src/prompts/schemas/prompt-template.schema.json`,version:`1.0.0`,title:`Task Master Prompt Template`,description:`Schema for Task Master AI prompt template files`,type:`object`,required:[`id`,`version`,`description`,`prompts`],properties:{id:{type:`string`,pattern:`^[a-z0-9-]+$`,description:`Unique identifier for the prompt template`},version:{type:`string`,pattern:`^\\d+\\.\\d+\\.\\d+$`,description:`Semantic version of the prompt template`},description:{type:`string`,minLength:1,description:`Brief description of what this prompt does`},metadata:{$ref:`#/definitions/metadata`},parameters:{type:`object`,additionalProperties:{$ref:`#/definitions/parameter`}},prompts:{type:`object`,properties:{default:{$ref:`#/definitions/promptVariant`}},additionalProperties:{$ref:`#/definitions/conditionalPromptVariant`}}},definitions:{parameter:{type:`object`,required:[`type`,`description`],properties:{type:{type:`string`,enum:[`string`,`number`,`boolean`,`array`,`object`]},description:{type:`string`,minLength:1},required:{type:`boolean`,default:!1},default:{description:`Default value for optional parameters`},enum:{type:`array`,description:`Valid values for string parameters`},pattern:{type:`string`,description:`Regular expression pattern for string validation`},minimum:{type:`number`,description:`Minimum value for number parameters`},maximum:{type:`number`,description:`Maximum value for number parameters`}}},promptVariant:{type:`object`,required:[`system`,`user`],properties:{system:{type:`string`,minLength:1},user:{type:`string`,minLength:1}}},conditionalPromptVariant:{allOf:[{$ref:`#/definitions/promptVariant`},{type:`object`,properties:{condition:{type:`string`,description:`JavaScript expression for variant selection`}}}]},metadata:{type:`object`,properties:{author:{type:`string`},created:{type:`string`,format:`date-time`},updated:{type:`string`,format:`date-time`},tags:{type:`array`,items:{type:`string`}},category:{type:`string`,enum:[`task`,`analysis`,`research`,`parsing`,`update`,`expansion`]}}}}},Fa=class{constructor(){this.prompts=new Map([[`analyze-complexity`,Da],[`expand-task`,Oa],[`add-task`,Ea],[`research`,Aa],[`parse-prd`,ka],[`update-task`,Ma],[`update-tasks`,Na],[`update-subtask`,ja]]),this.cache=new Map,this.setupValidation()}setupValidation(){this.ajv=new _t({allErrors:!0,strict:!1}),vt(this.ajv);try{this.validatePrompt=this.ajv.compile(Pa),z(`debug`,`✓ JSON schema validation enabled`)}catch(e){z(`warn`,`⚠ Schema validation disabled: ${e.message}`),this.validatePrompt=()=>!0}}loadPrompt(e,t={},n=null){try{let r=`${e}-${JSON.stringify(t)}-${n}`;if(this.cache.has(r))return this.cache.get(r);let i=this.loadTemplate(e);this.validatePrompt&&this.validatePrompt!==!0&&this.validateParameters(i,t);let a=n?{...i.prompts[n],name:n}:this.selectVariant(i,t),o={systemPrompt:this.renderTemplate(a.system,t),userPrompt:this.renderTemplate(a.user,t),metadata:{templateId:i.id,version:i.version,variant:a.name||`default`,parameters:t}};return this.cache.set(r,o),o}catch(t){throw z(`error`,`Failed to load prompt ${e}: ${t.message}`),t}}loadTemplate(e){let t=this.prompts.get(e);if(!t)throw Error(`Prompt template '${e}' not found`);if(this.validatePrompt&&this.validatePrompt!==!0){if(!this.validatePrompt(t)){let e=this.validatePrompt.errors.map(e=>`${e.instancePath||`root`}: ${e.message}`).join(`, `);throw Error(`Schema validation failed: ${e}`)}}else if(!t.id||!t.prompts||!t.prompts.default)throw Error(`Invalid template structure: missing required fields (id, prompts.default)`);return t}validateParameters(e,t){if(!e.parameters)return;let n=[];for(let[r,i]of Object.entries(e.parameters)){let e=t[r];if(i.required&&e===void 0){n.push(`Required parameter '${r}' missing`);continue}e!==void 0&&(this.validateParameterType(e,i.type)||n.push(`Parameter '${r}' expected ${i.type}, got ${typeof e}`),i.enum&&!i.enum.includes(e)&&n.push(`Parameter '${r}' must be one of: ${i.enum.join(`, `)}`),i.pattern&&typeof e==`string`&&(new RegExp(i.pattern).test(e)||n.push(`Parameter '${r}' does not match required pattern: ${i.pattern}`)),typeof e==`number`&&(i.minimum!==void 0&&e<i.minimum&&n.push(`Parameter '${r}' must be >= ${i.minimum}`),i.maximum!==void 0&&e>i.maximum&&n.push(`Parameter '${r}' must be <= ${i.maximum}`)))}if(n.length>0)throw Error(`Parameter validation failed: ${n.join(`; `)}`)}validateParameterType(e,t){switch(t){case`string`:return typeof e==`string`;case`number`:return typeof e==`number`;case`boolean`:return typeof e==`boolean`;case`array`:return Array.isArray(e);case`object`:return typeof e==`object`&&!!e&&!Array.isArray(e);default:return!0}}selectVariant(e,t){for(let[n,r]of Object.entries(e.prompts))if(n!==`default`&&r.condition&&this.evaluateCondition(r.condition,t))return{...r,name:n};return{...e.prompts.default,name:`default`}}evaluateCondition(e,t){try{let n={...t};return Function(...Object.keys(n),`return ${e}`)(...Object.values(n))}catch{return z(`warn`,`Failed to evaluate condition: ${e}`),!1}}renderTemplate(e,t){let n=e;return n=n.replace(/\(eq\s+(\w+(?:\.\w+)*)\s+"([^"]+)"\)/g,(e,n,r)=>this.getNestedValue(t,n)===r?`true`:`false`),n=n.replace(/\(not\s+(\w+(?:\.\w+)*)\)/g,(e,n)=>this.getNestedValue(t,n)?`false`:`true`),n=n.replace(/\(gt\s+(\w+(?:\.\w+)*)\s+(\d+(?:\.\d+)?)\)/g,(e,n,r)=>{let i=this.getNestedValue(t,n);return typeof i==`number`&&i>parseFloat(r)?`true`:`false`}),n=n.replace(/\(gte\s+(\w+(?:\.\w+)*)\s+(\d+(?:\.\d+)?)\)/g,(e,n,r)=>{let i=this.getNestedValue(t,n);return typeof i==`number`&&i>=parseFloat(r)?`true`:`false`}),n=n.replace(/\{\{#if\s+([^}]+)\}\}([\s\S]*?)(?:\{\{else\}\}([\s\S]*?))?\{\{\/if\}\}/g,(e,n,r,i=``)=>{let a;return a=n===`true`?!0:n===`false`?!1:this.getNestedValue(t,n),a?r:i}),n=n.replace(/\{\{#each\s+(\w+(?:\.\w+)*)\}\}([\s\S]*?)\{\{\/each\}\}/g,(e,n,r)=>{let i=this.getNestedValue(t,n);return Array.isArray(i)?i.map((e,n)=>{let a={...t,...e,"@index":n,"@first":n===0,"@last":n===i.length-1};return this.renderTemplate(r,a)}).join(``):``}),n=n.replace(/\{\{\{json\s+(\w+(?:\.\w+)*)\}\}\}/g,(e,n)=>{let r=this.getNestedValue(t,n);return r===void 0?``:JSON.stringify(r,null,2)}),n=n.replace(/\{\{(\w+(?:\.\w+)*)\}\}/g,(e,n)=>{let r=this.getNestedValue(t,n);return r===void 0?``:r}),n}getNestedValue(e,t){return t.split(`.`).reduce((e,t)=>e&&e[t]!==void 0?e[t]:void 0,e)}validateAllPrompts(){let e={total:0,errors:[],valid:[]};for(let[t,n]of this.prompts.entries()){e.total++;try{if(this.validatePrompt&&this.validatePrompt!==!0&&!this.validatePrompt(n)){let e=this.validatePrompt.errors.map(e=>`${e.instancePath||`root`}: ${e.message}`).join(`, `);throw Error(`Schema validation failed: ${e}`)}e.valid.push(t)}catch(n){e.errors.push(`${t}: ${n.message}`)}}return e}listPrompts(){let e=[];for(let[t,n]of this.prompts.entries())try{e.push({id:n.id,description:n.description,version:n.version,parameters:n.parameters,tags:n.metadata?.tags||[]})}catch(e){z(`warn`,`Failed to process template ${t}: ${e.message}`)}return e}validateTemplate(e){try{let t;if(typeof e==`string`){if(t=this.prompts.get(e),!t)return{valid:!1,error:`Template '${e}' not found`}}else t=e;for(let e of[`id`,`version`,`description`,`prompts`])if(!t[e])return{valid:!1,error:`Missing required field: ${e}`};if(!t.prompts.default)return{valid:!1,error:`Missing default prompt variant`};for(let[e,n]of Object.entries(t.prompts))if(!n.system||!n.user)return{valid:!1,error:`Variant '${e}' missing system or user prompt`};return this.validatePrompt&&this.validatePrompt!==!0&&!this.validatePrompt(t)?{valid:!1,error:`Schema validation failed: ${this.validatePrompt.errors.map(e=>`${e.instancePath||`root`}: ${e.message}`).join(`, `)}`}:{valid:!0}}catch(e){return{valid:!1,error:e.message}}}};let Ia=null;function La(){return Ia||=new Fa,Ia}const{encode:Ra}=yt;var za=class{constructor(e,t){this.projectRoot=e,this.tasksPath=H.join(e,`.taskmaster`,`tasks`,`tasks.json`),this.tag=t,this.allTasks=this._loadAllTasks()}_loadAllTasks(){try{return w(this.tasksPath,this.projectRoot,this.tag)?.tasks||[]}catch(e){return console.warn(`Warning: Could not load tasks for ContextGatherer: ${e.message}`),[]}}countTokens(e){if(!e||typeof e!=`string`)return 0;try{return Ra(e).length}catch{return Math.ceil(e.length/4)}}async gather(e={}){let{tasks:t=[],files:n=[],customContext:r=``,includeProjectTree:i=!1,format:a=`research`,includeTokenCounts:o=!1,semanticQuery:s,maxSemanticResults:c=10,dependencyTasks:l=[]}=e,u=[],d=new Set(t.map(String)),f=null,p=null;if(o&&(p={total:0,customContext:null,tasks:[],files:[],projectTree:null}),s&&this.allTasks.length>0){let e=this._performSemanticSearch(s,c);f=e.analysisData,e.tasks.forEach(e=>{d.add(String(e.id))})}if(l.length>0&&this._buildDependencyGraphs(l).allRelatedTaskIds.forEach(e=>d.add(String(e))),r&&r.trim()){let e=this._formatCustomContext(r,a);u.push(e),o&&(p.customContext={tokens:this.countTokens(e),characters:e.length},p.total+=p.customContext.tokens)}if(d.size>0){let e=await this._gatherTaskContext(Array.from(d),a,o);if(e.context&&(u.push(e.context),o&&e.breakdown)){p.tasks=e.breakdown;let t=e.breakdown.reduce((e,t)=>e+t.tokens,0);p.total+=t}}if(n.length>0){let e=await this._gatherFileContext(n,a,o);if(e.context&&(u.push(e.context),o&&e.breakdown)){p.files=e.breakdown;let t=e.breakdown.reduce((e,t)=>e+t.tokens,0);p.total+=t}}if(i){let e=await this._gatherProjectTreeContext(a,o);e.context&&(u.push(e.context),o&&e.breakdown&&(p.projectTree=e.breakdown,p.total+=e.breakdown.tokens))}let m={context:this._joinContextSections(u,a),analysisData:f,contextSections:u.length,finalTaskIds:Array.from(d)};return o&&(m.tokenBreakdown=p),m}_performSemanticSearch(e,t){let n=new gt(this.allTasks.map(e=>{let t=e.dependencies?.length>0?e.dependencies.map(e=>this.allTasks.find(t=>t.id===e)?.title).filter(Boolean).join(` `):``;return{...e,dependencyTitles:t}}),{includeScore:!0,threshold:.4,keys:[{name:`title`,weight:1.5},{name:`description`,weight:2},{name:`details`,weight:3},{name:`dependencyTitles`,weight:.5}],shouldSort:!0,useExtendedSearch:!0,limit:50}),r=e.toLowerCase().replace(/[^\w\s-]/g,` `).split(/\s+/).filter(e=>e.length>3),i=n.search(e),a=[];for(let e of r)if(e.length>5){let t=n.search(e);t.length>0&&a.push(...t)}let o=[...i];for(let e of a)o.some(t=>t.item.id===e.item.id)||o.push(e);let s=o.filter(e=>e.score<.25).map(e=>e.item),c=o.filter(e=>e.score>=.25&&e.score<.4).map(e=>e.item),l=[...this.allTasks].sort((e,t)=>t.id-e.id).slice(0,5),u=[...s];for(let e of c)u.some(t=>t.id===e.id)||u.push(e);for(let e of l)u.some(t=>t.id===e.id)||u.push(e);return{tasks:u.slice(0,t),analysisData:{highRelevance:s,mediumRelevance:c,recentTasks:l,allRelevantTasks:u}}}_buildDependencyContext(e){let{allRelatedTaskIds:t,graphs:n,depthMap:r}=this._buildDependencyGraphs(e);if(t.size===0)return``;let i=Array.from(t).map(e=>this.allTasks.find(t=>t.id===e)).filter(Boolean).sort((e,t)=>(r.get(e.id)||0)-(r.get(t.id)||0)),a=i.slice(0,8),s=`\nThis task relates to a dependency structure with ${i.length} related tasks in the chain.`,c=this.allTasks.filter(t=>e.includes(t.id));c.length>0&&(s+=`\n\nDirect dependencies:\n${c.map(e=>`- Task ${e.id}: ${e.title} - ${e.description}`).join(`
|
|
843
847
|
`)}`);let l=i.filter(t=>!e.includes(t.id));l.length>0&&(s+=`\n\nIndirect dependencies (dependencies of dependencies):\n${l.slice(0,5).map(e=>`- Task ${e.id}: ${e.title} - ${e.description}`).join(`
|
|
844
848
|
`)}`,l.length>5&&(s+=`\n- ... and ${l.length-5} more indirect dependencies`)),s+=`
|
|
845
849
|
|
|
@@ -873,7 +877,7 @@ Dependency Chain Visualization:`,s+=n.map(e=>this._formatDependencyChain(e)).joi
|
|
|
873
877
|
|
|
874
878
|
`);case`system-prompt`:return e.join(` `);default:return e.join(`
|
|
875
879
|
|
|
876
|
-
`)}}},
|
|
880
|
+
`)}}},Ba=za;function Va(e){let t=[];for(let n in e)Object.prototype.hasOwnProperty.call(e,n)&&e[n]&&Array.isArray(e[n].tasks)&&(t=t.concat(e[n].tasks));return t}async function Ha(e,t,n=[],r=null,a={},s=`text`,c=null,l=!1){let{session:d,mcpLog:f,projectRoot:p,commandName:m,outputType:h,tag:g}=a,v=!!f,y=v?f:{info:(...e)=>z(`info`,...e),warn:(...e)=>z(`warn`,...e),error:(...e)=>z(`error`,...e),debug:(...e)=>z(`debug`,...e),success:(...e)=>z(`success`,...e)},x=r||ce(p)||la;if(r){let e=da(r);e?x=e:(s===`text`&&z(`warn`,`Invalid priority "${r}". Using default priority "${la}".`),x=la)}y.info(`Adding new task with prompt: "${t}", Priority: ${x}, Dependencies: ${n.join(`, `)||`None`}, Research: ${l}, ProjectRoot: ${p}`),g&&y.info(`Using tag context: ${g}`);let S=null,C=null,T=(e,t=`info`)=>{f?f[t](e):s===`text`&&z(t,e)};function E(e,t,n=new Set,r=new Map,i=0){if(n.has(t))return null;let a=e.find(e=>e.id===t);if(!a)return null;n.add(t),(!r.has(t)||i<r.get(t))&&r.set(t,i);let o=[];if(a.dependencies&&a.dependencies.length>0)for(let t of a.dependencies){let a=E(e,t,n,r,i+1);a&&o.push(a)}return{id:a.id,title:a.title,description:a.description,status:a.status,dependencies:o}}try{let r=w(e,p,g);r&&r._rawTaggedData&&(r=r._rawTaggedData),r||=(T(`tasks.json not found or invalid. Initializing new structure.`,`info`),{master:{tasks:[],metadata:{created:new Date().toISOString(),description:`Default tasks context`}}}),r&&Array.isArray(r.tasks)&&!r._rawTaggedData&&(T(`Legacy format detected. Migrating to tagged format...`,`info`),r={master:{tasks:r.tasks,metadata:r.metadata||{created:new Date().toISOString(),updated:new Date().toISOString(),description:`Tasks for master context`}}},ne(r.master,{description:`Tasks for master context`}),u(e),ee(e),T(`Successfully migrated to tagged format.`,`success`));let a=g;if(!r[a])throw T(`Tag "${a}" does not exist. Please create it first using the 'add-tag' command.`,`error`),Error(`Tag "${a}" not found.`);r[a].tasks||(r[a].tasks=[]),r[a].metadata||(r[a].metadata={created:new Date().toISOString(),updated:new Date().toISOString(),description:``});let f=Va(r),y=r[a].tasks,D=(y.length>0?Math.max(...y.map(e=>e.id)):0)+1;s===`text`&&console.log(W(B.white.bold(`Creating New Task #${D}`),{padding:1,borderColor:`blue`,borderStyle:`round`,margin:{top:1,bottom:1}}));let O=n.filter(e=>{let t=parseInt(e,10);return Number.isNaN(t)||!f.some(e=>e.id===t)});O.length>0&&(T(`The following dependencies do not exist or are invalid: ${O.join(`, `)}`,`warn`),T(`Removing invalid dependencies...`,`info`),n=n.filter(e=>!O.includes(e)));let k=n.map(e=>parseInt(e,10)),A=[],j=new Set,M=new Map;for(let e of k){let t=E(f,e,new Set,M);t&&A.push(t)}for(let[e,t]of M.entries())j.add(e);let N;if(c){if(T(`Using manually provided task data`,`info`),N=c,T(`DEBUG: Taking MANUAL task data path.`,`debug`),!N.title||typeof N.title!=`string`||!N.description||typeof N.description!=`string`)throw Error(`Manual task data must include at least a title and description.`)}else{T(`DEBUG: Taking AI task generation path.`,`debug`),T(`Generating task data with AI with prompt:\n${t}`,`info`);let e=await new Ba(p,g).gather({semanticQuery:t,dependencyTasks:k,format:`research`}),n=e.context,r=e.analysisData;s===`text`&&r&&Nl(r,t,n.length);let a=``;c?.title&&(a+=`\n- Suggested Title: "${c.title}"`),c?.description&&(a+=`\n- Suggested Description: "${c.description}"`),c?.details&&(a+=`\n- Additional Details Context: "${c.details}"`),c?.testStrategy&&(a+=`\n- Additional Test Strategy Context: "${c.testStrategy}"`);let{systemPrompt:o,userPrompt:u}=await La().loadPrompt(`add-task`,{prompt:t,newTaskId:D,existingTasks:f,gatheredContext:n,contextFromArgs:a,useResearch:l,priority:x,dependencies:k,hasCodebaseAnalysis:b(l,p,d,{command:`add-task`,prompt:t,additionalContext:a,task:{dependencies:k}}),projectRoot:p});s===`text`&&(S=_l(`Generating new task with ${l?`Research`:`Main`} AI... \n`));try{let e=l?`research`:`main`;if(T(`DEBUG: Calling generateObjectService...`,`debug`),C=await i({role:e,session:d,projectRoot:p,schema:Ta[`add-task`],objectName:`newTaskData`,systemPrompt:o,prompt:u,commandName:m||`add-task`,outputType:h||(v?`mcp`:`cli`)}),T(`DEBUG: generateObjectService returned successfully.`,`debug`),!C||!C.mainResult)throw Error(`AI service did not return the expected object structure.`);if(C.mainResult.title&&C.mainResult.description)N=C.mainResult;else if(C.mainResult.object&&C.mainResult.object.title&&C.mainResult.object.description)N=C.mainResult.object;else throw Error(`AI service did not return a valid task object.`);T(`Successfully generated task data from AI.`,`success`),S&&=(vl(S,`Task generated successfully`),null)}catch(e){throw S&&=(yl(S,`AI generation failed`),null),T(`DEBUG: generateObjectService caught error: ${e.message}`,`debug`),T(`Error generating task with AI: ${e.message}`,`error`),e}finally{T(`DEBUG: generateObjectService finally block reached.`,`debug`),S&&$(S)}}let P={id:D,title:N.title,description:N.description,details:N.details||``,testStrategy:N.testStrategy||``,status:`pending`,dependencies:N.dependencies?.length?N.dependencies:k,priority:x,subtasks:[]};if(N.dependencies?.length&&(N.dependencies.every(e=>{let t=parseInt(e,10);return!Number.isNaN(t)&&f.some(e=>e.id===t)})||(T(`AI suggested invalid dependencies. Filtering them out...`,`warn`),P.dependencies=N.dependencies.filter(e=>{let t=parseInt(e,10);return!Number.isNaN(t)&&f.some(e=>e.id===t)}))),r[a].tasks.push(P),ne(r[a],{description:`Tasks for ${a} context`}),T(`DEBUG: Writing tasks.json...`,`debug`),_(e,r,p,a),T(`DEBUG: tasks.json written.`,`debug`),s===`text`){let e=new K({head:[B.cyan.bold(`ID`),B.cyan.bold(`Title`),B.cyan.bold(`Description`)],colWidths:[5,30,50]});e.push([P.id,o(P.title,27),o(P.description,47)]),console.log(B.green(`✓ New task created successfully:`)),console.log(e.toString());let t=e=>{switch(e?.toLowerCase()){case`high`:return`red`;case`low`:return`gray`;default:return`yellow`}},n=P.dependencies.filter(e=>!k.includes(e)),r=k.filter(e=>!P.dependencies.includes(e)),i={};P.dependencies.forEach(e=>{let t=f.find(t=>t.id===e);t&&(i[e]=o(t.title,30))});let a=``;P.dependencies.length>0?(a=B.white(`Dependencies:`)+`
|
|
877
881
|
`,P.dependencies.forEach(e=>{let t=n.includes(e)?B.yellow(` (AI suggested)`):``;a+=B.white(` - ${e}: ${i[e]||`Unknown task`}${t}`)+`
|
|
878
882
|
`})):a=B.white(`Dependencies: None`)+`
|
|
879
883
|
`,r.length>0&&(a+=B.gray(`
|
|
@@ -886,58 +890,58 @@ User-specified dependencies that were not used:`)+`
|
|
|
886
890
|
`)),console.log(W(B.white.bold(`Task ${D} Created Successfully`)+`
|
|
887
891
|
|
|
888
892
|
`+B.white(`Title: ${P.title}`)+`
|
|
889
|
-
`+B.white(`Status: ${
|
|
893
|
+
`+B.white(`Status: ${xl(P.status)}`)+`
|
|
890
894
|
`+B.white(`Priority: ${B[t(P.priority)](P.priority)}`)+`
|
|
891
895
|
|
|
892
896
|
`+a+s+`
|
|
893
897
|
`+B.white.bold(`Next Steps:`)+`
|
|
894
898
|
`+B.cyan(`1. Run ${B.yellow(`task-master show ${D}`)} to see complete task details`)+`
|
|
895
899
|
`+B.cyan(`2. Run ${B.yellow(`task-master set-status --id=${D} --status=in-progress`)} to start working on it`)+`
|
|
896
|
-
`+B.cyan(`3. Run ${B.yellow(`task-master expand --id=${D}`)} to break it down into subtasks`),{padding:1,borderColor:`green`,borderStyle:`round`})),C&&C.telemetryData&&(h===`cli`||h===`text`)&&
|
|
900
|
+
`+B.cyan(`3. Run ${B.yellow(`task-master expand --id=${D}`)} to break it down into subtasks`),{padding:1,borderColor:`green`,borderStyle:`round`})),C&&C.telemetryData&&(h===`cli`||h===`text`)&&Ml(C.telemetryData,`cli`)}return T(`DEBUG: Returning new task ID: ${D} and telemetry.`,`debug`),{newTaskId:D,telemetryData:C?C.telemetryData:null,tagInfo:C?C.tagInfo:null}}catch(e){throw S&&$(S),T(`Error adding task: ${e.message}`,`error`),s===`text`&&console.error(B.red(`Error: ${e.message}`)),e}}var Ua=Ha;const Wa={research:{threshold:.5,limit:20,keys:[{name:`title`,weight:2},{name:`description`,weight:1},{name:`details`,weight:.5},{name:`dependencyTitles`,weight:.5}]},addTask:{threshold:.4,limit:15,keys:[{name:`title`,weight:2},{name:`description`,weight:1.5},{name:`details`,weight:.8},{name:`dependencyTitles`,weight:.5}]},default:{threshold:.4,limit:15,keys:[{name:`title`,weight:2},{name:`description`,weight:1.5},{name:`details`,weight:1},{name:`dependencyTitles`,weight:.5}]}},Ga=[{pattern:/(command|cli|flag)/i,label:`CLI commands`},{pattern:/(task|subtask|add)/i,label:`Task management`},{pattern:/(dependency|depend)/i,label:`Dependency handling`},{pattern:/(AI|model|prompt|research)/i,label:`AI integration`},{pattern:/(UI|display|show|interface)/i,label:`User interface`},{pattern:/(schedule|time|cron)/i,label:`Scheduling`},{pattern:/(config|setting|option)/i,label:`Configuration`},{pattern:/(test|testing|spec)/i,label:`Testing`},{pattern:/(auth|login|user)/i,label:`Authentication`},{pattern:/(database|db|data)/i,label:`Data management`},{pattern:/(api|endpoint|route)/i,label:`API development`},{pattern:/(deploy|build|release)/i,label:`Deployment`},{pattern:/(security|auth|login|user)/i,label:`Security`},{pattern:/.*/,label:`Other`}],Ka={high:.25,medium:.4,low:.6};var qa=class{constructor(e,t=`default`){this.tasks=e,this.config=Wa[t]||Wa.default,this.searchableTasks=this._prepareSearchableTasks(e),this.fuse=new gt(this.searchableTasks,{includeScore:!0,threshold:this.config.threshold,keys:this.config.keys,shouldSort:!0,useExtendedSearch:!0,limit:this.config.limit})}_prepareSearchableTasks(e){return e.map(t=>{let n=t.dependencies?.length>0?t.dependencies.map(t=>{let n=e.find(e=>e.id===t);return n?n.title:``}).filter(e=>e).join(` `):``;return{...t,dependencyTitles:n}})}_extractPromptWords(e){return e.toLowerCase().replace(/[^\w\s-]/g,` `).split(/\s+/).filter(e=>e.length>3)}findRelevantTasks(e,t={}){let{maxResults:n=8,includeRecent:r=!0,includeCategoryMatches:i=!0}=t,a=this._extractPromptWords(e),o=this.fuse.search(e),s=[];for(let e of a)if(e.length>5){let t=this.fuse.search(e);t.length>0&&s.push(...t)}let c=[...o];for(let e of s)c.some(t=>t.item.id===e.item.id)||c.push(e);let l=c.filter(e=>e.score<Ka.high).map(e=>({...e.item,score:e.score})),u=c.filter(e=>e.score>=Ka.high&&e.score<Ka.medium).map(e=>({...e.item,score:e.score})),d=c.filter(e=>e.score>=Ka.medium&&e.score<Ka.low).map(e=>({...e.item,score:e.score})),f=r?[...this.tasks].sort((e,t)=>t.id-e.id).slice(0,5):[],p=[],m=null;i&&(m=Ga.find(t=>t.pattern.test(e)),p=m?this.tasks.filter(e=>m.pattern.test(e.title)||m.pattern.test(e.description)||e.details&&m.pattern.test(e.details)).slice(0,3):[]);let h=[...l];for(let e of u)h.some(t=>t.id===e.id)||h.push(e);for(let e of d)h.some(t=>t.id===e.id)||h.push(e);for(let e of p)h.some(t=>t.id===e.id)||h.push(e);for(let e of f)h.some(t=>t.id===e.id)||h.push(e);let g=h.slice(0,n);return{results:g,breakdown:{highRelevance:l,mediumRelevance:u,lowRelevance:d,categoryTasks:p,recentTasks:f,promptCategory:m,promptWords:a},metadata:{totalSearched:this.tasks.length,fuzzyMatches:o.length,wordMatches:s.length,finalCount:g.length}}}getTaskIds(e){return e.results.map(e=>e.id.toString())}getTaskIdsWithSubtasks(e,t=!1){let n=[];for(let r of e.results)if(n.push(r.id.toString()),t&&r.subtasks&&r.subtasks.length>0)for(let e of r.subtasks)n.push(`${r.id}.${e.id}`);return n}formatSearchSummary(e,t={}){let{includeScores:n=!1,includeBreakdown:r=!1}=t,{results:i,breakdown:a,metadata:o}=e,s=`Found ${i.length} relevant tasks from ${o.totalSearched} total tasks`;if(r&&a){let e=[];a.highRelevance.length>0&&e.push(`${a.highRelevance.length} high relevance`),a.mediumRelevance.length>0&&e.push(`${a.mediumRelevance.length} medium relevance`),a.lowRelevance.length>0&&e.push(`${a.lowRelevance.length} low relevance`),a.categoryTasks.length>0&&e.push(`${a.categoryTasks.length} category matches`),e.length>0&&(s+=` (${e.join(`, `)})`),a.promptCategory&&(s+=`\nCategory detected: ${a.promptCategory.label}`)}return s}};async function Ja(e,t={}){let{session:n,mcpLog:r}=t,a=e.file||x,o=parseFloat(e.threshold||`5`),s=e.research||!1,c=e.projectRoot,l=e.tag,u=e.id?e.id.split(`,`).map(e=>parseInt(e.trim(),10)).filter(e=>!Number.isNaN(e)):null,d=e.from===void 0?null:parseInt(e.from,10),f=e.to===void 0?null:parseInt(e.to,10),p=r?`json`:`text`,m=(e,t=`info`)=>{r?r[t](e):!L()&&p===`text`&&z(t,e)},h=Ne(e.output,{projectRoot:c,tag:l},m);p===`text`&&console.log(B.blue(`Analyzing task complexity and generating expansion recommendations...`));try{m(`Reading tasks from ${a}...`,`info`);let t,g=0,_=null;if(e._filteredTasksData){if(t=e._filteredTasksData,g=e._originalTaskCount||t.tasks.length,!e._originalTaskCount)try{_=w(a,c,l),_&&_.tasks&&(g=_.tasks.length)}catch(e){z(`warn`,`Could not read original tasks file: ${e.message}`)}}else{if(_=w(a,c,l),!_||!_.tasks||!Array.isArray(_.tasks)||_.tasks.length===0)throw Error(`No tasks found in the tasks file`);g=_.tasks.length;let e=[`pending`,`blocked`,`in-progress`],n=_.tasks.filter(t=>e.includes(t.status?.toLowerCase()||`pending`));if(u&&u.length>0){if(m(`Filtering tasks by specific IDs: ${u.join(`, `)}`,`info`),n=n.filter(e=>u.includes(e.id)),p===`text`){if(n.length===0&&u.length>0)console.log(B.yellow(`Warning: No active tasks found with IDs: ${u.join(`, `)}`));else if(n.length<u.length){let e=n.map(e=>e.id),t=u.filter(t=>!e.includes(t));console.log(B.yellow(`Warning: Some requested task IDs were not found or are not active: ${t.join(`, `)}`))}}}else if(d!==null||f!==null){let e=d===null?1:d,t=f===null?Math.max(..._.tasks.map(e=>e.id)):f;m(`Filtering tasks by ID range: ${e} to ${t}`,`info`),n=n.filter(n=>n.id>=e&&n.id<=t),p===`text`&&n.length===0&&console.log(B.yellow(`Warning: No active tasks found in range: ${e}-${t}`))}t={..._,tasks:n,_originalTaskCount:g}}let v=``;if(_&&_.tasks.length>0)try{let e=new za(c,l),n=new qa(ke(_.tasks),`analyze-complexity`),r=t.tasks.map(e=>`${e.title} ${e.description}`).join(` `),i=n.findRelevantTasks(r,{maxResults:10}),a=n.getTaskIds(i);a.length>0&&(v=(await e.gather({tasks:a,format:`research`})).context||``)}catch(e){m(`Could not gather additional context: ${e.message}`,`warn`)}let y=g-t.tasks.length;if(m(`Found ${g} total tasks in the task file.`,`info`),u||d!==null||f!==null){let e=u?`Analyzing ${t.tasks.length} tasks with specific IDs: ${u.join(`, `)}`:`Analyzing ${t.tasks.length} tasks in range: ${d||1} to ${f||`end`}`;m(e,`info`),p===`text`&&console.log(B.blue(e))}else if(y>0){let e=`Skipping ${y} tasks marked as done/cancelled/deferred. Analyzing ${t.tasks.length} active tasks.`;m(e,`info`),p===`text`&&console.log(B.yellow(e))}let x=null,S=new Map;try{V.existsSync(h)&&(x=JSON.parse(V.readFileSync(h,`utf8`)),m(`Found existing complexity report at ${h}`,`info`),x&&x.complexityAnalysis&&Array.isArray(x.complexityAnalysis)&&(x.complexityAnalysis.forEach(e=>{S.set(e.taskId,e)}),m(`Existing report contains ${x.complexityAnalysis.length} task analyses`,`info`)))}catch(e){m(`Warning: Could not read existing report: ${e.message}`,`warn`),x=null,S.clear()}if(t.tasks.length===0){if(x&&(u||d!==null||f!==null))return m(`No matching tasks found for analysis. Keeping existing report.`,`info`),p===`text`&&console.log(B.yellow(`No matching tasks found for analysis. Keeping existing report.`)),{report:x,telemetryData:null};let e={meta:{generatedAt:new Date().toISOString(),tasksAnalyzed:0,thresholdScore:o,projectName:ge(n),usedResearch:s},complexityAnalysis:x?.complexityAnalysis||[]};return m(`Writing complexity report to ${h}...`,`info`),V.writeFileSync(h,JSON.stringify(e,null,` `),`utf8`),m(`Task complexity analysis complete. Report written to ${h}`,`success`),p===`text`&&(console.log(B.green(`Task complexity analysis complete. Report written to ${h}`)),console.log(`
|
|
897
901
|
Complexity Analysis Summary:`),console.log(`----------------------------`),console.log(`Tasks in input file: ${g}`),console.log(`Tasks successfully analyzed: 0`),console.log(`High complexity tasks: 0`),console.log(`Medium complexity tasks: 0`),console.log(`Low complexity tasks: 0`),console.log(`Sum verification: 0 (should equal 0)`),console.log(`Research-backed analysis: ${s?`Yes`:`No`}`),console.log(`\nSee ${h} for the full report and expansion commands.`),console.log(W(B.white.bold(`Suggested Next Steps:`)+`
|
|
898
902
|
|
|
899
|
-
${B.cyan(`1.`)} Run ${B.yellow(`task-master complexity-report`)} to review detailed findings\n${B.cyan(`2.`)} Run ${B.yellow(`task-master expand --id=<id>`)} to break down complex tasks\n${B.cyan(`3.`)} Run ${B.yellow(`task-master expand --all`)} to expand all pending tasks based on complexity`,{padding:1,borderColor:`cyan`,borderStyle:`round`,margin:{top:1}}))),{report:e,telemetryData:null}}let C=
|
|
903
|
+
${B.cyan(`1.`)} Run ${B.yellow(`task-master complexity-report`)} to review detailed findings\n${B.cyan(`2.`)} Run ${B.yellow(`task-master expand --id=<id>`)} to break down complex tasks\n${B.cyan(`3.`)} Run ${B.yellow(`task-master expand --all`)} to expand all pending tasks based on complexity`,{padding:1,borderColor:`cyan`,borderStyle:`round`,margin:{top:1}}))),{report:e,telemetryData:null}}let C=La(),T={tasks:t.tasks,gatheredContext:v||``,useResearch:s,hasCodebaseAnalysis:b(s,c,n,{command:`analyze-complexity`,tasks:t.tasks}),projectRoot:c||``},{systemPrompt:E,userPrompt:D}=await C.loadPrompt(`analyze-complexity`,T,`default`),O=null;p===`text`&&(O=_l(`${s?`Researching`:`Analyzing`} the complexity of your tasks with AI...\n`));let k=null,A=null;try{k=await i({prompt:D,systemPrompt:E,role:s?`research`:`main`,session:n,projectRoot:c,schema:Ta[`analyze-complexity`],objectName:`complexityAnalysis`,commandName:`analyze-complexity`,outputType:r?`mcp`:`cli`}),O&&=($(O),null),p===`text`&&(nt.clearLine(process.stdout,0),nt.cursorTo(process.stdout,0),console.log(B.green(`AI service call complete.`))),A=k.mainResult?.complexityAnalysis,m(`Received ${A.length} complexity analyses from AI.`,`info`);let e=t.tasks.map(e=>e.id),a=A.map(e=>e.taskId),l=e.filter(e=>!a.includes(e));if(l.length>0){m(`Missing analysis for ${l.length} tasks: ${l.join(`, `)}`,`warn`),p===`text`&&console.log(B.yellow(`Missing analysis for ${l.length} tasks: ${l.join(`, `)}`));for(let e of l){let n=t.tasks.find(t=>t.id===e);n&&(m(`Adding default analysis for task ${e}`,`info`),A.push({taskId:e,taskTitle:n.title,complexityScore:5,recommendedSubtasks:3,expansionPrompt:`Break down this task with a focus on ${n.title.toLowerCase()}.`,reasoning:`Automatically added due to missing analysis in AI response.`}))}}let u=[];if(x&&Array.isArray(x.complexityAnalysis)){let e=new Set(A.map(e=>e.taskId)),n=new Set(t.tasks.map(e=>e.id)),r=x.complexityAnalysis.filter(t=>!e.has(t.taskId)&&n.has(t.taskId));u=[...r,...A],m(`Merged ${A.length} new analyses with ${r.length} existing entries from current tag`,`info`)}else u=A;let d={meta:{generatedAt:new Date().toISOString(),tasksAnalyzed:t.tasks.length,totalTasks:g,analysisCount:u.length,thresholdScore:o,projectName:ge(n),usedResearch:s},complexityAnalysis:u};if(m(`Writing complexity report to ${h}...`,`info`),V.writeFileSync(h,JSON.stringify(d,null,` `),`utf8`),m(`Task complexity analysis complete. Report written to ${h}`,`success`),p===`text`){console.log(B.green(`Task complexity analysis complete. Report written to ${h}`));let e=A.filter(e=>e.complexityScore>=8).length,t=A.filter(e=>e.complexityScore>=5&&e.complexityScore<8).length,r=A.filter(e=>e.complexityScore<5).length,i=A.length;console.log(`
|
|
900
904
|
Current Analysis Summary:`),console.log(`----------------------------`),console.log(`Tasks analyzed in this run: ${i}`),console.log(`High complexity tasks: ${e}`),console.log(`Medium complexity tasks: ${t}`),console.log(`Low complexity tasks: ${r}`),x&&(console.log(`
|
|
901
905
|
Updated Report Summary:`),console.log(`----------------------------`),console.log(`Total analyses in report: ${u.length}`),console.log(`Analyses from previous runs: ${u.length-i}`),console.log(`New/updated analyses: ${i}`)),console.log(`Research-backed analysis: ${s?`Yes`:`No`}`),console.log(`\nSee ${h} for the full report and expansion commands.`),console.log(W(B.white.bold(`Suggested Next Steps:`)+`
|
|
902
906
|
|
|
903
|
-
${B.cyan(`1.`)} Run ${B.yellow(`task-master complexity-report`)} to review detailed findings\n${B.cyan(`2.`)} Run ${B.yellow(`task-master expand --id=<id>`)} to break down complex tasks\n${B.cyan(`3.`)} Run ${B.yellow(`task-master expand --all`)} to expand all pending tasks based on complexity`,{padding:1,borderColor:`cyan`,borderStyle:`round`,margin:{top:1}})),be(n)&&console.debug(B.gray(`Final analysis object: ${JSON.stringify(d,null,2)}`)),k.telemetryData&&
|
|
904
|
-
Please ensure your API keys are correctly configured in .env or ~/.taskmaster/.env`)),console.log(B.yellow(`Run 'task-master models --setup' if needed.`)))),e}}catch(e){if(m(`Error analyzing task complexity: ${e.message}`,`error`),p===`text`)console.error(B.red(`Error analyzing task complexity: ${e.message}`)),be(n)&&console.error(e),process.exit(1);else throw e}}var
|
|
907
|
+
${B.cyan(`1.`)} Run ${B.yellow(`task-master complexity-report`)} to review detailed findings\n${B.cyan(`2.`)} Run ${B.yellow(`task-master expand --id=<id>`)} to break down complex tasks\n${B.cyan(`3.`)} Run ${B.yellow(`task-master expand --all`)} to expand all pending tasks based on complexity`,{padding:1,borderColor:`cyan`,borderStyle:`round`,margin:{top:1}})),be(n)&&console.debug(B.gray(`Final analysis object: ${JSON.stringify(d,null,2)}`)),k.telemetryData&&Ml(k.telemetryData,`cli`)}return{report:d,telemetryData:k?.telemetryData,tagInfo:k?.tagInfo}}catch(e){throw O&&$(O),m(`Error during AI service call: ${e.message}`,`error`),p===`text`&&(console.error(B.red(`Error during AI service call: ${e.message}`)),e.message.includes(`API key`)&&(console.log(B.yellow(`
|
|
908
|
+
Please ensure your API keys are correctly configured in .env or ~/.taskmaster/.env`)),console.log(B.yellow(`Run 'task-master models --setup' if needed.`)))),e}}catch(e){if(m(`Error analyzing task complexity: ${e.message}`,`error`),p===`text`)console.error(B.red(`Error analyzing task complexity: ${e.message}`)),be(n)&&console.error(e),process.exit(1);else throw e}}var Ya=Ja;function Xa(e,t,n={}){let{projectRoot:r,tag:i}=n;z(`info`,`Reading tasks from ${e}...`);let a=w(e,r,i);(!a||!a.tasks)&&(z(`error`,`No valid tasks found.`),process.exit(1)),L()||console.log(W(B.white.bold(`Clearing Subtasks`),{padding:1,borderColor:`blue`,borderStyle:`round`,margin:{top:1,bottom:1}}));let s=t.split(`,`).map(e=>e.trim()),c=0,l=new K({head:[B.cyan.bold(`Task ID`),B.cyan.bold(`Task Title`),B.cyan.bold(`Subtasks Cleared`)],colWidths:[10,50,20],style:{head:[],border:[]}});s.forEach(e=>{let t=parseInt(e,10);if(Number.isNaN(t)){z(`error`,`Invalid task ID: ${e}`);return}let n=a.tasks.find(e=>e.id===t);if(!n){z(`error`,`Task ${t} not found`);return}if(!n.subtasks||n.subtasks.length===0){z(`info`,`Task ${t} has no subtasks to clear`),l.push([t.toString(),o(n.title,47),B.yellow(`No subtasks`)]);return}let r=n.subtasks.length;n.subtasks=[],c++,z(`info`,`Cleared ${r} subtasks from task ${t}`),l.push([t.toString(),o(n.title,47),B.green(`${r} subtasks cleared`)])}),c>0?(_(e,a,r,i),L()||(console.log(W(B.white.bold(`Subtask Clearing Summary:`),{padding:{left:2,right:2,top:0,bottom:0},margin:{top:1,bottom:0},borderColor:`blue`,borderStyle:`round`})),console.log(l.toString())),L()||(console.log(W(B.green(`Successfully cleared subtasks from ${B.bold(c)} task(s)`),{padding:1,borderColor:`green`,borderStyle:`round`,margin:{top:1}})),console.log(W(B.white.bold(`Next Steps:`)+`
|
|
905
909
|
|
|
906
|
-
${B.cyan(`1.`)} Run ${B.yellow(`task-master expand --id=<id>`)} to generate new subtasks\n${B.cyan(`2.`)} Run ${B.yellow(`task-master list --with-subtasks`)} to verify changes`,{padding:1,borderColor:`cyan`,borderStyle:`round`,margin:{top:1}})))):L()||console.log(W(B.yellow(`No subtasks were cleared`),{padding:1,borderColor:`yellow`,borderStyle:`round`,margin:{top:1}}))}var Ja=qa;function Ya(e,t){let n=!!e,r=e||{info:e=>!L()&&z(`info`,e),warn:e=>!L()&&z(`warn`,e),error:e=>!L()&&z(`error`,e),debug:e=>!L()&&be(t)&&z(`debug`,e)};return{logger:r,report:(e,...t)=>{n?typeof r[e]==`function`?r[e](...t):r.info(...t):L()||z(e,...t)},isMCP:n}}async function Xa(e,t,n,r=!1,a=``,o={},s=!1){let{session:c,mcpLog:l,projectRoot:u,tag:d,complexityReportPath:f}=o,p=l?`json`:`text`,m=u||Fe(e),{logger:h,report:v,isMCP:y}=Ya(l,c);y&&h.info(`expandTask called with context: session=${!!c}`);try{let o=r?g(m):Re(m);if(new Set([`claude-code`,`gemini-cli`,`grok-cli`,`codex-cli`]).has(o))h.info(`Skipping remote expansion bridge for local CLI provider: ${o}`);else{let e=await Ur({taskId:t,numSubtasks:n,useResearch:r,additionalContext:a,force:s,projectRoot:m,tag:d,isMCP:y,outputFormat:p,report:v});if(e)return e}h.info(`Reading tasks from ${e}`);let l=w(e,m,d);if(!l||!l.tasks)throw Error(`Invalid tasks data in ${e}`);let u=l.tasks.findIndex(e=>e.id===parseInt(t,10));if(u===-1)throw Error(`Task ${t} not found`);let x=l.tasks[u];h.info(`Expanding task ${t}: ${x.title}${r?` with research`:``}`),s&&Array.isArray(x.subtasks)&&x.subtasks.length>0&&(h.info(`Force flag set. Clearing existing ${x.subtasks.length} subtasks for task ${t}.`),x.subtasks=[]);let S=``;try{let e=new Ia(m,d),n=new Wa(ke(l.tasks),`expand-task`),r=`${x.title} ${x.description}`,i=n.findRelevantTasks(r,{maxResults:5,includeSelf:!0}),a=n.getTaskIds(i),o=[...new Set([t.toString(),...a])];o.length>0&&(S=(await e.gather({tasks:o,format:`research`})).context||``)}catch(e){h.warn(`Could not gather context: ${e.message}`)}let C,T=``,E=null;h.info(`Looking for complexity report at: ${f}${d===`master`?``:` (tag-specific for '${d}')`}`);try{V.existsSync(f)?(E=w(f)?.complexityAnalysis?.find(e=>e.taskId===x.id),E?(h.info(`Found complexity analysis for task ${x.id}: Score ${E.complexityScore}`),E.reasoning&&(T=`\nComplexity Analysis Reasoning: ${E.reasoning}`)):h.info(`No complexity analysis found for task ${x.id} in report.`)):h.info(`Complexity report not found at ${f}. Skipping complexity check.`)}catch(e){h.warn(`Could not read or parse complexity report: ${e.message}. Proceeding without it.`)}let D=parseInt(n,10);!Number.isNaN(D)&&D>=0?(C=D,h.info(`Using explicitly provided subtask count: ${C}`)):E?.recommendedSubtasks?(C=parseInt(E.recommendedSubtasks,10),h.info(`Using subtask count from complexity report: ${C}`)):(C=j(c),h.info(`Using default number of subtasks: ${C}`)),(Number.isNaN(C)||C<0)&&(h.warn(`Invalid subtask count determined (${C}), defaulting to 3.`),C=3);let O=(x.subtasks?.length||0)+1,k=Pa(),A=b(r,m,c,{command:`expand-task`,task:x,additionalContext:a,complexityReasoningContext:T,numTasks:C}),M=``;(a||T)&&(M=`\n\n${a}${T}`.trim()),S&&(M=`${M}\n\n# Project Context\n\n${S}`.trim());let N;E?.expansionPrompt&&(typeof E.expansionPrompt==`string`?N=E.expansionPrompt:typeof E.expansionPrompt==`object`&&E.expansionPrompt.text&&(N=E.expansionPrompt.text));let P=S;typeof S==`object`&&S&&(P=S.data?S.data:S.text?S.text:JSON.stringify(S));let ee={task:x,subtaskCount:C,nextSubtaskId:O,additionalContext:a,complexityReasoningContext:T,gatheredContext:P||``,useResearch:r,expansionPrompt:N||void 0,hasCodebaseAnalysis:A,projectRoot:m||``},te=`default`;N?(te=`complexity-report`,h.info(`Using expansion prompt from complexity report for task ${x.id}.`)):r?(te=`research`,h.info(`Using research variant for task ${x.id}.`)):h.info(`Using standard prompt generation for task ${x.id}.`);let{systemPrompt:ne,userPrompt:re}=k.loadPrompt(`expand-task`,ee,te);h.debug(`Selected variant: ${te}`),h.debug(`Prompt params passed: ${JSON.stringify(ee,null,2)}`),h.debug(`System prompt (first 500 chars): ${ne.substring(0,500)}...`),h.debug(`User prompt (first 500 chars): ${re.substring(0,500)}...`);let ie=[],ae=null;p===`text`&&(ae=ml(`Generating ${C||`appropriate number of`} subtasks...\n`));let F=null;try{F=await i({prompt:re,systemPrompt:ne,role:r?`research`:`main`,session:c,projectRoot:m,schema:Sa[`expand-task`],objectName:`subtasks`,commandName:`expand-task`,outputType:p});let e=F?.mainResult;if(!e||!Array.isArray(e.subtasks))throw Error(`AI response did not include a valid subtasks array.`);ie=e.subtasks.map(e=>({...e,dependencies:e.dependencies??[],status:e.status??`pending`,testStrategy:e.testStrategy??null})),h.info(`Received ${ie.length} subtasks from AI.`)}catch(e){throw ae&&$(ae),h.error(`Error during AI call or parsing for task ${t}: ${e.message}`,`error`),e}finally{ae&&$(ae)}return Array.isArray(x.subtasks)||(x.subtasks=[]),x.subtasks.push(...ie),l.tasks[u]=x,_(e,l,m,d),p===`text`&&F&&F.telemetryData&&kl(F.telemetryData,`cli`),{task:x,telemetryData:F?.telemetryData,tagInfo:F?.tagInfo}}catch(e){throw h.error(`Error expanding task ${t}: ${e.message}`,`error`),p===`text`&&be(c)&&console.error(e),e}}var Za=Xa;async function Qa(e,t,n=!1,r=``,i=!1,a={},o=`text`){let{session:s,mcpLog:c,projectRoot:l,tag:u,complexityReportPath:d}=a,f=!!c,p=l||Fe();if(!p)throw Error(`Could not determine project root directory`);let m=c||(o===`json`?{info:e=>{},warn:e=>{},error:e=>console.error(`ERROR: ${e}`),debug:e=>{}}:{info:e=>!L()&&z(`info`,e),warn:e=>!L()&&z(`warn`,e),error:e=>!L()&&z(`error`,e),debug:e=>!L()&&be(s)&&z(`debug`,e)}),h=null,g=0,_=0,v=0,y=[];!f&&o===`text`&&(h=ml(`Analyzing tasks for expansion...`));try{m.info(`Reading tasks from ${e}`);let s=w(e,p,u);if(!s||!s.tasks)throw Error(`Invalid tasks data in ${e}`);let c=s.tasks.filter(e=>(e.status===`pending`||e.status===`in-progress`)&&(!e.subtasks||e.subtasks.length===0||i));if(v=c.length,m.info(`Found ${v} tasks eligible for expansion.`),h&&$(h,`Analysis complete.`),v===0)return m.info(`No tasks eligible for expansion.`),{success:!0,expandedCount:0,failedCount:0,skippedCount:0,tasksToExpand:0,telemetryData:y,message:`No tasks eligible for expansion.`};for(let l of c){let c=null;!f&&o===`text`&&(c=ml(`Expanding task ${l.id}...`));try{let o=await Za(e,l.id,t,n,r,{...a,projectRoot:p,tag:s.tag||u,complexityReportPath:d},i);g++,o&&o.telemetryData&&y.push(o.telemetryData),c&&$(c,`Task ${l.id} expanded.`),m.info(`Successfully expanded task ${l.id}.`)}catch(e){_++,c&&$(c,`Failed to expand task ${l.id}.`,!1),m.error(`Failed to expand task ${l.id}: ${e.message}`)}}m.info(`Expansion complete: ${g} expanded, ${_} failed.`);let l=me(y,`expand-all-tasks`);if(o===`text`){let e=`${B.white.bold(`Expansion Summary:`)}\n\n${B.cyan(`-`)} Attempted: ${B.bold(v)}\n${B.green(`-`)} Expanded: ${B.bold(g)}\n${B.gray(`-`)} Skipped: ${B.bold(0)}\n${B.red(`-`)} Failed: ${B.bold(_)}`;console.log(W(e,{padding:1,margin:{top:1},borderColor:_>0?`red`:`green`,borderStyle:`round`}))}return o===`text`&&l&&kl(l,`cli`),{success:!0,expandedCount:g,failedCount:_,skippedCount:0,tasksToExpand:v,telemetryData:l}}catch(e){throw h&&$(h,`Error.`,!1),m.error(`Error during expand all operation: ${e.message}`),!f&&be(s)&&console.error(e),e}}var $a=Qa;function eo(e,t,n){if(t.parentTaskId===n||t.dependencies&&t.dependencies.includes(n))return!0;if(t.dependencies)for(let r of t.dependencies){let t=e.find(e=>e.id===r);if(t&&eo(e,t,n))return!0}if(t.subtasks){for(let r of t.subtasks)if(eo(e,r,n))return!0}return!1}var to=eo;async function no(e,t,n=null,r=!1,i=`text`,a={}){let{projectRoot:s,tag:c}=a;try{let a;try{let e=await(await I({projectPath:s||process.cwd()})).tasks.list({tag:c});a={tasks:e.tasks},z(`debug`,`Loaded ${e.tasks.length} tasks via tm-core (${e.storageType} storage)`)}catch(t){z(`warn`,`TmCore failed, falling back to legacy readJSON: ${t.message}`),a=w(e,s,c)}if(!a||!a.tasks)throw Error(`No valid tasks found in ${e}`);let l=Be(n);l&&l.complexityAnalysis&&a.tasks.forEach(e=>je(e,l));let u;if(t&&t.toLowerCase()!==`all`){let e=t.split(`,`).map(e=>e.trim().toLowerCase()).filter(e=>e.length>0);u=a.tasks.filter(t=>t.status&&e.includes(t.status.toLowerCase()))}else u=a.tasks;let d=a.tasks.length,f=a.tasks.filter(e=>e.status===`done`||e.status===`completed`).length,p=d>0?f/d*100:0,m=f,h=a.tasks.filter(e=>e.status===`in-progress`).length,g=a.tasks.filter(e=>e.status===`pending`).length,_=a.tasks.filter(e=>e.status===`blocked`).length,v=a.tasks.filter(e=>e.status===`deferred`).length,y=a.tasks.filter(e=>e.status===`cancelled`).length,b=a.tasks.filter(e=>e.status===`review`).length,x=0,S=0,C=0,T=0,E=0,D=0,O=0,k=0;a.tasks.forEach(e=>{e.subtasks&&e.subtasks.length>0&&(x+=e.subtasks.length,S+=e.subtasks.filter(e=>e.status===`done`||e.status===`completed`).length,C+=e.subtasks.filter(e=>e.status===`in-progress`).length,T+=e.subtasks.filter(e=>e.status===`pending`).length,E+=e.subtasks.filter(e=>e.status===`blocked`).length,D+=e.subtasks.filter(e=>e.status===`deferred`).length,O+=e.subtasks.filter(e=>e.status===`cancelled`).length,k+=e.subtasks.filter(e=>e.status===`review`).length)});let A=x>0?S/x*100:0,j=new Set(a.tasks.filter(e=>e.status===`done`||e.status===`completed`).map(e=>e.id)),M=a.tasks.filter(e=>e.status!==`done`&&e.status!==`completed`&&(!e.dependencies||e.dependencies.length===0)).length,N=a.tasks.filter(e=>e.status!==`done`&&e.status!==`completed`&&e.dependencies&&e.dependencies.length>0&&e.dependencies.every(e=>j.has(e))).length,P=a.tasks.filter(e=>e.status!==`done`&&e.status!==`completed`&&e.dependencies&&e.dependencies.length>0&&!e.dependencies.every(e=>j.has(e))).length,ee=M+N,te={};a.tasks.forEach(e=>{e.dependencies&&e.dependencies.length>0&&e.dependencies.forEach(e=>{te[e]=(te[e]||0)+1})});let ne=null,re=0;for(let[e,t]of Object.entries(te))t>re&&(re=t,ne=parseInt(e));let ie=ne===null?null:a.tasks.find(e=>e.id===ne),ae=a.tasks.reduce((e,t)=>e+(t.dependencies?t.dependencies.length:0),0)/a.tasks.length,F=Jr(a.tasks,l);if(i===`json`)return{tasks:u.map(e=>{let{details:t,...n}=e;return n.subtasks&&Array.isArray(n.subtasks)&&(n.subtasks=n.subtasks.map(e=>{let{details:t,...n}=e;return n})),n}),filter:t||`all`,stats:{total:d,completed:m,inProgress:h,pending:g,blocked:_,deferred:v,cancelled:y,review:b,completionPercentage:p,subtasks:{total:x,completed:S,inProgress:C,pending:T,blocked:E,deferred:D,cancelled:O,completionPercentage:A}}};if(i===`markdown-readme`)return io(a,u,{totalTasks:d,completedTasks:f,completionPercentage:p,doneCount:m,inProgressCount:h,pendingCount:g,blockedCount:_,deferredCount:v,cancelledCount:y,totalSubtasks:x,completedSubtasks:S,subtaskCompletionPercentage:A,inProgressSubtasks:C,pendingSubtasks:T,blockedSubtasks:E,deferredSubtasks:D,cancelledSubtasks:O,reviewSubtasks:k,tasksWithNoDeps:M,tasksReadyToWork:ee,tasksWithUnsatisfiedDeps:P,mostDependedOnTask:ie,mostDependedOnTaskId:ne,maxDependents:re,avgDependenciesPerTask:ae,complexityReport:l,withSubtasks:r,nextItem:F});if(i===`compact`)return co(u,r);let oe={"in-progress":d>0?h/d*100:0,pending:d>0?g/d*100:0,blocked:d>0?_/d*100:0,deferred:d>0?v/d*100:0,cancelled:d>0?y/d*100:0,review:d>0?b/d*100:0},se={"in-progress":x>0?C/x*100:0,pending:x>0?T/x*100:0,blocked:x>0?E/x*100:0,deferred:x>0?D/x*100:0,cancelled:x>0?O/x*100:0,review:x>0?k/x*100:0},ce=_l(p,30,oe),le=_l(A,30,se),ue;try{ue=process.stdout.columns}catch{z(`debug`,`Could not determine terminal width, using default`)}ue||=80,ue=Math.max(ue,80);let de=B.white.bold(`Project Dashboard`)+`
|
|
910
|
+
${B.cyan(`1.`)} Run ${B.yellow(`task-master expand --id=<id>`)} to generate new subtasks\n${B.cyan(`2.`)} Run ${B.yellow(`task-master list --with-subtasks`)} to verify changes`,{padding:1,borderColor:`cyan`,borderStyle:`round`,margin:{top:1}})))):L()||console.log(W(B.yellow(`No subtasks were cleared`),{padding:1,borderColor:`yellow`,borderStyle:`round`,margin:{top:1}}))}var Za=Xa;function Qa(e,t){let n=!!e,r=e||{info:e=>!L()&&z(`info`,e),warn:e=>!L()&&z(`warn`,e),error:e=>!L()&&z(`error`,e),debug:e=>!L()&&be(t)&&z(`debug`,e)};return{logger:r,report:(e,...t)=>{n?typeof r[e]==`function`?r[e](...t):r.info(...t):L()||z(e,...t)},isMCP:n}}async function $a(e,t,n,r=!1,a=``,o={},s=!1){let{session:c,mcpLog:l,projectRoot:u,tag:d,complexityReportPath:f}=o,p=l?`json`:`text`,m=u||Fe(e),{logger:h,report:v,isMCP:y}=Qa(l,c);y&&h.info(`expandTask called with context: session=${!!c}`);try{let o=r?g(m):Re(m);if(new Set([`claude-code`,`gemini-cli`,`grok-cli`,`codex-cli`]).has(o))h.info(`Skipping remote expansion bridge for local CLI provider: ${o}`);else{let e=await Ur({taskId:t,numSubtasks:n,useResearch:r,additionalContext:a,force:s,projectRoot:m,tag:d,isMCP:y,outputFormat:p,report:v});if(e)return e}h.info(`Reading tasks from ${e}`);let l=w(e,m,d);if(!l||!l.tasks)throw Error(`Invalid tasks data in ${e}`);let u=l.tasks.findIndex(e=>e.id===parseInt(t,10));if(u===-1)throw Error(`Task ${t} not found`);let x=l.tasks[u];h.info(`Expanding task ${t}: ${x.title}${r?` with research`:``}`),s&&Array.isArray(x.subtasks)&&x.subtasks.length>0&&(h.info(`Force flag set. Clearing existing ${x.subtasks.length} subtasks for task ${t}.`),x.subtasks=[]);let S=``;try{let e=new za(m,d),n=new qa(ke(l.tasks),`expand-task`),r=`${x.title} ${x.description}`,i=n.findRelevantTasks(r,{maxResults:5,includeSelf:!0}),a=n.getTaskIds(i),o=[...new Set([t.toString(),...a])];o.length>0&&(S=(await e.gather({tasks:o,format:`research`})).context||``)}catch(e){h.warn(`Could not gather context: ${e.message}`)}let C,T=``,E=null;h.info(`Looking for complexity report at: ${f}${d===`master`?``:` (tag-specific for '${d}')`}`);try{V.existsSync(f)?(E=w(f)?.complexityAnalysis?.find(e=>e.taskId===x.id),E?(h.info(`Found complexity analysis for task ${x.id}: Score ${E.complexityScore}`),E.reasoning&&(T=`\nComplexity Analysis Reasoning: ${E.reasoning}`)):h.info(`No complexity analysis found for task ${x.id} in report.`)):h.info(`Complexity report not found at ${f}. Skipping complexity check.`)}catch(e){h.warn(`Could not read or parse complexity report: ${e.message}. Proceeding without it.`)}let D=parseInt(n,10);!Number.isNaN(D)&&D>=0?(C=D,h.info(`Using explicitly provided subtask count: ${C}`)):E?.recommendedSubtasks?(C=parseInt(E.recommendedSubtasks,10),h.info(`Using subtask count from complexity report: ${C}`)):(C=j(c),h.info(`Using default number of subtasks: ${C}`)),(Number.isNaN(C)||C<0)&&(h.warn(`Invalid subtask count determined (${C}), defaulting to 3.`),C=3);let O=(x.subtasks?.length||0)+1,k=La(),A=b(r,m,c,{command:`expand-task`,task:x,additionalContext:a,complexityReasoningContext:T,numTasks:C}),M=``;(a||T)&&(M=`\n\n${a}${T}`.trim()),S&&(M=`${M}\n\n# Project Context\n\n${S}`.trim());let N;E?.expansionPrompt&&(typeof E.expansionPrompt==`string`?N=E.expansionPrompt:typeof E.expansionPrompt==`object`&&E.expansionPrompt.text&&(N=E.expansionPrompt.text));let P=S;typeof S==`object`&&S&&(P=S.data?S.data:S.text?S.text:JSON.stringify(S));let ee={task:x,subtaskCount:C,nextSubtaskId:O,additionalContext:a,complexityReasoningContext:T,gatheredContext:P||``,useResearch:r,expansionPrompt:N||void 0,hasCodebaseAnalysis:A,projectRoot:m||``},te=`default`;N?(te=`complexity-report`,h.info(`Using expansion prompt from complexity report for task ${x.id}.`)):r?(te=`research`,h.info(`Using research variant for task ${x.id}.`)):h.info(`Using standard prompt generation for task ${x.id}.`);let{systemPrompt:ne,userPrompt:re}=k.loadPrompt(`expand-task`,ee,te);h.debug(`Selected variant: ${te}`),h.debug(`Prompt params passed: ${JSON.stringify(ee,null,2)}`),h.debug(`System prompt (first 500 chars): ${ne.substring(0,500)}...`),h.debug(`User prompt (first 500 chars): ${re.substring(0,500)}...`);let ie=[],ae=null;p===`text`&&(ae=_l(`Generating ${C||`appropriate number of`} subtasks...\n`));let F=null;try{F=await i({prompt:re,systemPrompt:ne,role:r?`research`:`main`,session:c,projectRoot:m,schema:Ta[`expand-task`],objectName:`subtasks`,commandName:`expand-task`,outputType:p});let e=F?.mainResult;if(!e||!Array.isArray(e.subtasks))throw Error(`AI response did not include a valid subtasks array.`);ie=e.subtasks.map(e=>({...e,dependencies:e.dependencies??[],status:e.status??`pending`,testStrategy:e.testStrategy??null})),h.info(`Received ${ie.length} subtasks from AI.`)}catch(e){throw ae&&$(ae),h.error(`Error during AI call or parsing for task ${t}: ${e.message}`,`error`),e}finally{ae&&$(ae)}return Array.isArray(x.subtasks)||(x.subtasks=[]),x.subtasks.push(...ie),l.tasks[u]=x,_(e,l,m,d),p===`text`&&F&&F.telemetryData&&Ml(F.telemetryData,`cli`),{task:x,telemetryData:F?.telemetryData,tagInfo:F?.tagInfo}}catch(e){throw h.error(`Error expanding task ${t}: ${e.message}`,`error`),p===`text`&&be(c)&&console.error(e),e}}var eo=$a;async function to(e,t,n=!1,r=``,i=!1,a={},o=`text`){let{session:s,mcpLog:c,projectRoot:l,tag:u,complexityReportPath:d}=a,f=!!c,p=l||Fe();if(!p)throw Error(`Could not determine project root directory`);let m=c||(o===`json`?{info:e=>{},warn:e=>{},error:e=>console.error(`ERROR: ${e}`),debug:e=>{}}:{info:e=>!L()&&z(`info`,e),warn:e=>!L()&&z(`warn`,e),error:e=>!L()&&z(`error`,e),debug:e=>!L()&&be(s)&&z(`debug`,e)}),h=null,g=0,_=0,v=0,y=[];!f&&o===`text`&&(h=_l(`Analyzing tasks for expansion...`));try{m.info(`Reading tasks from ${e}`);let s=w(e,p,u);if(!s||!s.tasks)throw Error(`Invalid tasks data in ${e}`);let c=s.tasks.filter(e=>(e.status===`pending`||e.status===`in-progress`)&&(!e.subtasks||e.subtasks.length===0||i));if(v=c.length,m.info(`Found ${v} tasks eligible for expansion.`),h&&$(h,`Analysis complete.`),v===0)return m.info(`No tasks eligible for expansion.`),{success:!0,expandedCount:0,failedCount:0,skippedCount:0,tasksToExpand:0,telemetryData:y,message:`No tasks eligible for expansion.`};for(let l of c){let c=null;!f&&o===`text`&&(c=_l(`Expanding task ${l.id}...`));try{let o=await eo(e,l.id,t,n,r,{...a,projectRoot:p,tag:s.tag||u,complexityReportPath:d},i);g++,o&&o.telemetryData&&y.push(o.telemetryData),c&&$(c,`Task ${l.id} expanded.`),m.info(`Successfully expanded task ${l.id}.`)}catch(e){_++,c&&$(c,`Failed to expand task ${l.id}.`,!1),m.error(`Failed to expand task ${l.id}: ${e.message}`)}}m.info(`Expansion complete: ${g} expanded, ${_} failed.`);let l=me(y,`expand-all-tasks`);if(o===`text`){let e=`${B.white.bold(`Expansion Summary:`)}\n\n${B.cyan(`-`)} Attempted: ${B.bold(v)}\n${B.green(`-`)} Expanded: ${B.bold(g)}\n${B.gray(`-`)} Skipped: ${B.bold(0)}\n${B.red(`-`)} Failed: ${B.bold(_)}`;console.log(W(e,{padding:1,margin:{top:1},borderColor:_>0?`red`:`green`,borderStyle:`round`}))}return o===`text`&&l&&Ml(l,`cli`),{success:!0,expandedCount:g,failedCount:_,skippedCount:0,tasksToExpand:v,telemetryData:l}}catch(e){throw h&&$(h,`Error.`,!1),m.error(`Error during expand all operation: ${e.message}`),!f&&be(s)&&console.error(e),e}}var no=to;function ro(e,t,n){if(t.parentTaskId===n||t.dependencies&&t.dependencies.includes(n))return!0;if(t.dependencies)for(let r of t.dependencies){let t=e.find(e=>e.id===r);if(t&&ro(e,t,n))return!0}if(t.subtasks){for(let r of t.subtasks)if(ro(e,r,n))return!0}return!1}var io=ro;async function ao(e,t,n=null,r=!1,i=`text`,a={}){let{projectRoot:s,tag:c}=a;try{let a;try{let e=await(await I({projectPath:s||process.cwd()})).tasks.list({tag:c});a={tasks:e.tasks},z(`debug`,`Loaded ${e.tasks.length} tasks via tm-core (${e.storageType} storage)`)}catch(t){z(`warn`,`TmCore failed, falling back to legacy readJSON: ${t.message}`),a=w(e,s,c)}if(!a||!a.tasks)throw Error(`No valid tasks found in ${e}`);let l=Be(n);l&&l.complexityAnalysis&&a.tasks.forEach(e=>je(e,l));let u;if(t&&t.toLowerCase()!==`all`){let e=t.split(`,`).map(e=>e.trim().toLowerCase()).filter(e=>e.length>0);u=a.tasks.filter(t=>t.status&&e.includes(t.status.toLowerCase()))}else u=a.tasks;let d=a.tasks.length,f=a.tasks.filter(e=>e.status===`done`||e.status===`completed`).length,p=d>0?f/d*100:0,m=f,h=a.tasks.filter(e=>e.status===`in-progress`).length,g=a.tasks.filter(e=>e.status===`pending`).length,_=a.tasks.filter(e=>e.status===`blocked`).length,v=a.tasks.filter(e=>e.status===`deferred`).length,y=a.tasks.filter(e=>e.status===`cancelled`).length,b=a.tasks.filter(e=>e.status===`review`).length,x=0,S=0,C=0,T=0,E=0,D=0,O=0,k=0;a.tasks.forEach(e=>{e.subtasks&&e.subtasks.length>0&&(x+=e.subtasks.length,S+=e.subtasks.filter(e=>e.status===`done`||e.status===`completed`).length,C+=e.subtasks.filter(e=>e.status===`in-progress`).length,T+=e.subtasks.filter(e=>e.status===`pending`).length,E+=e.subtasks.filter(e=>e.status===`blocked`).length,D+=e.subtasks.filter(e=>e.status===`deferred`).length,O+=e.subtasks.filter(e=>e.status===`cancelled`).length,k+=e.subtasks.filter(e=>e.status===`review`).length)});let A=x>0?S/x*100:0,j=new Set(a.tasks.filter(e=>e.status===`done`||e.status===`completed`).map(e=>e.id)),M=a.tasks.filter(e=>e.status!==`done`&&e.status!==`completed`&&(!e.dependencies||e.dependencies.length===0)).length,N=a.tasks.filter(e=>e.status!==`done`&&e.status!==`completed`&&e.dependencies&&e.dependencies.length>0&&e.dependencies.every(e=>j.has(e))).length,P=a.tasks.filter(e=>e.status!==`done`&&e.status!==`completed`&&e.dependencies&&e.dependencies.length>0&&!e.dependencies.every(e=>j.has(e))).length,ee=M+N,te={};a.tasks.forEach(e=>{e.dependencies&&e.dependencies.length>0&&e.dependencies.forEach(e=>{te[e]=(te[e]||0)+1})});let ne=null,re=0;for(let[e,t]of Object.entries(te))t>re&&(re=t,ne=parseInt(e));let ie=ne===null?null:a.tasks.find(e=>e.id===ne),ae=a.tasks.reduce((e,t)=>e+(t.dependencies?t.dependencies.length:0),0)/a.tasks.length,F=Jr(a.tasks,l);if(i===`json`)return{tasks:u.map(e=>{let{details:t,...n}=e;return n.subtasks&&Array.isArray(n.subtasks)&&(n.subtasks=n.subtasks.map(e=>{let{details:t,...n}=e;return n})),n}),filter:t||`all`,stats:{total:d,completed:m,inProgress:h,pending:g,blocked:_,deferred:v,cancelled:y,review:b,completionPercentage:p,subtasks:{total:x,completed:S,inProgress:C,pending:T,blocked:E,deferred:D,cancelled:O,completionPercentage:A}}};if(i===`markdown-readme`)return so(a,u,{totalTasks:d,completedTasks:f,completionPercentage:p,doneCount:m,inProgressCount:h,pendingCount:g,blockedCount:_,deferredCount:v,cancelledCount:y,totalSubtasks:x,completedSubtasks:S,subtaskCompletionPercentage:A,inProgressSubtasks:C,pendingSubtasks:T,blockedSubtasks:E,deferredSubtasks:D,cancelledSubtasks:O,reviewSubtasks:k,tasksWithNoDeps:M,tasksReadyToWork:ee,tasksWithUnsatisfiedDeps:P,mostDependedOnTask:ie,mostDependedOnTaskId:ne,maxDependents:re,avgDependenciesPerTask:ae,complexityReport:l,withSubtasks:r,nextItem:F});if(i===`compact`)return fo(u,r);let oe={"in-progress":d>0?h/d*100:0,pending:d>0?g/d*100:0,blocked:d>0?_/d*100:0,deferred:d>0?v/d*100:0,cancelled:d>0?y/d*100:0,review:d>0?b/d*100:0},se={"in-progress":x>0?C/x*100:0,pending:x>0?T/x*100:0,blocked:x>0?E/x*100:0,deferred:x>0?D/x*100:0,cancelled:x>0?O/x*100:0,review:x>0?k/x*100:0},ce=bl(p,30,oe),le=bl(A,30,se),ue;try{ue=process.stdout.columns}catch{z(`debug`,`Could not determine terminal width, using default`)}ue||=80,ue=Math.max(ue,80);let de=B.white.bold(`Project Dashboard`)+`
|
|
907
911
|
Tasks Progress: ${B.greenBright(ce)} ${p.toFixed(0)}%\nDone: ${B.green(m)} In Progress: ${B.blue(h)} Pending: ${B.yellow(g)} Blocked: ${B.red(_)} Deferred: ${B.gray(v)} Cancelled: ${B.gray(y)}\n\nSubtasks Progress: ${B.cyan(le)} ${A.toFixed(0)}%\nCompleted: ${B.green(S)}/${x} In Progress: ${B.blue(C)} Pending: ${B.yellow(T)} Blocked: ${B.red(E)} Deferred: ${B.gray(D)} Cancelled: ${B.gray(O)}\n\n`+B.cyan.bold(`Priority Breakdown:`)+`
|
|
908
912
|
${B.red(`•`)} ${B.white(`High priority:`)} ${a.tasks.filter(e=>e.priority===`high`).length}\n${B.yellow(`•`)} ${B.white(`Medium priority:`)} ${a.tasks.filter(e=>e.priority===`medium`).length}\n${B.green(`•`)} ${B.white(`Low priority:`)} ${a.tasks.filter(e=>e.priority===`low`).length}`,fe=B.white.bold(`Dependency Status & Next Task`)+`
|
|
909
913
|
`+B.cyan.bold(`Dependency Metrics:`)+`
|
|
910
914
|
${B.green(`•`)} ${B.white(`Tasks with no dependencies:`)} ${M}\n${B.green(`•`)} ${B.white(`Tasks ready to work on:`)} ${ee}\n${B.yellow(`•`)} ${B.white(`Tasks blocked by dependencies:`)} ${P}\n${B.magenta(`•`)} ${B.white(`Most depended-on task:`)} ${ie?B.cyan(`#${ne} (${re} dependents)`):B.gray(`None`)}\n${B.blue(`•`)} ${B.white(`Avg dependencies per task:`)} ${ae.toFixed(1)}\n\n`+B.cyan.bold(`Next Task to Work On:`)+`
|
|
911
915
|
ID: ${B.cyan(F?F.id:`N/A`)} - ${F?B.white.bold(o(F.title,40)):B.yellow(`No task available`)}
|
|
912
|
-
Priority: ${F?B.white(F.priority||`medium`):``} Dependencies: ${F?
|
|
913
|
-
Complexity: ${F&&F.complexityScore?
|
|
916
|
+
Priority: ${F?B.white(F.priority||`medium`):``} Dependencies: ${F?Sl(F.dependencies,a.tasks,!0,l):``}
|
|
917
|
+
Complexity: ${F&&F.complexityScore?wl(F.complexityScore):B.gray(`N/A`)}`;if(ue>=104){let e=ue,t=Math.floor(e/2),n=t-4,r=W(de,{padding:1,borderColor:`blue`,borderStyle:`round`,width:n,dimBorder:!1}),i=W(fe,{padding:1,borderColor:`magenta`,borderStyle:`round`,width:n,dimBorder:!1}),a=r.split(`
|
|
914
918
|
`),o=i.split(`
|
|
915
919
|
`),s=Math.max(a.length,o.length),c=[];for(let e=0;e<s;e++){let n=e<a.length?a[e]:``,r=e<o.length?o[e]:``,i=n.trimEnd().padEnd(t,` `);c.push(i+r)}console.log(c.join(`
|
|
916
|
-
`))}else{let e=W(de,{padding:1,borderColor:`blue`,borderStyle:`round`,margin:{top:0,bottom:1}}),t=W(fe,{padding:1,borderColor:`magenta`,borderStyle:`round`,margin:{top:0,bottom:1}});console.log(e),console.log(t)}if(u.length===0){console.log(W(t?B.yellow(`No tasks with status '${t}' found`):B.yellow(`No tasks found`),{padding:1,borderColor:`yellow`,borderStyle:`round`}));return}let pe=r?10:7,me=100-pe-15-12-20-10,he=ue-10,ge=Math.floor(he*(pe/100)),_e=Math.floor(he*(15/100)),ve=Math.floor(he*(12/100)),ye=Math.floor(he*(20/100)),be=Math.floor(he*(10/100)),xe=Math.floor(he*(me/100)),Se=new K({head:[B.cyan.bold(`ID`),B.cyan.bold(`Title`),B.cyan.bold(`Status`),B.cyan.bold(`Priority`),B.cyan.bold(`Dependencies`),B.cyan.bold(`Complexity`)],colWidths:[ge,xe,_e,ve,ye,be],style:{head:[],border:[],compact:!1},wordWrap:!0,wrapOnWordBoundary:!0});u.forEach(e=>{let t=`None`;t=e.dependencies&&e.dependencies.length>0?
|
|
917
|
-
Falling back to simple task list due to terminal width constraints:`)),u.forEach(e=>{console.log(`${B.cyan(e.id)}: ${B.white(e.title)} - ${
|
|
920
|
+
`))}else{let e=W(de,{padding:1,borderColor:`blue`,borderStyle:`round`,margin:{top:0,bottom:1}}),t=W(fe,{padding:1,borderColor:`magenta`,borderStyle:`round`,margin:{top:0,bottom:1}});console.log(e),console.log(t)}if(u.length===0){console.log(W(t?B.yellow(`No tasks with status '${t}' found`):B.yellow(`No tasks found`),{padding:1,borderColor:`yellow`,borderStyle:`round`}));return}let pe=r?10:7,me=100-pe-15-12-20-10,he=ue-10,ge=Math.floor(he*(pe/100)),_e=Math.floor(he*(15/100)),ve=Math.floor(he*(12/100)),ye=Math.floor(he*(20/100)),be=Math.floor(he*(10/100)),xe=Math.floor(he*(me/100)),Se=new K({head:[B.cyan.bold(`ID`),B.cyan.bold(`Title`),B.cyan.bold(`Status`),B.cyan.bold(`Priority`),B.cyan.bold(`Dependencies`),B.cyan.bold(`Complexity`)],colWidths:[ge,xe,_e,ve,ye,be],style:{head:[],border:[],compact:!1},wordWrap:!0,wrapOnWordBoundary:!0});u.forEach(e=>{let t=`None`;t=e.dependencies&&e.dependencies.length>0?Sl(e.dependencies,a.tasks,!0,l):B.gray(`None`);let n=e.title.replace(/\n/g,` `),i={high:B.red,medium:B.yellow,low:B.gray}[e.priority||`medium`]||B.white,s=xl(e.status,!0);Se.push([e.id.toString(),o(n,xe-3),s,i(o(e.priority||`medium`,ve-2)),t,e.complexityScore?wl(e.complexityScore):B.gray(`N/A`)]),r&&e.subtasks&&e.subtasks.length>0&&e.subtasks.forEach(t=>{let n=`None`;t.dependencies&&t.dependencies.length>0&&(n=t.dependencies.map(t=>{if(typeof t==`number`&&t<100){let n=e.subtasks.find(e=>e.id===t);if(n){let r=n.status===`done`||n.status===`completed`,i=n.status===`in-progress`;return r?B.green.bold(`${e.id}.${t}`):i?B.hex(`#FFA500`).bold(`${e.id}.${t}`):B.red.bold(`${e.id}.${t}`)}}let n=a.tasks.find(e=>e.id===t);if(n){je(n,l);let e=n.status===`done`||n.status===`completed`,r=n.status===`in-progress`;return e?B.green.bold(`${t}`):r?B.hex(`#FFA500`).bold(`${t}`):B.red.bold(`${t}`)}return B.cyan(t.toString())}).join(`, `)||B.gray(`None`)),Se.push([`${e.id}.${t.id}`,B.dim(`└─ ${o(t.title,xe-5)}`),xl(t.status,!0),B.dim(`-`),n,t.complexityScore?B.gray(`${t.complexityScore}`):B.gray(`N/A`)])})});try{console.log(Se.toString())}catch(e){z(`error`,`Error rendering table: ${e.message}`),console.log(B.yellow(`
|
|
921
|
+
Falling back to simple task list due to terminal width constraints:`)),u.forEach(e=>{console.log(`${B.cyan(e.id)}: ${B.white(e.title)} - ${xl(e.status)}`)})}t&&(console.log(B.yellow(`\nFiltered by status: ${t}`)),console.log(B.yellow(`Showing ${u.length} of ${d} tasks`)));let Ce={high:B.red.bold,medium:B.yellow,low:B.gray};if(F){let e=``,t=a.tasks.find(e=>String(e.id)===String(F.id));t&&t.subtasks&&t.subtasks.length>0&&(e=`\n\n${B.white.bold(`Subtasks:`)}\n`,e+=t.subtasks.map(e=>{je(e,l);let n=e.status||`pending`,r={done:B.green,completed:B.green,pending:B.yellow,"in-progress":B.blue,deferred:B.gray,blocked:B.red,cancelled:B.gray}[n.toLowerCase()]||B.white;return`${B.cyan(`${t.id}.${e.id}`)} [${r(n)}] ${e.title}`}).join(`
|
|
918
922
|
`)),console.log(W(B.hex(`#FF8800`).bold(`🔥 Next Task to Work On: #${F.id} - ${F.title}`)+`
|
|
919
923
|
|
|
920
|
-
${B.white(`Priority:`)} ${Ce[F.priority||`medium`](F.priority||`medium`)} ${B.white(`Status:`)} ${
|
|
924
|
+
${B.white(`Priority:`)} ${Ce[F.priority||`medium`](F.priority||`medium`)} ${B.white(`Status:`)} ${xl(F.status,!0)}\n${B.white(`Dependencies:`)} ${F.dependencies&&F.dependencies.length>0?Sl(F.dependencies,a.tasks,!0,l):B.gray(`None`)}\n\n${B.white(`Description:`)} ${oo(F,a.tasks)}`+e+`
|
|
921
925
|
|
|
922
926
|
${B.cyan(`Start working:`)} ${B.yellow(`task-master set-status --id=${F.id} --status=in-progress`)}\n${B.cyan(`View details:`)} ${B.yellow(`task-master show ${F.id}`)}`,{padding:{left:2,right:2,top:1,bottom:1},borderColor:`#FF8800`,borderStyle:`round`,margin:{top:1,bottom:1},title:`⚡ RECOMMENDED NEXT TASK ⚡`,titleAlignment:`center`,width:ue-4,fullscreen:!1}))}else console.log(W(B.hex(`#FF8800`).bold(`No eligible next task found`)+`
|
|
923
927
|
|
|
924
928
|
All pending tasks have dependencies that are not yet completed, or all tasks are done.`,{padding:1,borderColor:`#FF8800`,borderStyle:`round`,margin:{top:1,bottom:1},title:`⚡ NEXT TASK ⚡`,titleAlignment:`center`,width:ue-4}));console.log(W(B.white.bold(`Suggested Next Steps:`)+`
|
|
925
929
|
|
|
926
|
-
${B.cyan(`1.`)} Run ${B.yellow(`task-master next`)} to see what to work on next\n${B.cyan(`2.`)} Run ${B.yellow(`task-master expand --id=<id>`)} to break down a task into subtasks\n${B.cyan(`3.`)} Run ${B.yellow(`task-master set-status --id=<id> --status=done`)} to mark a task as complete`,{padding:1,borderColor:`gray`,borderStyle:`round`,margin:{top:1}}))}catch(e){if(z(`error`,`Error listing tasks: ${e.message}`),i===`json`)throw{code:`TASK_LIST_ERROR`,message:e.message,details:e.stack};console.error(B.red(`Error: ${e.message}`)),process.exit(1)}}function
|
|
930
|
+
${B.cyan(`1.`)} Run ${B.yellow(`task-master next`)} to see what to work on next\n${B.cyan(`2.`)} Run ${B.yellow(`task-master expand --id=<id>`)} to break down a task into subtasks\n${B.cyan(`3.`)} Run ${B.yellow(`task-master set-status --id=<id> --status=done`)} to mark a task as complete`,{padding:1,borderColor:`gray`,borderStyle:`round`,margin:{top:1}}))}catch(e){if(z(`error`,`Error listing tasks: ${e.message}`),i===`json`)throw{code:`TASK_LIST_ERROR`,message:e.message,details:e.stack};console.error(B.red(`Error: ${e.message}`)),process.exit(1)}}function oo(e,t){if(!e)return`N/A`;if(e.parentId){let n=t.find(t=>t.id===e.parentId);return n?.subtasks?.find(t=>`${n.id}.${t.id}`===e.id)?.description||`No description available.`}else return t.find(t=>String(t.id)===String(e.id))?.description||`No description available.`}function so(e,t,n){let{totalTasks:r,completedTasks:i,completionPercentage:a,doneCount:o,inProgressCount:s,pendingCount:c,blockedCount:l,deferredCount:u,cancelledCount:d,totalSubtasks:f,completedSubtasks:p,subtaskCompletionPercentage:m,inProgressSubtasks:h,pendingSubtasks:g,blockedSubtasks:_,deferredSubtasks:v,cancelledSubtasks:y,tasksWithNoDeps:b,tasksReadyToWork:x,tasksWithUnsatisfiedDeps:S,mostDependedOnTask:C,mostDependedOnTaskId:w,maxDependents:T,avgDependenciesPerTask:E,complexityReport:D,withSubtasks:O,nextItem:k}=n,A=``,j=(e,t=20)=>{let n=Math.round(e/100*t),r=t-n;return`█`.repeat(n)+`░`.repeat(r)},M=j(a,20),N=j(m,20);A+=`| Project Dashboard | |
|
|
927
931
|
`,A+=`| :- |:-|
|
|
928
932
|
`,A+=`| Task Progress | ${M} ${Math.round(a)}% |\n`,A+=`| Done | ${o} |\n`,A+=`| In Progress | ${s} |\n`,A+=`| Pending | ${c} |\n`,A+=`| Deferred | ${u} |\n`,A+=`| Cancelled | ${d} |\n`,A+=`|-|-|
|
|
929
933
|
`,A+=`| Subtask Progress | ${N} ${Math.round(m)}% |\n`,A+=`| Completed | ${p} |\n`,A+=`| In Progress | ${h} |\n`,A+=`| Pending | ${g} |\n`,A+=`
|
|
930
934
|
|
|
931
935
|
`,A+=`| ID | Title | Status | Priority | Dependencies | Complexity |
|
|
932
936
|
`,A+=`| :- | :- | :- | :- | :- | :- |
|
|
933
|
-
`;let P=e=>{switch(e){case`done`:case`completed`:return`✓ done`;case`in-progress`:return`► in-progress`;case`pending`:return`○ pending`;case`blocked`:return`⭕ blocked`;case`deferred`:return`x deferred`;case`cancelled`:return`x cancelled`;case`review`:return`? review`;default:return e||`pending`}},ee=(e,t)=>!e||e.length===0?`None`:e.map(e=>(t.find(t=>t.id===e),e.toString())).join(`, `);return t.forEach(t=>{let n=t.title,r=P(t.status),i=t.priority||`medium`,a=ee(t.dependencies,e.tasks),o=t.complexityScore?`● ${t.complexityScore}`:`N/A`;A+=`| ${t.id} | ${n} | ${r} | ${i} | ${a} | ${o} |\n`,O&&t.subtasks&&t.subtasks.length>0&&t.subtasks.forEach(n=>{let r=`${n.title}`,i=P(n.status),a=ee(n.dependencies,e.tasks),o=n.complexityScore?n.complexityScore.toString():`N/A`;A+=`| ${t.id}.${n.id} | ${r} | ${i} | - | ${a} | ${o} |\n`})}),A}function
|
|
934
|
-
`))}var lo=no;new class{constructor(e={}){this.config={maxCacheSize:e.maxCacheSize||1e3,ttl:e.ttl||1e3*60*5,maxContextSize:e.maxContextSize||4e3},this.cache=new bt({max:this.config.maxCacheSize,ttl:this.config.ttl,updateAgeOnGet:!0}),this.stats={hits:0,misses:0,invalidations:0}}async getContext(e,t={}){let n=this._getCacheKey(e,t),r=this.cache.get(n);if(r)return this.stats.hits++,r;this.stats.misses++;let i={id:e,metadata:{...t,created:new Date().toISOString()}};return this.cache.set(n,i),i}async updateContext(e,t){let n=await this.getContext(e);Object.assign(n.metadata,t);let r=this._getCacheKey(e,n.metadata);return this.cache.set(r,n),n}invalidateContext(e,t={}){let n=this._getCacheKey(e,t);this.cache.delete(n),this.stats.invalidations++}getCachedData(e){let t=this.cache.get(e);if(t!==void 0)return this.stats.hits++,t;this.stats.misses++}setCachedData(e,t){this.cache.set(e,t)}invalidateCacheKey(e){this.cache.delete(e),this.stats.invalidations++}getStats(){return{hits:this.stats.hits,misses:this.stats.misses,invalidations:this.stats.invalidations,size:this.cache.size,maxSize:this.config.maxCacheSize,ttl:this.config.ttl}}_getCacheKey(e,t){return`${e}:${JSON.stringify(t)}`}};const uo={info:()=>{},warn:()=>{},error:()=>{},debug:()=>{},success:()=>{}};function fo(e,t=uo){let n=e?.file,r=e?.projectRoot;if(n&&H.isAbsolute(n))return n;let i=r?F(r):null;if(n&&i)return H.resolve(i,n);if(i){let e=a(n,{projectRoot:i},t);if(e===null&&!n){let e=H.join(i,`.taskmaster`,`tasks`,`tasks.json`);return t?.info?.(`Core findTasksPath returned null, using default path: ${e}`),e}return e}return a(n,null,t)}function po(e,t=uo){let n=e?.input,r=e?.projectRoot;if(n&&H.isAbsolute(n))return n;let i=r?F(r):null;return n&&i?H.resolve(i,n):i?k(n,{projectRoot:i},t):k(n,null,t)}function mo(e,t=uo){let n=e?.complexityReport,r=e?.projectRoot,i=e?.tag;if(n&&H.isAbsolute(n))return n;let a=r?F(r):null;return n&&a?H.resolve(a,n):a?D(n,{projectRoot:a,tag:i},t):D(n,null,t)}function ho(e,t){if(!t?.projectRoot)throw Error(`projectRoot is required in args to resolve project paths`);let n=F(t.projectRoot);return H.isAbsolute(e)?e:H.resolve(n,e)}function go(e,t=uo){return fo(e,t)}function _o(e,t=uo){return mo(e,t)}function vo(e,t,n=uo){return Ne(e,t,n)}$e(import.meta.url);function yo(e){return{info:(t,...n)=>e.info(t,...n),warn:(t,...n)=>e.warn(t,...n),error:(t,...n)=>e.error(t,...n),debug:(t,...n)=>e.debug?e.debug(t,...n):null,success:(t,...n)=>e.info(t,...n)}}const bo=$e(import.meta.url);H.dirname(bo);const xo=yo({info:e=>console.log(B.blue(`ℹ`),e),warn:e=>console.log(B.yellow(`⚠`),e),error:e=>console.error(B.red(`✗`),e),success:e=>console.log(B.green(`✓`),e)});async function So(e={}){let t=Fe()||process.cwd();xo.info(`Starting migration in: ${t}`);let n=H.join(t,`.taskmaster`);if(V.existsSync(n)&&!e.force){xo.warn(`.taskmaster directory already exists. Use --force to overwrite or skip migration.`);return}let r=Co(t);if(r.length===0){xo.info(`No files to migrate. Project may already be using the new structure.`);return}xo.info(`Migration plan:`);for(let t of r){let n=e.dryRun?`Would move`:`Will move`;xo.info(` ${n}: ${t.from} → ${t.to}`)}if(e.dryRun){xo.info(`Dry run complete. Use --dry-run=false to perform actual migration.`);return}if(!e.yes){let e=(await import(`readline`)).createInterface({input:process.stdin,output:process.stdout}),t=await new Promise(t=>{e.question(`Proceed with migration? (y/N): `,t)});if(e.close(),t.toLowerCase()!==`y`&&t.toLowerCase()!==`yes`){xo.info(`Migration cancelled.`);return}}try{await wo(t,r,e),xo.success(`Migration completed successfully!`),xo.info(`You can now use the new .taskmaster directory structure.`),e.cleanup||xo.info(`Old files were preserved. Use --cleanup to remove them after verification.`)}catch(e){throw xo.error(`Migration failed: ${e.message}`),e}}function Co(e){let t=[],n=H.join(e,`tasks`);if(V.existsSync(n)){let e=V.readdirSync(n);for(let n of e)t.push({from:H.join(`tasks`,n),to:H.join(`.taskmaster`,`tasks`,n),type:`task`})}let r=H.join(e,`scripts`);if(V.existsSync(r)){let e=V.readdirSync(r);for(let n of e){let e=H.join(r,n);if(V.statSync(e).isFile()){let e,r=n.toLowerCase();if(r.includes(`example`)||r.includes(`template`)||r.includes(`boilerplate`)||r.includes(`sample`))e=H.join(`.taskmaster`,`templates`,n);else if(r.includes(`complexity`)&&r.includes(`report`)&&r.endsWith(`.json`))e=H.join(`.taskmaster`,`reports`,n);else if(r.includes(`prd`)||r.endsWith(`.md`)||r.endsWith(`.txt`))e=H.join(`.taskmaster`,`docs`,n);else{xo.warn(`Skipping migration of '${n}' - uncertain categorization. You may need to move this manually.`);continue}t.push({from:H.join(`scripts`,n),to:e,type:`script`})}}}let i=H.join(e,h);return V.existsSync(i)&&t.push({from:h,to:c,type:`config`}),t}async function wo(e,t,n){let r=H.join(e,`.taskmaster`);V.existsSync(r)||V.mkdirSync(r,{recursive:!0});let i=new Set;for(let e of t){let t=H.dirname(e.to);i.add(t)}for(let t of i){let n=H.join(e,t);V.existsSync(n)||(V.mkdirSync(n,{recursive:!0}),xo.info(`Created directory: ${t}`))}if(n.backup){let t=H.join(e,`.taskmaster-migration-backup`);xo.info(`Creating backup in: ${t}`),V.existsSync(t)&&V.rmSync(t,{recursive:!0,force:!0}),V.mkdirSync(t,{recursive:!0})}for(let r of t){let t=H.join(e,r.from),i=H.join(e,r.to);if(!V.existsSync(t)){xo.warn(`Source file not found: ${r.from}`);continue}if(n.backup){let n=H.join(e,`.taskmaster-migration-backup`,r.from),i=H.dirname(n);V.existsSync(i)||V.mkdirSync(i,{recursive:!0}),V.copyFileSync(t,n)}let a=H.dirname(i);V.existsSync(a)||V.mkdirSync(a,{recursive:!0}),V.copyFileSync(t,i),xo.info(`Migrated: ${r.from} → ${r.to}`),n.cleanup&&V.unlinkSync(t)}if(n.cleanup)for(let t of[`tasks`,`scripts`]){let n=H.join(e,t);if(V.existsSync(n))try{V.readdirSync(n).length===0&&(V.rmdirSync(n),xo.info(`Removed empty directory: ${t}`))}catch{}}}function To(e,t,n={}){return ve(e,t,{...n,direction:`forward`,logger:{warn:console.warn}})}var Eo=class extends Error{constructor(e,t,n={}){super(t),this.name=`MoveTaskError`,this.code=e,this.data=n}};const Do={CROSS_TAG_DEPENDENCY_CONFLICTS:`CROSS_TAG_DEPENDENCY_CONFLICTS`,CANNOT_MOVE_SUBTASK:`CANNOT_MOVE_SUBTASK`,SOURCE_TARGET_TAGS_SAME:`SOURCE_TARGET_TAGS_SAME`,TASK_NOT_FOUND:`TASK_NOT_FOUND`,SUBTASK_NOT_FOUND:`SUBTASK_NOT_FOUND`,PARENT_TASK_NOT_FOUND:`PARENT_TASK_NOT_FOUND`,PARENT_TASK_NO_SUBTASKS:`PARENT_TASK_NO_SUBTASKS`,DESTINATION_TASK_NOT_FOUND:`DESTINATION_TASK_NOT_FOUND`,TASK_ALREADY_EXISTS:`TASK_ALREADY_EXISTS`,INVALID_TASKS_FILE:`INVALID_TASKS_FILE`,ID_COUNT_MISMATCH:`ID_COUNT_MISMATCH`,INVALID_SOURCE_TAG:`INVALID_SOURCE_TAG`,INVALID_TARGET_TAG:`INVALID_TARGET_TAG`};function Oo(e){if(e==null)return e;if(typeof e==`number`)return Number.isFinite(e)?e:null;if(typeof e==`string`){let t=e.trim();if(t===``)return null;let n=t.includes(`.`)?t.split(`.`)[0]:t,r=parseInt(n,10);return Number.isFinite(r)?r:null}return null}async function ko(e,t,n,r=!1,i={}){let{projectRoot:a,tag:o}=i,s=t.split(`,`).map(e=>e.trim()),c=n.split(`,`).map(e=>e.trim());if(s.length!==c.length)throw new Eo(Do.ID_COUNT_MISMATCH,`Number of source IDs (${s.length}) must match number of destination IDs (${c.length})`);if(s.length>1){let t=[];for(let n=0;n<s.length;n++){let r=await ko(e,s[n],c[n],!1,i);t.push(r)}return{message:`Successfully moved ${s.length} tasks/subtasks`,moves:t}}let l=w(e,a,o);if(l&&l._rawTaggedData&&(l=l._rawTaggedData),!l||!l[o]||!Array.isArray(l[o].tasks))throw new Eo(Do.INVALID_TASKS_FILE,`Invalid tasks file or tag "${o}" not found at ${e}`);let u=l[o].tasks;z(`info`,`Moving task/subtask ${t} to ${n} (tag: ${o})`);let d=t.includes(`.`),f=n.includes(`.`),p;return p=d&&f?Ao(u,t,n):d&&!f?jo(u,t,n):!d&&f?Mo(u,t,n):No(u,t,n),l[o].tasks=u,_(e,l,i.projectRoot,o),p}function Ao(e,t,n){let[r,i]=t.split(`.`).map(e=>parseInt(e,10)),[a,o]=n.split(`.`).map(e=>parseInt(e,10)),s=e.find(e=>e.id===r),c=e.find(e=>e.id===a);if(!s)throw new Eo(Do.PARENT_TASK_NOT_FOUND,`Source parent task with ID ${r} not found`);if(!c)throw new Eo(Do.PARENT_TASK_NOT_FOUND,`Destination parent task with ID ${a} not found`);s.subtasks||=[],c.subtasks||=[];let l=s.subtasks.findIndex(e=>e.id===i);if(l===-1)throw new Eo(Do.SUBTASK_NOT_FOUND,`Source subtask ${t} not found`);let u=s.subtasks[l];if(r===a)if(c.subtasks.length>0){let e=c.subtasks.findIndex(e=>e.id===o);if(e!==-1){s.subtasks.splice(l,1);let t=l<e?e-1:e;c.subtasks.splice(t+1,0,u)}else s.subtasks.splice(l,1),c.subtasks.push(u)}else s.subtasks.splice(l,1),c.subtasks.push(u);else Po(u,s,l,c,o);return{message:`Moved subtask ${t} to ${n}`,movedItem:u}}function jo(e,t,n){let[r,i]=t.split(`.`).map(e=>parseInt(e,10)),a=parseInt(n,10),o=e.find(e=>e.id===r);if(!o)throw new Eo(Do.PARENT_TASK_NOT_FOUND,`Source parent task with ID ${r} not found`);if(!o.subtasks)throw new Eo(Do.PARENT_TASK_NO_SUBTASKS,`Source parent task ${r} has no subtasks`);let s=o.subtasks.findIndex(e=>e.id===i);if(s===-1)throw new Eo(Do.SUBTASK_NOT_FOUND,`Source subtask ${t} not found`);let c=o.subtasks[s];if(e.find(e=>e.id===a))throw new Eo(Do.TASK_ALREADY_EXISTS,`Cannot move to existing task ID ${a}. Choose a different ID or use subtask destination.`);let l={id:a,title:c.title,description:c.description,status:c.status||`pending`,dependencies:c.dependencies||[],priority:c.priority||`medium`,details:c.details||``,testStrategy:c.testStrategy||``,subtasks:[]};o.subtasks.splice(s,1);let u=e.findIndex(e=>e.id>a);return u===-1?e.push(l):e.splice(u,0,l),{message:`Converted subtask ${t} to task ${n}`,movedItem:l}}function Mo(e,t,n){let r=parseInt(t,10),[i,a]=n.split(`.`).map(e=>parseInt(e,10)),o=e.findIndex(e=>e.id===r),s=e.find(e=>e.id===i);if(o===-1)throw new Eo(Do.TASK_NOT_FOUND,`Source task with ID ${r} not found`);if(!s)throw new Eo(Do.PARENT_TASK_NOT_FOUND,`Destination parent task with ID ${i} not found`);let c=e[o];s.subtasks||=[];let l={id:a,title:c.title,description:c.description,status:c.status||`pending`,dependencies:c.dependencies||[],details:c.details||``,testStrategy:c.testStrategy||``},u=-1;s.subtasks.length>0&&(u=s.subtasks.findIndex(e=>e.id===a),u===-1&&(u=s.subtasks.length-1));let d=u===-1?0:u+1;return s.subtasks.splice(d,0,l),e.splice(o,1),{message:`Converted task ${t} to subtask ${n}`,movedItem:l}}function No(e,t,n){let r=parseInt(t,10),i=parseInt(n,10),a=e.findIndex(e=>e.id===r);if(a===-1)throw new Eo(Do.TASK_NOT_FOUND,`Source task with ID ${r} not found`);let o=e[a],s=e.findIndex(e=>e.id===i);if(s!==-1)throw e[s],new Eo(Do.TASK_ALREADY_EXISTS,`Task with ID ${i} already exists. Use a different destination ID.`);return Fo(e,a,o,i)}function Po(e,t,n,r,i){let a=parseInt(i,10),o={...e,id:a};r.subtasks||=[];let s=-1;r.subtasks.length>0&&(s=r.subtasks.findIndex(e=>e.id===a),s===-1&&(s=r.subtasks.length-1));let c=s===-1?0:s+1;return r.subtasks.splice(c,0,o),t.subtasks.splice(n,1),o}function Fo(e,t,n,r){let i=e.findIndex(e=>e.id===r),a={...n,id:r};e.forEach(e=>{if(e.dependencies&&e.dependencies.includes(n.id)){let t=e.dependencies.indexOf(n.id);e.dependencies[t]=r}e.subtasks&&e.subtasks.forEach(e=>{if(e.dependencies&&e.dependencies.includes(n.id)){let t=e.dependencies.indexOf(n.id);e.dependencies[t]=r}})}),Array.isArray(a.subtasks)&&a.subtasks.forEach(e=>{Array.isArray(e.dependencies)&&(e.dependencies=e.dependencies.map(e=>{if(typeof e==`string`&&e.includes(`.`)){let[t,i]=e.split(`.`);if(parseInt(t,10)===n.id)return`${r}.${i}`}return e}))}),e.splice(t,1);let o=t<i?i-1:i;return o>=0&&o<e.length?e[o]=a:e.push(a),z(`info`,`Moved task ${n.id} to new ID ${r}`),{message:`Moved task ${n.id} to new ID ${r}`,movedItem:a}}function Io(e){let t=[];for(let n in e)if(Object.prototype.hasOwnProperty.call(e,n)&&e[n]&&Array.isArray(e[n].tasks)){let r=e[n].tasks.map(e=>({...e,tag:n}));t=t.concat(r)}return t}async function Lo(e,t,n,r,i){let{projectRoot:a}=i,o=w(e,a,n);if(o&&o._rawTaggedData&&(o=o._rawTaggedData),!o||!o[n]||!Array.isArray(o[n].tasks))throw new Eo(Do.INVALID_SOURCE_TAG,`Source tag "${n}" not found or invalid`);o[r]||(o[r]={tasks:[]},z(`info`,`Created new tag "${r}"`));let s=t.map(e=>String(e)),c=o[n].tasks.filter(e=>{let t=String(e.id);return s.includes(t)});return t.forEach(e=>{Yl(e,n,r)}),{rawData:o,sourceTasks:c}}async function Ro(e){let{rawData:t,sourceTasks:n}=e;return{rawData:t,sourceTasks:n,allTasks:Io(t)}}async function zo(e,t,n,r,i,a){let{withDependencies:o=!1,ignoreDependencies:s=!1}=n,c=Array.isArray(t)?t.filter(e=>e&&e.tag===i):[];if(o){let t=To(e,c,{maxDepth:100,includeSelf:!1}),n=new Set(c.map(e=>typeof e.id==`string`?parseInt(e.id,10):e.id)),i=t.filter(e=>{let t=Oo(e);return Number.isFinite(t)&&n.has(t)}),a=[...new Set([...r,...i])];return z(`info`,`Moving ${a.length} tasks (including dependencies): ${a.join(`, `)}`),{tasksToMove:a,dependencyResolution:{type:`with-dependencies`,dependentTasks:i}}}let l=Jl(e,i,a,t);if(l.length>0){if(s)return e.forEach(e=>{let n=c,r=Array.isArray(t)?t.filter(e=>e&&e.tag===a):[];e.dependencies=e.dependencies.filter(e=>{let t=Oo(e);return Number.isFinite(t)&&n.some(e=>e.id===t)?!1:(Number.isFinite(t)&&r.some(e=>e.id===t),!0)})}),z(`warn`,`Removed ${l.length} cross-tag dependencies`),{tasksToMove:r,dependencyResolution:{type:`ignored-dependencies`,conflicts:l}};throw new Eo(Do.CROSS_TAG_DEPENDENCY_CONFLICTS,`Cannot move tasks: ${l.length} cross-tag dependency conflicts found`,{conflicts:l,sourceTag:i,targetTag:a,taskIds:r})}return{tasksToMove:r,dependencyResolution:{type:`no-conflicts`}}}async function Bo(e,t,n,r,i,a){let{projectRoot:o}=i,s=[];for(let i of e){let e=typeof i==`string`?parseInt(i,10):i,a=r[t].tasks.findIndex(t=>t.id===e);if(a===-1)throw new Eo(Do.TASK_NOT_FOUND,`Task ${i} not found in source tag "${t}"`);let o=r[t].tasks[a];if(r[n].tasks.findIndex(t=>t.id===e)!==-1)throw new Eo(Do.TASK_ALREADY_EXISTS,`Task ${i} already exists in target tag "${n}"`,{conflictingId:e,targetTag:n,suggestions:[`Choose a different target tag without conflicting IDs`,`Move a different set of IDs (avoid existing ones)`,`If needed, move within-tag to a new ID first, then cross-tag move`]});r[t].tasks.splice(a,1);let c=Uo(o,t,n);r[n].tasks.push(c),s.push({id:i,fromTag:t,toTag:n}),z(`info`,`Moved task ${i} from "${t}" to "${n}"`)}return{rawData:r,movedTasks:s}}async function Vo(e,t,n,r,i,a){let{projectRoot:o}=n,{rawData:s,movedTasks:c}=e;_(t,s,o,null);let l={message:`Successfully moved ${c.length} tasks from "${r}" to "${i}"`,movedTasks:c};return a&&a.type===`ignored-dependencies`&&(l.tips=[`Run "task-master validate-dependencies" to check for dependency issues.`,`Run "task-master fix-dependencies" to automatically repair dangling dependencies.`]),l}async function Ho(e,t,n,r,i={},a={}){let{rawData:o,sourceTasks:s,allTasks:c}=await Ro(await Lo(e,t,n,r,a)),{tasksToMove:l,dependencyResolution:u}=await zo(s,c,i,t,n,r);return await Vo(await Bo(l,n,r,o,a,e),e,a,n,r,u)}function Uo(e,t,n){return e.tag=n,e.metadata||={},e.metadata.moveHistory||(e.metadata.moveHistory=[]),e.metadata.moveHistory.push({fromTag:t,toTag:n,timestamp:new Date().toISOString()}),e}var Wo=ko,Go=class e extends Error{constructor(t,n){super(t),this.name=`StreamingError`,this.code=n,Error.captureStackTrace&&Error.captureStackTrace(this,e)}};const Ko={NOT_ASYNC_ITERABLE:`STREAMING_NOT_SUPPORTED`,STREAM_PROCESSING_FAILED:`STREAM_PROCESSING_FAILED`,STREAM_NOT_ITERABLE:`STREAM_NOT_ITERABLE`,BUFFER_SIZE_EXCEEDED:`BUFFER_SIZE_EXCEEDED`};var qo=class e{static async withTimeout(e,t,n=`Operation`){let r,i=new Promise((e,i)=>{r=setTimeout(()=>{i(new Go(`${n} timed out after ${t/1e3} seconds`,Ko.STREAM_PROCESSING_FAILED))},t)});try{let t=await Promise.race([e,i]);return clearTimeout(r),t}catch(e){throw clearTimeout(r),e}}static async withSoftTimeout(e,t,n=void 0){let r,i=new Promise(e=>{r=setTimeout(()=>{e(n)},t)});try{let t=await Promise.race([e,i]);return clearTimeout(r),t}catch{return clearTimeout(r),n}}static createController(t,n=`Operation`){return{timeoutMs:t,operationName:n,async wrap(r,i=null){let a=i?`${n} - ${i}`:n;return e.withTimeout(r,t,a)},async wrapSoft(n,r=void 0){return e.withSoftTimeout(n,t,r)}}}static isTimeoutError(e){return e instanceof Go&&e.code===Ko.STREAM_PROCESSING_FAILED&&e.message.includes(`timed out`)}},Jo=class e{constructor(e,t=`ms`){this.milliseconds=this._toMilliseconds(e,t)}static milliseconds(t){return new e(t,`ms`)}static seconds(t){return new e(t,`s`)}static minutes(t){return new e(t,`m`)}static hours(t){return new e(t,`h`)}get seconds(){return this.milliseconds/1e3}get minutes(){return this.milliseconds/6e4}get hours(){return this.milliseconds/36e5}toString(){return this.milliseconds<1e3?`${this.milliseconds}ms`:this.milliseconds<6e4?`${this.seconds}s`:this.milliseconds<36e5?`${Math.floor(this.minutes)}m ${Math.floor(this.seconds%60)}s`:`${Math.floor(this.hours)}h ${Math.floor(this.minutes%60)}m`}_toMilliseconds(e,t){return e*({ms:1,s:1e3,m:6e4,h:36e5}[t]||1)}};const Yo=U.object({id:U.number(),title:U.string().min(1),description:U.string().min(1),details:U.string(),testStrategy:U.string(),priority:U.enum(aa),dependencies:U.array(U.number()),status:U.string()}),Xo=U.object({tasks:U.array(Yo),metadata:U.union([U.object({projectName:U.string(),totalTasks:U.number(),sourceFile:U.string(),generatedAt:U.string()}).strict(),U.null()]).default(null)});var Zo=class{constructor(e,t,n,r={}){this.prdPath=e,this.tasksPath=t,this.numTasks=n,this.force=r.force||!1,this.append=r.append||!1,this.research=r.research||!1,this.reportProgress=r.reportProgress,this.mcpLog=r.mcpLog,this.session=r.session,this.projectRoot=r.projectRoot,this.tag=r.tag,this.streamingTimeout=r.streamingTimeout||Jo.seconds(180).milliseconds,this.targetTag=this.tag||fe(this.projectRoot)||`master`,this.isMCP=!!this.mcpLog,this.outputFormat=this.isMCP&&!this.reportProgress?`json`:`text`,this.useStreaming=!1}hasCodebaseAnalysis(e=null){return b(this.research,this.projectRoot,this.session,e)}},Qo=class{constructor(e,t){this.isMCP=!!e,this.outputFormat=this.isMCP&&!t?`json`:`text`,this.logFn=e||{info:(...e)=>z(`info`,...e),warn:(...e)=>z(`warn`,...e),error:(...e)=>z(`error`,...e),debug:(...e)=>z(`debug`,...e),success:(...e)=>z(`success`,...e)}}report(e,t=`info`){this.logFn&&typeof this.logFn[t]==`function`?this.logFn[t](e):!L()&&this.outputFormat===`text`&&z(t,e)}};function $o(e){return`${Math.floor(e/60)}m ${Math.floor(e%60).toString().padStart(2,`0`)}s`}const es={BAR_WIDTH:40,TABLE_COL_WIDTHS:[28,50],DEFAULT_MODEL:`Default`,DEFAULT_TEMPERATURE:.7},Q={HIGH:`high`,MEDIUM:`medium`,LOW:`low`},ts={[Q.HIGH]:`#CC0000`,[Q.MEDIUM]:`#FF8800`,[Q.LOW]:`#FFCC00`},ns={main:{padding:{top:1,bottom:1,left:2,right:2},margin:{top:0,bottom:0},borderColor:`blue`,borderStyle:`round`},summary:{padding:{top:1,right:1,bottom:1,left:1},borderColor:`blue`,borderStyle:`round`,margin:{top:1,right:1,bottom:1,left:0}},warning:{padding:1,borderColor:`yellow`,borderStyle:`round`,margin:{top:1,bottom:1}},nextSteps:{padding:1,borderColor:`cyan`,borderStyle:`round`,margin:{top:1,right:0,bottom:1,left:0}}};function rs({prdFilePath:e,outputPath:t,numTasks:n,model:r,temperature:i,append:a,research:o}){let s=a?`Appending`:`Generating`,c=`Model: ${r} | Temperature: ${i}`;return o&&(c+=` | ${B.cyan.bold(`🔬 Research Mode`)}`),B.bold(`🤖 Parsing PRD and ${s} Tasks`)+`
|
|
937
|
+
`;let P=e=>{switch(e){case`done`:case`completed`:return`✓ done`;case`in-progress`:return`► in-progress`;case`pending`:return`○ pending`;case`blocked`:return`⭕ blocked`;case`deferred`:return`x deferred`;case`cancelled`:return`x cancelled`;case`review`:return`? review`;default:return e||`pending`}},ee=(e,t)=>!e||e.length===0?`None`:e.map(e=>(t.find(t=>t.id===e),e.toString())).join(`, `);return t.forEach(t=>{let n=t.title,r=P(t.status),i=t.priority||`medium`,a=ee(t.dependencies,e.tasks),o=t.complexityScore?`● ${t.complexityScore}`:`N/A`;A+=`| ${t.id} | ${n} | ${r} | ${i} | ${a} | ${o} |\n`,O&&t.subtasks&&t.subtasks.length>0&&t.subtasks.forEach(n=>{let r=`${n.title}`,i=P(n.status),a=ee(n.dependencies,e.tasks),o=n.complexityScore?n.complexityScore.toString():`N/A`;A+=`| ${t.id}.${n.id} | ${r} | ${i} | - | ${a} | ${o} |\n`})}),A}function co(e){if(!e||e.length===0)return``;if(e.length>5){let t=e.slice(0,5).join(`,`),n=e.length-5;return` → ${B.cyan(t)}${B.gray(`... (+`+n+` more)`)}`}else return` → ${B.cyan(e.join(`,`))}`}function lo(e,t=50){let n=e.status||`pending`,r=e.priority||`medium`,i=o(e.title||`Untitled`,t),a=xl(n,!0),s={high:B.red,medium:B.yellow,low:B.gray}[r]||B.white,c=co(e.dependencies);return`${B.cyan(e.id)} ${a} ${B.white(i)} ${s(`(`+r+`)`)}${c}`}function uo(e,t,n=47){let r=e.status||`pending`,i=o(e.title||`Untitled`,n),a=xl(r,!0),s=co(e.dependencies);return` ${B.cyan(t+`.`+e.id)} ${a} ${B.dim(i)}${s}`}function fo(e,t){if(e.length===0){console.log(`No tasks found`);return}let n=[];e.forEach(e=>{n.push(lo(e)),t&&e.subtasks&&e.subtasks.length>0&&e.subtasks.forEach(t=>{n.push(uo(t,e.id))})}),console.log(n.join(`
|
|
938
|
+
`))}var po=ao;new class{constructor(e={}){this.config={maxCacheSize:e.maxCacheSize||1e3,ttl:e.ttl||1e3*60*5,maxContextSize:e.maxContextSize||4e3},this.cache=new bt({max:this.config.maxCacheSize,ttl:this.config.ttl,updateAgeOnGet:!0}),this.stats={hits:0,misses:0,invalidations:0}}async getContext(e,t={}){let n=this._getCacheKey(e,t),r=this.cache.get(n);if(r)return this.stats.hits++,r;this.stats.misses++;let i={id:e,metadata:{...t,created:new Date().toISOString()}};return this.cache.set(n,i),i}async updateContext(e,t){let n=await this.getContext(e);Object.assign(n.metadata,t);let r=this._getCacheKey(e,n.metadata);return this.cache.set(r,n),n}invalidateContext(e,t={}){let n=this._getCacheKey(e,t);this.cache.delete(n),this.stats.invalidations++}getCachedData(e){let t=this.cache.get(e);if(t!==void 0)return this.stats.hits++,t;this.stats.misses++}setCachedData(e,t){this.cache.set(e,t)}invalidateCacheKey(e){this.cache.delete(e),this.stats.invalidations++}getStats(){return{hits:this.stats.hits,misses:this.stats.misses,invalidations:this.stats.invalidations,size:this.cache.size,maxSize:this.config.maxCacheSize,ttl:this.config.ttl}}_getCacheKey(e,t){return`${e}:${JSON.stringify(t)}`}};const mo={info:()=>{},warn:()=>{},error:()=>{},debug:()=>{},success:()=>{}};function ho(e,t=mo){let n=e?.file,r=e?.projectRoot;if(n&&H.isAbsolute(n))return n;let i=r?F(r):null;if(n&&i)return H.resolve(i,n);if(i){let e=a(n,{projectRoot:i},t);if(e===null&&!n){let e=H.join(i,`.taskmaster`,`tasks`,`tasks.json`);return t?.info?.(`Core findTasksPath returned null, using default path: ${e}`),e}return e}return a(n,null,t)}function go(e,t=mo){let n=e?.input,r=e?.projectRoot;if(n&&H.isAbsolute(n))return n;let i=r?F(r):null;return n&&i?H.resolve(i,n):i?k(n,{projectRoot:i},t):k(n,null,t)}function _o(e,t=mo){let n=e?.complexityReport,r=e?.projectRoot,i=e?.tag;if(n&&H.isAbsolute(n))return n;let a=r?F(r):null;return n&&a?H.resolve(a,n):a?D(n,{projectRoot:a,tag:i},t):D(n,null,t)}function vo(e,t){if(!t?.projectRoot)throw Error(`projectRoot is required in args to resolve project paths`);let n=F(t.projectRoot);return H.isAbsolute(e)?e:H.resolve(n,e)}function yo(e,t=mo){return ho(e,t)}function bo(e,t=mo){return _o(e,t)}function xo(e,t,n=mo){return Ne(e,t,n)}$e(import.meta.url);function So(e){return{info:(t,...n)=>e.info(t,...n),warn:(t,...n)=>e.warn(t,...n),error:(t,...n)=>e.error(t,...n),debug:(t,...n)=>e.debug?e.debug(t,...n):null,success:(t,...n)=>e.info(t,...n)}}const Co=$e(import.meta.url);H.dirname(Co);const wo=So({info:e=>console.log(B.blue(`ℹ`),e),warn:e=>console.log(B.yellow(`⚠`),e),error:e=>console.error(B.red(`✗`),e),success:e=>console.log(B.green(`✓`),e)});async function To(e={}){let t=Fe()||process.cwd();wo.info(`Starting migration in: ${t}`);let n=H.join(t,`.taskmaster`);if(V.existsSync(n)&&!e.force){wo.warn(`.taskmaster directory already exists. Use --force to overwrite or skip migration.`);return}let r=Eo(t);if(r.length===0){wo.info(`No files to migrate. Project may already be using the new structure.`);return}wo.info(`Migration plan:`);for(let t of r){let n=e.dryRun?`Would move`:`Will move`;wo.info(` ${n}: ${t.from} → ${t.to}`)}if(e.dryRun){wo.info(`Dry run complete. Use --dry-run=false to perform actual migration.`);return}if(!e.yes){let e=(await import(`readline`)).createInterface({input:process.stdin,output:process.stdout}),t=await new Promise(t=>{e.question(`Proceed with migration? (y/N): `,t)});if(e.close(),t.toLowerCase()!==`y`&&t.toLowerCase()!==`yes`){wo.info(`Migration cancelled.`);return}}try{await Do(t,r,e),wo.success(`Migration completed successfully!`),wo.info(`You can now use the new .taskmaster directory structure.`),e.cleanup||wo.info(`Old files were preserved. Use --cleanup to remove them after verification.`)}catch(e){throw wo.error(`Migration failed: ${e.message}`),e}}function Eo(e){let t=[],n=H.join(e,`tasks`);if(V.existsSync(n)){let e=V.readdirSync(n);for(let n of e)t.push({from:H.join(`tasks`,n),to:H.join(`.taskmaster`,`tasks`,n),type:`task`})}let r=H.join(e,`scripts`);if(V.existsSync(r)){let e=V.readdirSync(r);for(let n of e){let e=H.join(r,n);if(V.statSync(e).isFile()){let e,r=n.toLowerCase();if(r.includes(`example`)||r.includes(`template`)||r.includes(`boilerplate`)||r.includes(`sample`))e=H.join(`.taskmaster`,`templates`,n);else if(r.includes(`complexity`)&&r.includes(`report`)&&r.endsWith(`.json`))e=H.join(`.taskmaster`,`reports`,n);else if(r.includes(`prd`)||r.endsWith(`.md`)||r.endsWith(`.txt`))e=H.join(`.taskmaster`,`docs`,n);else{wo.warn(`Skipping migration of '${n}' - uncertain categorization. You may need to move this manually.`);continue}t.push({from:H.join(`scripts`,n),to:e,type:`script`})}}}let i=H.join(e,h);return V.existsSync(i)&&t.push({from:h,to:c,type:`config`}),t}async function Do(e,t,n){let r=H.join(e,`.taskmaster`);V.existsSync(r)||V.mkdirSync(r,{recursive:!0});let i=new Set;for(let e of t){let t=H.dirname(e.to);i.add(t)}for(let t of i){let n=H.join(e,t);V.existsSync(n)||(V.mkdirSync(n,{recursive:!0}),wo.info(`Created directory: ${t}`))}if(n.backup){let t=H.join(e,`.taskmaster-migration-backup`);wo.info(`Creating backup in: ${t}`),V.existsSync(t)&&V.rmSync(t,{recursive:!0,force:!0}),V.mkdirSync(t,{recursive:!0})}for(let r of t){let t=H.join(e,r.from),i=H.join(e,r.to);if(!V.existsSync(t)){wo.warn(`Source file not found: ${r.from}`);continue}if(n.backup){let n=H.join(e,`.taskmaster-migration-backup`,r.from),i=H.dirname(n);V.existsSync(i)||V.mkdirSync(i,{recursive:!0}),V.copyFileSync(t,n)}let a=H.dirname(i);V.existsSync(a)||V.mkdirSync(a,{recursive:!0}),V.copyFileSync(t,i),wo.info(`Migrated: ${r.from} → ${r.to}`),n.cleanup&&V.unlinkSync(t)}if(n.cleanup)for(let t of[`tasks`,`scripts`]){let n=H.join(e,t);if(V.existsSync(n))try{V.readdirSync(n).length===0&&(V.rmdirSync(n),wo.info(`Removed empty directory: ${t}`))}catch{}}}function Oo(e,t,n={}){return ve(e,t,{...n,direction:`forward`,logger:{warn:console.warn}})}var ko=class extends Error{constructor(e,t,n={}){super(t),this.name=`MoveTaskError`,this.code=e,this.data=n}};const Ao={CROSS_TAG_DEPENDENCY_CONFLICTS:`CROSS_TAG_DEPENDENCY_CONFLICTS`,CANNOT_MOVE_SUBTASK:`CANNOT_MOVE_SUBTASK`,SOURCE_TARGET_TAGS_SAME:`SOURCE_TARGET_TAGS_SAME`,TASK_NOT_FOUND:`TASK_NOT_FOUND`,SUBTASK_NOT_FOUND:`SUBTASK_NOT_FOUND`,PARENT_TASK_NOT_FOUND:`PARENT_TASK_NOT_FOUND`,PARENT_TASK_NO_SUBTASKS:`PARENT_TASK_NO_SUBTASKS`,DESTINATION_TASK_NOT_FOUND:`DESTINATION_TASK_NOT_FOUND`,TASK_ALREADY_EXISTS:`TASK_ALREADY_EXISTS`,INVALID_TASKS_FILE:`INVALID_TASKS_FILE`,ID_COUNT_MISMATCH:`ID_COUNT_MISMATCH`,INVALID_SOURCE_TAG:`INVALID_SOURCE_TAG`,INVALID_TARGET_TAG:`INVALID_TARGET_TAG`};function jo(e){if(e==null)return e;if(typeof e==`number`)return Number.isFinite(e)?e:null;if(typeof e==`string`){let t=e.trim();if(t===``)return null;let n=t.includes(`.`)?t.split(`.`)[0]:t,r=parseInt(n,10);return Number.isFinite(r)?r:null}return null}async function Mo(e,t,n,r=!1,i={}){let{projectRoot:a,tag:o}=i,s=t.split(`,`).map(e=>e.trim()),c=n.split(`,`).map(e=>e.trim());if(s.length!==c.length)throw new ko(Ao.ID_COUNT_MISMATCH,`Number of source IDs (${s.length}) must match number of destination IDs (${c.length})`);if(s.length>1){let t=[];for(let n=0;n<s.length;n++){let r=await Mo(e,s[n],c[n],!1,i);t.push(r)}return{message:`Successfully moved ${s.length} tasks/subtasks`,moves:t}}let l=w(e,a,o);if(l&&l._rawTaggedData&&(l=l._rawTaggedData),!l||!l[o]||!Array.isArray(l[o].tasks))throw new ko(Ao.INVALID_TASKS_FILE,`Invalid tasks file or tag "${o}" not found at ${e}`);let u=l[o].tasks;z(`info`,`Moving task/subtask ${t} to ${n} (tag: ${o})`);let d=t.includes(`.`),f=n.includes(`.`),p;return p=d&&f?No(u,t,n):d&&!f?Po(u,t,n):!d&&f?Fo(u,t,n):Io(u,t,n),l[o].tasks=u,_(e,l,i.projectRoot,o),p}function No(e,t,n){let[r,i]=t.split(`.`).map(e=>parseInt(e,10)),[a,o]=n.split(`.`).map(e=>parseInt(e,10)),s=e.find(e=>e.id===r),c=e.find(e=>e.id===a);if(!s)throw new ko(Ao.PARENT_TASK_NOT_FOUND,`Source parent task with ID ${r} not found`);if(!c)throw new ko(Ao.PARENT_TASK_NOT_FOUND,`Destination parent task with ID ${a} not found`);s.subtasks||=[],c.subtasks||=[];let l=s.subtasks.findIndex(e=>e.id===i);if(l===-1)throw new ko(Ao.SUBTASK_NOT_FOUND,`Source subtask ${t} not found`);let u=s.subtasks[l];if(r===a)if(c.subtasks.length>0){let e=c.subtasks.findIndex(e=>e.id===o);if(e!==-1){s.subtasks.splice(l,1);let t=l<e?e-1:e;c.subtasks.splice(t+1,0,u)}else s.subtasks.splice(l,1),c.subtasks.push(u)}else s.subtasks.splice(l,1),c.subtasks.push(u);else Lo(u,s,l,c,o);return{message:`Moved subtask ${t} to ${n}`,movedItem:u}}function Po(e,t,n){let[r,i]=t.split(`.`).map(e=>parseInt(e,10)),a=parseInt(n,10),o=e.find(e=>e.id===r);if(!o)throw new ko(Ao.PARENT_TASK_NOT_FOUND,`Source parent task with ID ${r} not found`);if(!o.subtasks)throw new ko(Ao.PARENT_TASK_NO_SUBTASKS,`Source parent task ${r} has no subtasks`);let s=o.subtasks.findIndex(e=>e.id===i);if(s===-1)throw new ko(Ao.SUBTASK_NOT_FOUND,`Source subtask ${t} not found`);let c=o.subtasks[s];if(e.find(e=>e.id===a))throw new ko(Ao.TASK_ALREADY_EXISTS,`Cannot move to existing task ID ${a}. Choose a different ID or use subtask destination.`);let l={id:a,title:c.title,description:c.description,status:c.status||`pending`,dependencies:c.dependencies||[],priority:c.priority||`medium`,details:c.details||``,testStrategy:c.testStrategy||``,subtasks:[]};o.subtasks.splice(s,1);let u=e.findIndex(e=>e.id>a);return u===-1?e.push(l):e.splice(u,0,l),{message:`Converted subtask ${t} to task ${n}`,movedItem:l}}function Fo(e,t,n){let r=parseInt(t,10),[i,a]=n.split(`.`).map(e=>parseInt(e,10)),o=e.findIndex(e=>e.id===r),s=e.find(e=>e.id===i);if(o===-1)throw new ko(Ao.TASK_NOT_FOUND,`Source task with ID ${r} not found`);if(!s)throw new ko(Ao.PARENT_TASK_NOT_FOUND,`Destination parent task with ID ${i} not found`);let c=e[o];s.subtasks||=[];let l={id:a,title:c.title,description:c.description,status:c.status||`pending`,dependencies:c.dependencies||[],details:c.details||``,testStrategy:c.testStrategy||``},u=-1;s.subtasks.length>0&&(u=s.subtasks.findIndex(e=>e.id===a),u===-1&&(u=s.subtasks.length-1));let d=u===-1?0:u+1;return s.subtasks.splice(d,0,l),e.splice(o,1),{message:`Converted task ${t} to subtask ${n}`,movedItem:l}}function Io(e,t,n){let r=parseInt(t,10),i=parseInt(n,10),a=e.findIndex(e=>e.id===r);if(a===-1)throw new ko(Ao.TASK_NOT_FOUND,`Source task with ID ${r} not found`);let o=e[a],s=e.findIndex(e=>e.id===i);if(s!==-1)throw e[s],new ko(Ao.TASK_ALREADY_EXISTS,`Task with ID ${i} already exists. Use a different destination ID.`);return Ro(e,a,o,i)}function Lo(e,t,n,r,i){let a=parseInt(i,10),o={...e,id:a};r.subtasks||=[];let s=-1;r.subtasks.length>0&&(s=r.subtasks.findIndex(e=>e.id===a),s===-1&&(s=r.subtasks.length-1));let c=s===-1?0:s+1;return r.subtasks.splice(c,0,o),t.subtasks.splice(n,1),o}function Ro(e,t,n,r){let i=e.findIndex(e=>e.id===r),a={...n,id:r};e.forEach(e=>{if(e.dependencies&&e.dependencies.includes(n.id)){let t=e.dependencies.indexOf(n.id);e.dependencies[t]=r}e.subtasks&&e.subtasks.forEach(e=>{if(e.dependencies&&e.dependencies.includes(n.id)){let t=e.dependencies.indexOf(n.id);e.dependencies[t]=r}})}),Array.isArray(a.subtasks)&&a.subtasks.forEach(e=>{Array.isArray(e.dependencies)&&(e.dependencies=e.dependencies.map(e=>{if(typeof e==`string`&&e.includes(`.`)){let[t,i]=e.split(`.`);if(parseInt(t,10)===n.id)return`${r}.${i}`}return e}))}),e.splice(t,1);let o=t<i?i-1:i;return o>=0&&o<e.length?e[o]=a:e.push(a),z(`info`,`Moved task ${n.id} to new ID ${r}`),{message:`Moved task ${n.id} to new ID ${r}`,movedItem:a}}function zo(e){let t=[];for(let n in e)if(Object.prototype.hasOwnProperty.call(e,n)&&e[n]&&Array.isArray(e[n].tasks)){let r=e[n].tasks.map(e=>({...e,tag:n}));t=t.concat(r)}return t}async function Bo(e,t,n,r,i){let{projectRoot:a}=i,o=w(e,a,n);if(o&&o._rawTaggedData&&(o=o._rawTaggedData),!o||!o[n]||!Array.isArray(o[n].tasks))throw new ko(Ao.INVALID_SOURCE_TAG,`Source tag "${n}" not found or invalid`);o[r]||(o[r]={tasks:[]},z(`info`,`Created new tag "${r}"`));let s=t.map(e=>String(e)),c=o[n].tasks.filter(e=>{let t=String(e.id);return s.includes(t)});return t.forEach(e=>{Ql(e,n,r)}),{rawData:o,sourceTasks:c}}async function Vo(e){let{rawData:t,sourceTasks:n}=e;return{rawData:t,sourceTasks:n,allTasks:zo(t)}}async function Ho(e,t,n,r,i,a){let{withDependencies:o=!1,ignoreDependencies:s=!1}=n,c=Array.isArray(t)?t.filter(e=>e&&e.tag===i):[];if(o){let t=Oo(e,c,{maxDepth:100,includeSelf:!1}),n=new Set(c.map(e=>typeof e.id==`string`?parseInt(e.id,10):e.id)),i=t.filter(e=>{let t=jo(e);return Number.isFinite(t)&&n.has(t)}),a=[...new Set([...r,...i])];return z(`info`,`Moving ${a.length} tasks (including dependencies): ${a.join(`, `)}`),{tasksToMove:a,dependencyResolution:{type:`with-dependencies`,dependentTasks:i}}}let l=Zl(e,i,a,t);if(l.length>0){if(s)return e.forEach(e=>{let n=c,r=Array.isArray(t)?t.filter(e=>e&&e.tag===a):[];e.dependencies=e.dependencies.filter(e=>{let t=jo(e);return Number.isFinite(t)&&n.some(e=>e.id===t)?!1:(Number.isFinite(t)&&r.some(e=>e.id===t),!0)})}),z(`warn`,`Removed ${l.length} cross-tag dependencies`),{tasksToMove:r,dependencyResolution:{type:`ignored-dependencies`,conflicts:l}};throw new ko(Ao.CROSS_TAG_DEPENDENCY_CONFLICTS,`Cannot move tasks: ${l.length} cross-tag dependency conflicts found`,{conflicts:l,sourceTag:i,targetTag:a,taskIds:r})}return{tasksToMove:r,dependencyResolution:{type:`no-conflicts`}}}async function Uo(e,t,n,r,i,a){let{projectRoot:o}=i,s=[];for(let i of e){let e=typeof i==`string`?parseInt(i,10):i,a=r[t].tasks.findIndex(t=>t.id===e);if(a===-1)throw new ko(Ao.TASK_NOT_FOUND,`Task ${i} not found in source tag "${t}"`);let o=r[t].tasks[a];if(r[n].tasks.findIndex(t=>t.id===e)!==-1)throw new ko(Ao.TASK_ALREADY_EXISTS,`Task ${i} already exists in target tag "${n}"`,{conflictingId:e,targetTag:n,suggestions:[`Choose a different target tag without conflicting IDs`,`Move a different set of IDs (avoid existing ones)`,`If needed, move within-tag to a new ID first, then cross-tag move`]});r[t].tasks.splice(a,1);let c=Ko(o,t,n);r[n].tasks.push(c),s.push({id:i,fromTag:t,toTag:n}),z(`info`,`Moved task ${i} from "${t}" to "${n}"`)}return{rawData:r,movedTasks:s}}async function Wo(e,t,n,r,i,a){let{projectRoot:o}=n,{rawData:s,movedTasks:c}=e;_(t,s,o,null);let l={message:`Successfully moved ${c.length} tasks from "${r}" to "${i}"`,movedTasks:c};return a&&a.type===`ignored-dependencies`&&(l.tips=[`Run "task-master validate-dependencies" to check for dependency issues.`,`Run "task-master fix-dependencies" to automatically repair dangling dependencies.`]),l}async function Go(e,t,n,r,i={},a={}){let{rawData:o,sourceTasks:s,allTasks:c}=await Vo(await Bo(e,t,n,r,a)),{tasksToMove:l,dependencyResolution:u}=await Ho(s,c,i,t,n,r);return await Wo(await Uo(l,n,r,o,a,e),e,a,n,r,u)}function Ko(e,t,n){return e.tag=n,e.metadata||={},e.metadata.moveHistory||(e.metadata.moveHistory=[]),e.metadata.moveHistory.push({fromTag:t,toTag:n,timestamp:new Date().toISOString()}),e}var qo=Mo,Jo=class e extends Error{constructor(t,n){super(t),this.name=`StreamingError`,this.code=n,Error.captureStackTrace&&Error.captureStackTrace(this,e)}};const Yo={NOT_ASYNC_ITERABLE:`STREAMING_NOT_SUPPORTED`,STREAM_PROCESSING_FAILED:`STREAM_PROCESSING_FAILED`,STREAM_NOT_ITERABLE:`STREAM_NOT_ITERABLE`,BUFFER_SIZE_EXCEEDED:`BUFFER_SIZE_EXCEEDED`};var Xo=class e{static async withTimeout(e,t,n=`Operation`){let r,i=new Promise((e,i)=>{r=setTimeout(()=>{i(new Jo(`${n} timed out after ${t/1e3} seconds`,Yo.STREAM_PROCESSING_FAILED))},t)});try{let t=await Promise.race([e,i]);return clearTimeout(r),t}catch(e){throw clearTimeout(r),e}}static async withSoftTimeout(e,t,n=void 0){let r,i=new Promise(e=>{r=setTimeout(()=>{e(n)},t)});try{let t=await Promise.race([e,i]);return clearTimeout(r),t}catch{return clearTimeout(r),n}}static createController(t,n=`Operation`){return{timeoutMs:t,operationName:n,async wrap(r,i=null){let a=i?`${n} - ${i}`:n;return e.withTimeout(r,t,a)},async wrapSoft(n,r=void 0){return e.withSoftTimeout(n,t,r)}}}static isTimeoutError(e){return e instanceof Jo&&e.code===Yo.STREAM_PROCESSING_FAILED&&e.message.includes(`timed out`)}},Zo=class e{constructor(e,t=`ms`){this.milliseconds=this._toMilliseconds(e,t)}static milliseconds(t){return new e(t,`ms`)}static seconds(t){return new e(t,`s`)}static minutes(t){return new e(t,`m`)}static hours(t){return new e(t,`h`)}get seconds(){return this.milliseconds/1e3}get minutes(){return this.milliseconds/6e4}get hours(){return this.milliseconds/36e5}toString(){return this.milliseconds<1e3?`${this.milliseconds}ms`:this.milliseconds<6e4?`${this.seconds}s`:this.milliseconds<36e5?`${Math.floor(this.minutes)}m ${Math.floor(this.seconds%60)}s`:`${Math.floor(this.hours)}h ${Math.floor(this.minutes%60)}m`}_toMilliseconds(e,t){return e*({ms:1,s:1e3,m:6e4,h:36e5}[t]||1)}};const Qo=U.object({id:U.number(),title:U.string().min(1),description:U.string().min(1),details:U.string(),testStrategy:U.string(),priority:U.enum(ca),dependencies:U.array(U.number()),status:U.string()}),$o=U.object({tasks:U.array(Qo),metadata:U.union([U.object({projectName:U.string(),totalTasks:U.number(),sourceFile:U.string(),generatedAt:U.string()}).strict(),U.null()]).default(null)});var es=class{constructor(e,t,n,r={}){this.prdPath=e,this.tasksPath=t,this.numTasks=n,this.force=r.force||!1,this.append=r.append||!1,this.research=r.research||!1,this.reportProgress=r.reportProgress,this.mcpLog=r.mcpLog,this.session=r.session,this.projectRoot=r.projectRoot,this.tag=r.tag,this.streamingTimeout=r.streamingTimeout||Zo.seconds(180).milliseconds,this.targetTag=this.tag||fe(this.projectRoot)||`master`,this.isMCP=!!this.mcpLog,this.outputFormat=this.isMCP&&!this.reportProgress?`json`:`text`,this.useStreaming=!1}hasCodebaseAnalysis(e=null){return b(this.research,this.projectRoot,this.session,e)}},ts=class{constructor(e,t){this.isMCP=!!e,this.outputFormat=this.isMCP&&!t?`json`:`text`,this.logFn=e||{info:(...e)=>z(`info`,...e),warn:(...e)=>z(`warn`,...e),error:(...e)=>z(`error`,...e),debug:(...e)=>z(`debug`,...e),success:(...e)=>z(`success`,...e)}}report(e,t=`info`){this.logFn&&typeof this.logFn[t]==`function`?this.logFn[t](e):!L()&&this.outputFormat===`text`&&z(t,e)}};function ns(e){return`${Math.floor(e/60)}m ${Math.floor(e%60).toString().padStart(2,`0`)}s`}const rs={BAR_WIDTH:40,TABLE_COL_WIDTHS:[28,50],DEFAULT_MODEL:`Default`,DEFAULT_TEMPERATURE:.7},Q={HIGH:`high`,MEDIUM:`medium`,LOW:`low`},is={[Q.HIGH]:`#CC0000`,[Q.MEDIUM]:`#FF8800`,[Q.LOW]:`#FFCC00`},as={main:{padding:{top:1,bottom:1,left:2,right:2},margin:{top:0,bottom:0},borderColor:`blue`,borderStyle:`round`},summary:{padding:{top:1,right:1,bottom:1,left:1},borderColor:`blue`,borderStyle:`round`,margin:{top:1,right:1,bottom:1,left:0}},warning:{padding:1,borderColor:`yellow`,borderStyle:`round`,margin:{top:1,bottom:1}},nextSteps:{padding:1,borderColor:`cyan`,borderStyle:`round`,margin:{top:1,right:0,bottom:1,left:0}}};function os({prdFilePath:e,outputPath:t,numTasks:n,model:r,temperature:i,append:a,research:o}){let s=a?`Appending`:`Generating`,c=`Model: ${r} | Temperature: ${i}`;return o&&(c+=` | ${B.cyan.bold(`🔬 Research Mode`)}`),B.bold(`🤖 Parsing PRD and ${s} Tasks`)+`
|
|
935
939
|
`+B.dim(c)+`
|
|
936
940
|
|
|
937
941
|
`+B.blue(`Input: ${e}`)+`
|
|
938
942
|
`+B.blue(`Output: ${t}`)+`
|
|
939
|
-
`+B.blue(`Tasks to ${a?`Append`:`Generate`}: ${n}`)}function
|
|
940
|
-
`);console.log(W(u,
|
|
943
|
+
`+B.blue(`Tasks to ${a?`Append`:`Generate`}: ${n}`)}function ss(e){console.log(W(e,as.main))}function cs(e,t){console.log(B.yellow.bold(`📝 Append mode`)+` - Adding to ${e} existing tasks (next ID: ${t})`)}function ls(e){let t=B.red.bold(`⚠️ Force flag enabled`);return e?`${t} - Will overwrite if conflicts occur`:`${t} - Overwriting existing tasks`}function us({prdFilePath:e,outputPath:t,numTasks:n,model:r=rs.DEFAULT_MODEL,temperature:i=rs.DEFAULT_TEMPERATURE,append:a=!1,research:o=!1,force:s=!1,existingTasks:c=[],nextId:l=1}){if(!e||typeof e!=`string`||e.trim()===``)throw Error(`prdFilePath is required and must be a non-empty string`);if(!t||typeof t!=`string`||t.trim()===``)throw Error(`outputPath is required and must be a non-empty string`);ss(os({prdFilePath:e,outputPath:t,numTasks:n,model:r,temperature:i,append:a,research:o})),(a||s)&&(a&&cs(c.length,l),s&&console.log(ls(a)),console.log())}function ds(e,t){let n={};return Object.values(Q).forEach(r=>{let i=e[r]||0;n[r]={count:i,percentage:t>0?Math.round(i/t*100):0}}),n}function fs(e,t){let n=rs.BAR_WIDTH,r={};if(t===0)return Object.values(Q).forEach(e=>{r[e]=0}),r;let i={};Object.values(Q).forEach(r=>{i[r]=e[r].count/t*n}),Object.values(Q).forEach(e=>{r[e]=Math.floor(i[e])}),Object.values(Q).forEach(t=>{e[t].count>0&&r[t]===0&&(r[t]=1)});let a=n-Object.values(r).reduce((e,t)=>e+t,0);if(a>0){let e=Object.values(Q).map(e=>({priority:e,decimal:i[e]-Math.floor(i[e])})).sort((e,t)=>t.decimal-e.decimal);for(let t=0;t<a&&t<e.length;t++)r[e[t].priority]++}return r}function ps(e){let t=``;t+=B.hex(is[Q.HIGH])(`█`.repeat(e[Q.HIGH])),t+=B.hex(is[Q.MEDIUM])(`█`.repeat(e[Q.MEDIUM])),t+=B.yellow(`█`.repeat(e[Q.LOW]));let n=Object.values(e).reduce((e,t)=>e+t,0);return n<rs.BAR_WIDTH&&(t+=B.gray(`░`.repeat(rs.BAR_WIDTH-n))),t}function ms(e){let t=[];return Object.entries(Q).forEach(([n,r])=>{let i=e[r],a=r===Q.HIGH?B.hex(is[Q.HIGH]):r===Q.MEDIUM?B.hex(is[Q.MEDIUM]):B.yellow,o=n.charAt(0)+n.slice(1).toLowerCase();t.push(`${a.bold(i.count)} ${a(o)} (${i.percentage}%)`)}),[B.cyan(`Priority distribution:`),t.join(` · `)]}function hs(e){let{totalTasks:t,taskPriorities:n={},prdFilePath:r,outputPath:i,elapsedTime:a,usedFallback:o=!1,actionVerb:s=`generated`}=e,c=ns(a),l=new K({chars:{top:``,"top-mid":``,"top-left":``,"top-right":``,bottom:``,"bottom-mid":``,"bottom-left":``,"bottom-right":``,left:``,"left-mid":``,mid:``,"mid-mid":``,right:``,"right-mid":``,middle:` `},style:{border:[],"padding-left":2},colWidths:rs.TABLE_COL_WIDTHS});if(l.push([B.cyan(`Total tasks ${s}:`),B.bold(t)],[B.cyan(`Processing time:`),B.bold(c)]),n&&Object.keys(n).length>0){let e=ds(n,t),r=ms(e);l.push(r);let i=ps(fs(e,t));l.push([B.cyan(`Distribution:`),i])}l.push([B.cyan(`PRD source:`),B.italic(r)],[B.cyan(`Tasks file:`),B.italic(i)]),o&&l.push([B.yellow(`Fallback parsing:`),B.yellow(`✓ Used fallback parsing`)]);let u=[B.bold.underline(`PRD Parsing Complete - Tasks ${s.charAt(0).toUpperCase()+s.slice(1)}`),``,l.toString()].join(`
|
|
944
|
+
`);console.log(W(u,as.summary)),o&&gs(),_s()}function gs(){let e=B.yellow.bold(`⚠️ Fallback Parsing Used`)+`
|
|
941
945
|
|
|
942
946
|
`+B.white(`The system used fallback parsing to complete task generation.`)+`
|
|
943
947
|
`+B.white(`This typically happens when streaming JSON parsing is incomplete.`)+`
|
|
@@ -945,22 +949,22 @@ ${B.cyan(`1.`)} Run ${B.yellow(`task-master next`)} to see what to work on next\
|
|
|
945
949
|
`+B.white(`• Reviewing task completeness`)+`
|
|
946
950
|
`+B.white(`• Checking for any missing details`)+`
|
|
947
951
|
|
|
948
|
-
`+B.white(`This is normal and usually doesn't indicate any issues.`);console.log(W(e,
|
|
952
|
+
`+B.white(`This is normal and usually doesn't indicate any issues.`);console.log(W(e,as.warning))}function _s(){let e=B.white.bold(`Next Steps:`)+`
|
|
949
953
|
|
|
950
|
-
${B.cyan(`1.`)} Run ${B.yellow(`task-master list`)} to view all tasks\n${B.cyan(`2.`)} Run ${B.yellow(`task-master expand --id=<id>`)} to break down a task into subtasks\n${B.cyan(`3.`)} Run ${B.yellow(`task-master analyze-complexity`)} to analyze task complexity`;console.log(W(e,
|
|
954
|
+
${B.cyan(`1.`)} Run ${B.yellow(`task-master list`)} to view all tasks\n${B.cyan(`2.`)} Run ${B.yellow(`task-master expand --id=<id>`)} to break down a task into subtasks\n${B.cyan(`3.`)} Run ${B.yellow(`task-master analyze-complexity`)} to analyze task complexity`;console.log(W(e,as.nextSteps))}function vs(e){return Math.ceil(e.length/4)}function ys(e){let t=V.readFileSync(e,`utf8`);if(!t)throw Error(`Input file ${e} is empty or could not be read.`);return t}function bs(e,t){let n=[],r=1;if(!V.existsSync(e))return{existingTasks:n,nextId:r};try{let i=V.readFileSync(e,`utf8`),a=JSON.parse(i);a[t]?.tasks&&Array.isArray(a[t].tasks)&&(n=a[t].tasks,n.length>0&&(r=Math.max(...n.map(e=>e.id||0))+1))}catch{return{existingTasks:[],nextId:1}}return{existingTasks:n,nextId:r}}function xs({existingTasks:e,targetTag:t,append:n,force:r,isMCP:i,logger:a}){if(!(e.length>0)){a.report(`Tag '${t}' is empty or doesn't exist. Creating/updating tag with new tasks.`,`info`);return}if(n){a.report(`Append mode enabled. Found ${e.length} existing tasks in tag '${t}'.`,`info`);return}if(!r){let n=`Tag '${t}' already contains ${e.length} tasks. Use --force to overwrite or --append to add to existing tasks.`;if(a.report(n,`error`),i)throw Error(n);console.error(B.red(n)),process.exit(1)}a.report(`Force flag enabled. Overwriting existing tasks in tag '${t}'.`,`debug`)}function Ss(e,t,n,r){Cs(e,t);let i=t,a=new Map,o=e.map(e=>{let t=i++;return a.set(e.id,t),{...e,id:t,status:e.status||`pending`,priority:e.priority||r,dependencies:Array.isArray(e.dependencies)?e.dependencies:[],subtasks:e.subtasks||[],title:e.title||``,description:e.description||``,details:e.details||``,testStrategy:e.testStrategy||``}});return o.forEach(e=>{e.dependencies=e.dependencies.map(e=>a.get(e)).filter(t=>t!=null&&t<e.id&&(ie(n,t)||o.some(e=>e.id===t)))}),o}function Cs(e,t=1){if(!Array.isArray(e)||e.length===0)return;let n=e.map(e=>e.id);if(n.some(e=>!Number.isInteger(e)||e<1))throw Error(`PRD tasks must use sequential positive integer IDs starting at 1.`);let r=new Set(n);if(r.size!==n.length)throw Error(`PRD task IDs must be unique and sequential starting at 1.`);let i=[...r].sort((e,t)=>e-t),a=i[0];if(a!==1&&a!==t)throw Error(`PRD task IDs must start at 1 or ${t} and be sequential.`);for(let e=0;e<i.length;e+=1)if(i[e]!==a+e)throw Error(`PRD task IDs must be a contiguous sequence starting at ${a}.`)}function ws(e,t,n,r){let i=H.dirname(e);V.existsSync(i)||V.mkdirSync(i,{recursive:!0});let a={};if(V.existsSync(e))try{let t=V.readFileSync(e,`utf8`);a=JSON.parse(t)}catch{a={}}a[n]={tasks:t,metadata:{created:a[n]?.metadata?.created||new Date().toISOString(),updated:new Date().toISOString(),description:`Tasks for ${n} context`}},ne(a[n],{description:`Tasks for ${n} context`}),V.writeFileSync(e,JSON.stringify(a,null,2)),r.report(`Successfully saved ${t.length} tasks to ${e}`,`debug`)}async function Ts(e,t,n){let r=La(),i=ce(e.projectRoot)||`medium`;return r.loadPrompt(`parse-prd`,{research:e.research,numTasks:e.numTasks,nextId:n,prdContent:t,prdPath:e.prdPath,defaultTaskPriority:i,hasCodebaseAnalysis:e.hasCodebaseAnalysis({command:`parse-prd`,prdContent:t,numTasks:e.numTasks}),projectRoot:e.projectRoot||``})}async function Es({task:e,currentCount:t,totalTasks:n,estimatedTokens:r,progressTracker:i,reportProgress:a,priorityMap:o,defaultPriority:s,estimatedInputTokens:c}){let l=e.priority||s,u=o[l]||o.medium;if(i&&(i.addTaskLine(t,e.title,l),r&&i.updateTokens(c,r)),a)try{let i=r?Math.floor(r/n):0;await a({progress:t,total:n,message:`${u} Task ${t}/${n} - ${e.title} | ~Output: ${i} tokens`})}catch{}}async function Ds({processedTasks:e,nextId:t,summary:n,prdPath:r,tasksPath:i,usedFallback:a,aiServiceResponse:o}){let s=(()=>{if(!Array.isArray(e)||e.length===0)return`task_${String(t).padStart(3,`0`)}.txt`;let n=e[0].id,r=e[e.length-1].id;return e.length===1?`task_${String(n).padStart(3,`0`)}.txt`:`task_${String(n).padStart(3,`0`)}.txt -> task_${String(r).padStart(3,`0`)}.txt`})();hs({totalTasks:e.length,taskPriorities:n.taskPriorities,prdFilePath:r,outputPath:i,elapsedTime:n.elapsedTime,usedFallback:a,taskFilesGenerated:s,actionVerb:n.actionVerb}),o?.telemetryData&&(o.mainResult?.usage&&await Xo.withSoftTimeout(o.mainResult.usage,1e3,void 0),Ml(o.telemetryData,`cli`))}function Os({processedTasks:e,research:t,finalTasks:n,tasksPath:r,aiServiceResponse:i}){console.log(W(B.green(`Successfully generated ${e.length} new tasks${t?` with research-backed analysis`:``}. Total tasks in ${r}: ${n.length}`),{padding:1,borderColor:`green`,borderStyle:`round`})),console.log(W(B.white.bold(`Next Steps:`)+`
|
|
951
955
|
|
|
952
|
-
${B.cyan(`1.`)} Run ${B.yellow(`task-master list`)} to view all tasks\n${B.cyan(`2.`)} Run ${B.yellow(`task-master expand --id=<id>`)} to break down a task into subtasks`,{padding:1,borderColor:`cyan`,borderStyle:`round`,margin:{top:1}})),i?.telemetryData&&
|
|
953
|
-
`).start());try{n.report(`Calling AI service to generate tasks from PRD${e.research?` with research-backed analysis`:``}...`,`info`);let t=await i({role:e.research?`research`:`main`,session:e.session,projectRoot:e.projectRoot,schema:Xo,objectName:`tasks_data`,systemPrompt:r,prompt:a,commandName:`parse-prd`,outputType:e.isMCP?`mcp`:`cli`}),c=null;if(t?.mainResult&&(typeof t.mainResult==`object`&&t.mainResult!==null&&`tasks`in t.mainResult?c=t.mainResult:typeof t.mainResult.object==`object`&&t.mainResult.object!==null&&`tasks`in t.mainResult.object&&(c=t.mainResult.object)),!c||!Array.isArray(c.tasks))throw Error(`AI service returned unexpected data structure after validation.`);return s&&s.succeed(`Tasks generated successfully!`),{parsedTasks:c.tasks,aiServiceResponse:t,estimatedInputTokens:o}}catch(e){throw s&&s.fail(`Error parsing PRD: ${e.message}`),e}}const[Ds,Os,ks]=aa,As=new Map;var js=class{constructor(e,t,n,r=null){this.name=e,this.levels=t,this.colors=n,this.thresholds=r}getColor(e){return this.colors[e]||B.gray}getLevelFromScore(e){if(!this.thresholds)throw Error(`${this.name} does not support score-based levels`);return e>=7?this.levels[0]:e<=3?this.levels[2]:this.levels[1]}};const Ms={cli:{filled:`●`,empty:`○`},statusBar:{high:`⋮`,medium:`:`,low:`.`},mcp:{high:`🔴`,medium:`🟠`,low:`🟢`}},Ns=new js(`priority`,[Ds,Os,ks],{[Ds]:B.hex(`#CC0000`),[Os]:B.hex(`#FF8800`),[ks]:B.yellow});function Ps(e,t){let n=Ms.cli.filled,r=Ms.cli.empty,i=``;for(let a=0;a<3;a++)a<e?i+=t(n):i+=B.white(r);return i}function Fs(e,t){return 3-t.indexOf(e)}function Is(e,t){if(As.has(e))return As.get(e);let n=t();return As.set(e,n),n}function Ls(){return Is(`mcp-priority-all`,()=>({[Ds]:Ms.mcp.high,[Os]:Ms.mcp.medium,[ks]:Ms.mcp.low}))}function Rs(){return Is(`cli-priority-all`,()=>{let e={};return Ns.levels.forEach(t=>{e[t]=Ps(Fs(t,Ns.levels),Ns.getColor(t))}),e})}function zs(){return Is(`statusbar-priority-all`,()=>{let e={};return Ns.levels.forEach((t,n)=>{let r=n===0?Ms.statusBar.high:n===1?Ms.statusBar.medium:Ms.statusBar.low;e[t]=Ns.getColor(t)(r)}),e})}function Bs(){return{[Ds]:Ns.colors[Ds],[Os]:Ns.colors[Os],[ks]:Ns.colors[ks]}}function Vs(e=!1){return e?Ls():Rs()}function Hs(e,t=!1){let n=Vs(t);return n[e]||n[Os]}new js(`complexity`,[`high`,`medium`,`low`],{high:B.hex(`#CC0000`),medium:B.hex(`#FF8800`),low:B.green},{high:e=>e>=7,medium:e=>e>=4&&e<=6,low:e=>e<=3});const Us={clearOnComplete:!1,stopOnComplete:!0,hideCursor:!0,barsize:40},Ws={shades_classic:mt.Presets.shades_classic,shades_grey:mt.Presets.shades_grey,rect:mt.Presets.rect,legacy:mt.Presets.legacy},Gs=new class{constructor(e={},t=Ws.shades_classic){this.defaultOptions={...Us,...e},this.defaultPreset=t}createSingleBar(e={},t=null){let n=this._mergeConfig(e),r=t||this.defaultPreset;return new mt.SingleBar(n,r)}createMultiBar(e={},t=null){let n=this._mergeConfig(e),r=t||this.defaultPreset;return new mt.MultiBar(n,r)}_mergeConfig(e){return{...this.defaultOptions,...e}}setDefaultOptions(e){this.defaultOptions={...this.defaultOptions,...e}}setDefaultPreset(e){this.defaultPreset=e}};function Ks(e={}){return Gs.createMultiBar(e)}var qs=class{constructor(e={}){this.numUnits=e.numUnits||1,this.unitName=e.unitName||`unit`,this.startTime=null,this.completedUnits=0,this.tokensIn=0,this.tokensOut=0,this.isEstimate=!0,this.bestAvgTimePerUnit=null,this.lastEstimateTime=null,this.lastEstimateSeconds=0,this.multibar=null,this.timeTokensBar=null,this.progressBar=null,this._timerInterval=null,this.isStarted=!1,this.isFinished=!1,this._initializeCustomProperties(e)}_initializeCustomProperties(e){}get unitNamePlural(){return`${this.unitName}s`}start(){this.isStarted||this.isFinished||(this.isStarted=!0,this.startTime=Date.now(),this.multibar=Ks(),this.timeTokensBar=this.multibar.create(1,0,{},{format:this._getTimeTokensBarFormat(),barsize:1,hideCursor:!0,clearOnComplete:!1}),this.progressBar=this.multibar.create(this.numUnits,0,{},{format:this._getProgressBarFormat(),barCompleteChar:`█`,barIncompleteChar:`░`}),this._updateTimeTokensBar(),this.progressBar.update(0,{[this.unitNamePlural]:`0/${this.numUnits}`}),this._timerInterval=setInterval(()=>this._updateTimeTokensBar(),1e3),this._setupCustomUI())}_setupCustomUI(){}_getTimeTokensBarFormat(){return`{clock} {elapsed} | Tokens (I/O): {in}/{out} | Est: {remaining}`}_getProgressBarFormat(){return`${this.unitName.charAt(0).toUpperCase()+this.unitName.slice(1)}s {${this.unitNamePlural}} |{bar}| {percentage}%`}updateTokens(e,t,n=!1){this.tokensIn=e||0,this.tokensOut=t||0,this.isEstimate=n,this._updateTimeTokensBar()}_updateTimeTokensBar(){if(!this.timeTokensBar||this.isFinished)return;let e=this._formatElapsedTime(),t=this._estimateRemainingTime(),n=this.isEstimate?`~ Tokens (I/O)`:`Tokens (I/O)`;this.timeTokensBar.update(1,{clock:`⏱️`,elapsed:e,in:this.tokensIn,out:this.tokensOut,remaining:t,tokensLabel:n,...this._getCustomTimeTokensPayload()})}_getCustomTimeTokensPayload(){return{}}_formatElapsedTime(){if(!this.startTime)return`0m 00s`;let e=Math.floor((Date.now()-this.startTime)/1e3);return`${Math.floor(e/60)}m ${(e%60).toString().padStart(2,`0`)}s`}_estimateRemainingTime(){let e=this._getProgressFraction();if(e>=1)return`~0s`;let t=Date.now(),n=(t-this.startTime)/1e3;if(e===0)return`~calculating...`;let r=n/e;(this.bestAvgTimePerUnit===null||r<this.bestAvgTimePerUnit)&&(this.bestAvgTimePerUnit=r);let i=this.numUnits*(1-e),a=Math.ceil(i*this.bestAvgTimePerUnit);if(this.lastEstimateTime){let e=Math.floor((t-this.lastEstimateTime)/1e3),n=Math.max(0,this.lastEstimateSeconds-e);if(n===0)return`~0s`;a=Math.min(a,n)}return this.lastEstimateTime=t,this.lastEstimateSeconds=a,`~${this._formatDuration(a)}`}_getProgressFraction(){return this.completedUnits/this.numUnits}_formatDuration(e){if(e<60)return`${e}s`;let t=Math.floor(e/60),n=e%60;return t<60?n>0?`${t}m ${n}s`:`${t}m`:`${Math.floor(t/60)}h ${t%60}m`}getElapsedTime(){return this.startTime?Date.now()-this.startTime:0}stop(){this.isFinished||(this.isFinished=!0,this._timerInterval&&=(clearInterval(this._timerInterval),null),this.multibar&&(this._updateTimeTokensBar(),this.multibar.stop()),this.cleanup())}getSummary(){return{completedUnits:this.completedUnits,elapsedTime:this.getElapsedTime()}}cleanup(){if(this._timerInterval&&=(clearInterval(this._timerInterval),null),this.multibar){try{this.multibar.stop()}catch{}this.multibar=null}this.timeTokensBar=null,this.progressBar=null,this.isStarted=!1,this.isFinished=!0,this._performCustomCleanup()}_performCustomCleanup(){}},Js=class{constructor(e){if(!e)throw Error(`Multibar instance is required`);this.multibar=e}createBar(e,t={}){if(typeof e!=`string`)throw Error(`Format must be a string`);let n=this.multibar.create(1,1,{},{format:e,barsize:1,hideCursor:!0,clearOnComplete:!1});return n.update(1,t),n}createHeader(e,t){this.createBar(t),this.createBar(e),this.createBar(t)}createRow(e,t){if(!t||typeof t!=`object`)throw Error(`Payload must be an object`);return this.createBar(e,t)}createBorder(e){return this.createBar(e)}};function Ys(e,t,n){new Js(e).createHeader(t,n)}function Xs(e,t,n){new Js(e).createRow(t,n)}function Zs(e,t){new Js(e).createBorder(t)}Rs();const Qs=zs();Bs();const $s={DEBOUNCE_DELAY:100,MAX_TITLE_LENGTH:57,TRUNCATED_LENGTH:54,TASK_ID_PAD_START:3,TASK_ID_PAD_END:4,PRIORITY_PAD_END:3,VALID_PRIORITIES:[`high`,`medium`,`low`],DEFAULT_PRIORITY:`medium`};var ec=class{constructor(e=$s.DEBOUNCE_DELAY){this.delay=e,this.pendingTimeout=null}debounce(e){this.clear(),this.pendingTimeout=setTimeout(()=>{e(),this.pendingTimeout=null},this.delay)}clear(){this.pendingTimeout&&=(clearTimeout(this.pendingTimeout),null)}hasPending(){return this.pendingTimeout!==null}},tc=class{constructor(){this.priorities={high:0,medium:0,low:0}}increment(e){let t=this.normalize(e);return this.priorities[t]++,t}normalize(e){let t=e?e.toLowerCase():$s.DEFAULT_PRIORITY;return $s.VALID_PRIORITIES.includes(t)?t:$s.DEFAULT_PRIORITY}getCounts(){return{...this.priorities}}},nc=class{static formatTitle(e,t){return e?e.length>$s.MAX_TITLE_LENGTH?e.substring(0,$s.TRUNCATED_LENGTH)+`...`:e:`Task ${t}`}static formatPriority(e){return Hs(e,!1).padEnd($s.PRIORITY_PAD_END,` `)}static formatTaskId(e){return e.toString().padStart($s.TASK_ID_PAD_START,` `).padEnd($s.TASK_ID_PAD_END,` `)}},rc=class extends qs{_initializeCustomProperties(e){this.append=e.append,this.priorityManager=new tc,this.debouncer=new ec,this.headerShown=!1}_getTimeTokensBarFormat(){return`{clock} {elapsed} | ${Qs.high} {high} ${Qs.medium} {medium} ${Qs.low} {low} | Tokens (I/O): {in}/{out} | Est: {remaining}`}_getProgressBarFormat(){return`Tasks {tasks} |{bar}| {percentage}%`}_getCustomTimeTokensPayload(){return this.priorityManager.getCounts()}addTaskLine(e,t,n=`medium`){if(!this.multibar||this.isFinished)return;this._ensureHeaderShown();let r=this._updateTaskCounters(e,n);this._updateTimeTokensBar(),this.debouncer.debounce(()=>{this._updateProgressDisplay(e,t,r)})}_ensureHeaderShown(){this.headerShown||(this.headerShown=!0,Ys(this.multibar,` TASK | PRI | TITLE`,`------+-----+----------------------------------------------------------------`))}_updateTaskCounters(e,t){let n=this.priorityManager.increment(t);return this.completedUnits=e,n}_updateProgressDisplay(e,t,n){this.progressBar.update(this.completedUnits,{tasks:`${this.completedUnits}/${this.numUnits}`});let r=nc.formatTitle(t,e),i=nc.formatPriority(n),a=nc.formatTaskId(e);Xs(this.multibar,` ${a} | ${i} | {title}`,{title:r}),Zs(this.multibar,`------+-----+----------------------------------------------------------------`),this._updateTimeTokensBar()}finish(){this.debouncer.hasPending()&&(this.debouncer.clear(),this._updateTimeTokensBar()),this.cleanup(),super.finish()}_performCustomCleanup(){this.debouncer.clear()}getSummary(){return{...super.getSummary(),taskPriorities:this.priorityManager.getCounts(),actionVerb:this.append?`appended`:`generated`}}};function ic(e={}){return new rc(e)}async function ac(e,t,n){let r=oc(e,t,n);await cc(e,n,r.estimatedInputTokens);let i=await lc(e,t,e.streamingTimeout),{progressTracker:a,priorityMap:o}=await uc(e,n),s=await dc(i.mainResult,e,t,n,a,o,r.defaultPriority,r.estimatedInputTokens,r.logger);if(sc(s),s.usage&&e.projectRoot){let{logAiUsage:t}=await import(`./ai-services-unified-DPFFMTq4.js`),{getUserId:n}=await import(`./config-manager-BI29Nudz.js`),a=n(e.projectRoot);if(a&&i.providerName&&i.modelId)try{let n=await t({userId:a,commandName:`parse-prd`,providerName:i.providerName,modelId:i.modelId,inputTokens:s.usage.promptTokens||0,outputTokens:s.usage.completionTokens||0,outputType:e.isMCP?`mcp`:`cli`});n&&(i.telemetryData=n)}catch(e){r.logger.report(`Failed to log telemetry: ${e.message}`,`debug`)}}return xc(s,i,r.estimatedInputTokens,a)}function oc(e,t,n){let{systemPrompt:r,userPrompt:i}=t;return{logger:new Qo(e.mcpLog,e.reportProgress),estimatedInputTokens:hs(r+i),defaultPriority:ce(e.projectRoot)||`medium`}}function sc(e){if(e.parsedTasks.length===0)throw Error(`No tasks were generated from the PRD`)}async function cc(e,t,n){e.reportProgress&&await e.reportProgress({progress:0,total:t,message:`Starting PRD analysis (Input: ${n} tokens)${e.research?` with research`:``}...`})}async function lc(e,n,r){let{systemPrompt:i,userPrompt:a}=n;return await qo.withTimeout(t({role:e.research?`research`:`main`,session:e.session,projectRoot:e.projectRoot,schema:Xo,systemPrompt:i,prompt:a,commandName:`parse-prd`,outputType:e.isMCP?`mcp`:`cli`}),r,`Streaming operation`)}async function uc(e,t){let n=Vs(e.isMCP),r=null;if(e.outputFormat===`text`&&!e.isMCP){r=ic({numUnits:t,unitName:`task`,append:e.append});let n=e.research?he():l(),i=v(e.research?`research`:`main`);ss({prdFilePath:e.prdPath,outputPath:e.tasksPath,numTasks:t,append:e.append,research:e.research,force:e.force,existingTasks:[],nextId:1,model:n||`Default`,temperature:i?.temperature||.7}),r.start()}return{progressTracker:r,priorityMap:n}}async function dc(e,t,n,r,i,a,o,s,c){let{systemPrompt:l,userPrompt:u}=n,d={config:{...t,schema:Xo},numTasks:r,progressTracker:i,priorityMap:a,defaultPriority:o,estimatedInputTokens:s,prompt:u,systemPrompt:l};try{let t={lastPartialObject:null,taskCount:0,estimatedOutputTokens:0,usage:null};if(await fc(e.partialObjectStream,t,d),e.usage)try{t.usage=await e.usage}catch(e){c.report(`Failed to get usage data: ${e.message}`,`debug`)}return gc(t,d)}catch(e){return c.report(`StreamObject processing failed: ${e.message}. Falling back to generateObject.`,`debug`),await bc(d,c)}}async function fc(e,t,n){for await(let r of e)t.lastPartialObject=r,r&&(t.estimatedOutputTokens=hs(JSON.stringify(r))),await pc(r,t,n)}async function pc(e,t,n){if(!e?.tasks||!Array.isArray(e.tasks))return;let r=e.tasks.length;r>t.taskCount?(await mc(e.tasks,t.taskCount,r,t.estimatedOutputTokens,n),t.taskCount=r):n.progressTracker&&t.estimatedOutputTokens>0&&n.progressTracker.updateTokens(n.estimatedInputTokens,t.estimatedOutputTokens,!0)}async function mc(e,t,n,r,i){for(let a=t;a<n;a++){let t=e[a]||{};t.title?await Cs({task:t,currentCount:a+1,totalTasks:i.numTasks,estimatedTokens:r,progressTracker:i.progressTracker,reportProgress:i.config.reportProgress,priorityMap:i.priorityMap,defaultPriority:i.defaultPriority,estimatedInputTokens:i.estimatedInputTokens}):await hc(a+1,r,i)}}async function hc(e,t,n){let{progressTracker:r,config:i,numTasks:a,defaultPriority:o,estimatedInputTokens:s}=n;r&&(r.addTaskLine(e,`Generating task ${e}...`,o),r.updateTokens(s,t,!0)),i.reportProgress&&!r&&await i.reportProgress({progress:e,total:a,message:`Generating task ${e}/${a}...`})}async function gc(e,t){let{lastPartialObject:n,estimatedOutputTokens:r,taskCount:i,usage:a}=e;if(!n?.tasks||!Array.isArray(n.tasks))throw Error(`No tasks generated from streamObject`);let o=a?.completionTokens||r,s=a?.promptTokens||t.estimatedInputTokens;return t.progressTracker&&await _c(n.tasks,i,a?o:r,t,a?s:null),{parsedTasks:n.tasks,estimatedOutputTokens:o,actualInputTokens:s,usage:a,usedFallback:!1}}async function _c(e,t,n,r,i=null){let{progressTracker:a,defaultPriority:o,estimatedInputTokens:s}=r;t>0?vc(e,a,o):await yc(e,n,r),a.updateTokens(i||s,n,!1),a.stop()}function vc(e,t,n){for(let r=0;r<e.length;r++){let i=e[r];i?.title&&t.addTaskLine(r+1,i.title,i.priority||n)}}async function yc(e,t,n){for(let r=0;r<e.length;r++){let i=e[r];i?.title&&await Cs({task:i,currentCount:r+1,totalTasks:n.numTasks,estimatedTokens:t,progressTracker:n.progressTracker,reportProgress:n.config.reportProgress,priorityMap:n.priorityMap,defaultPriority:n.defaultPriority,estimatedInputTokens:n.estimatedInputTokens})}}async function bc(e,t){if(t.report(`Using generateObject fallback for PRD parsing`,`info`),e.progressTracker)for(let t=0;t<e.numTasks;t++)e.progressTracker.addTaskLine(t+1,`Generating task ${t+1}...`,e.defaultPriority),e.progressTracker.updateTokens(e.estimatedInputTokens,0,!0);let n=await i({role:e.config.research?`research`:`main`,commandName:`parse-prd`,prompt:e.prompt,systemPrompt:e.systemPrompt,schema:e.config.schema,outputFormat:e.config.outputFormat||`text`,projectRoot:e.config.projectRoot,session:e.config.session}),r=n?.mainResult||n;if(r&&Array.isArray(r.tasks)&&(r.tasks=r.tasks.map(e=>({...e,dependencies:e.dependencies??[],priority:e.priority??null,details:e.details??null,testStrategy:e.testStrategy??null}))),r&&Array.isArray(r.tasks)){if(e.progressTracker){for(let t=0;t<r.tasks.length;t++){let n=r.tasks[t];n&&n.title&&e.progressTracker.addTaskLine(t+1,n.title,n.priority||e.defaultPriority)}let t=n.telemetryData?.outputTokens||hs(JSON.stringify(r)),i=n.telemetryData?.inputTokens||e.estimatedInputTokens;e.progressTracker.updateTokens(i,t,!1)}return{parsedTasks:r.tasks,estimatedOutputTokens:n.telemetryData?.outputTokens||hs(JSON.stringify(r)),actualInputTokens:n.telemetryData?.inputTokens,telemetryData:n.telemetryData,usedFallback:!0}}throw Error(`Failed to generate tasks using generateObject fallback`)}function xc(e,t,n,r){let i=null;if(r&&(i=r.getSummary(),r.cleanup()),e.usage&&t){let n=e.usage;t.usage||={promptTokens:n.promptTokens||0,completionTokens:n.completionTokens||0,totalTokens:n.totalTokens||0}}return{parsedTasks:e.parsedTasks,aiServiceResponse:t,estimatedInputTokens:e.actualInputTokens||n,estimatedOutputTokens:e.estimatedOutputTokens,usedFallback:e.usedFallback,progressTracker:r,summary:i}}async function Sc(e,t,n){let r=new Qo(e.mcpLog,e.reportProgress);r.report(`Parsing PRD file: ${e.prdPath}, Force: ${e.force}, Append: ${e.append}, Research: ${e.research}`,`debug`);try{let{existingTasks:i,nextId:a}=_s(e.tasksPath,e.targetTag);vs({existingTasks:i,targetTag:e.targetTag,append:e.append,force:e.force,isMCP:e.isMCP,logger:r});let o=await t(e,await Ss(e,gs(e.prdPath),a),e.numTasks),s=ce(e.projectRoot)||`medium`,c=ys(o.parsedTasks,a,i,s),l=e.append?[...i,...c]:c;return xs(e.tasksPath,l,e.targetTag,r),await Cc(e,o,c,l,a,n),{success:!0,tasksPath:e.tasksPath,telemetryData:o.aiServiceResponse?.telemetryData,tagInfo:o.aiServiceResponse?.tagInfo}}catch(t){throw r.report(`Error parsing PRD: ${t.message}`,`error`),e.isMCP||(console.error(B.red(`Error: ${t.message}`)),be(e.projectRoot)&&console.error(t)),t}}async function Cc(e,t,n,r,i,a){let{aiServiceResponse:o,estimatedInputTokens:s,estimatedOutputTokens:c}=t;if(e.reportProgress){let t=o?.telemetryData&&(o.telemetryData.inputTokens>0||o.telemetryData.outputTokens>0),n;if(t){let e=o.telemetryData.totalCost||0,t=o.telemetryData.currency||`USD`;n=`✅ Task Generation Completed | Tokens (I/O): ${o.telemetryData.inputTokens}/${o.telemetryData.outputTokens} | Cost: ${t===`USD`?`$`:t}${e.toFixed(4)}`}else n=`✅ Task Generation Completed | ~Tokens (I/O): ${s}/${a?c:`unknown`} | Cost: ~$0.00`;await e.reportProgress({progress:e.numTasks,total:e.numTasks,message:n})}e.outputFormat===`text`&&!e.isMCP&&(a&&t.summary?await ws({processedTasks:n,nextId:i,summary:t.summary,prdPath:e.prdPath,tasksPath:e.tasksPath,usedFallback:t.usedFallback,aiServiceResponse:o}):a||Ts({processedTasks:n,research:e.research,finalTasks:r,tasksPath:e.tasksPath,aiServiceResponse:o}))}async function wc(e,t,n,r={}){return Sc(new Zo(e,t,n,r),ac,!0)}async function Tc(e,t,n,r={}){return Sc(new Zo(e,t,n,r),Es,!1)}async function Ec(e,t,n,r={}){let i=new Zo(e,t,n,r);if(i.useStreaming)try{return await wc(e,t,n,r)}catch(a){if(a instanceof Go||a.code===Ko.NOT_ASYNC_ITERABLE||a.code===Ko.STREAM_PROCESSING_FAILED||a.code===Ko.STREAM_NOT_ITERABLE||qo.isTimeoutError(a)){let o=new Qo(i.mcpLog,i.reportProgress);return i.outputFormat===`text`&&!i.isMCP?console.log(B.yellow(`⚠️ Streaming operation ${a.message.includes(`timed out`)?`timed out`:`failed`}. Falling back to non-streaming mode...`)):o.report(`Streaming failed (${a.message}), falling back to non-streaming mode...`,`warn`),await Tc(e,t,n,r)}else throw a}else return await Tc(e,t,n,r)}var Dc=Ec;async function Oc(e,t,n=!1,r=!1,i={}){let{projectRoot:a,tag:o}=i;try{z(`info`,`Removing subtask ${t}...`);let r=w(e,a,o);if(!r||!r.tasks)throw Error(`Invalid or missing tasks file at ${e}`);if(!t.includes(`.`))throw Error(`Invalid subtask ID format: ${t}. Expected format: "parentId.subtaskId"`);let[i,s]=t.split(`.`),c=parseInt(i,10),l=parseInt(s,10),u=r.tasks.find(e=>e.id===c);if(!u)throw Error(`Parent task with ID ${c} not found`);if(!u.subtasks||u.subtasks.length===0)throw Error(`Parent task ${c} has no subtasks`);let d=u.subtasks.findIndex(e=>e.id===l);if(d===-1)throw Error(`Subtask ${t} not found`);let f={...u.subtasks[d]};u.subtasks.splice(d,1),u.subtasks.length===0&&(u.subtasks=void 0);let p=null;if(n){z(`info`,`Converting subtask ${t} to a standalone task...`);let e=Math.max(...r.tasks.map(e=>e.id))+1;p={id:e,title:f.title,description:f.description||``,details:f.details||``,status:f.status||`pending`,dependencies:f.dependencies||[],priority:u.priority||`medium`},p.dependencies.includes(c)||p.dependencies.push(c),r.tasks.push(p),z(`info`,`Created new task ${e} from subtask ${t}`)}else z(`info`,`Subtask ${t} deleted`);return _(e,r,a,o),p}catch(e){throw z(`error`,`Error removing subtask: ${e.message}`),e}}var kc=Oc;function Ac(e,t){if(typeof t==`string`&&t.includes(`.`)){let n=t.split(`.`);if(n.length!==2||!n[0]||!n[1]){let n=parseInt(t,10);return e.some(e=>e.id===n)}let[r,i]=n,a=parseInt(r,10),o=parseInt(i,10),s=e.find(e=>e.id===a);return s&&s.subtasks&&s.subtasks.some(e=>e.id===o)}let n=parseInt(t,10);return e.some(e=>e.id===n)}var jc=Ac;async function Mc(e,t,n={}){let{projectRoot:r,tag:i}=n,a={success:!0,messages:[],errors:[],removedTasks:[]},o=t.split(`,`).map(e=>e.trim()).filter(Boolean);if(o.length===0)return a.success=!1,a.errors.push(`No valid task IDs provided.`),a;try{let t=w(e,r,i);if(!t)throw Error(`Could not read tasks file at ${e}`);let n=t._rawTaggedData||t;if(!n[i]||!n[i].tasks)throw Error(`Tag '${i}' not found or has no tasks.`);let s=n[i].tasks,c=[];for(let e of o){if(!jc(s,e)){let t=`Task with ID ${e} in tag '${i}' not found or already removed.`;a.errors.push(t),a.success=!1;continue}try{if(typeof e==`string`&&e.includes(`.`)){let[t,n]=e.split(`.`).map(e=>parseInt(e,10)),r=s.find(e=>e.id===t);if(!r||!r.subtasks)throw Error(`Parent task ${t} or its subtasks not found for subtask ${e}`);let o=r.subtasks.findIndex(e=>e.id===n);if(o===-1)throw Error(`Subtask ${n} not found in parent task ${t}`);let c={...r.subtasks[o],parentTaskId:t};a.removedTasks.push(c),r.subtasks.splice(o,1),a.messages.push(`Successfully removed subtask ${e} from tag '${i}'`)}else{let t=parseInt(e,10),n=s.findIndex(e=>e.id===t);if(n===-1)throw Error(`Task with ID ${e} not found in tag '${i}'`);let r=s[n];a.removedTasks.push(r),c.push(t),s.splice(n,1),a.messages.push(`Successfully removed task ${e} from tag '${i}'`)}}catch(t){let n=`Error processing ID ${e}: ${t.message}`;a.errors.push(n),a.success=!1,z(`warn`,n)}}if(a.removedTasks.length>0){let t=new Set(o.map(e=>typeof e==`string`&&e.includes(`.`)?e:parseInt(e,10)));for(let e in n[i].tasks=s,n)Object.prototype.hasOwnProperty.call(n,e)&&n[e]&&n[e].tasks&&n[e].tasks.forEach(e=>{e.dependencies&&=e.dependencies.filter(e=>!t.has(e)),e.subtasks&&e.subtasks.forEach(n=>{n.dependencies&&=n.dependencies.filter(n=>!t.has(`${e.id}.${n}`)&&!t.has(n))})});_(e,n,r,i);for(let t of c){let n=H.join(H.dirname(e),`task_${t.toString().padStart(3,`0`)}.txt`);if(Ke.existsSync(n))try{Ke.unlinkSync(n),a.messages.push(`Deleted task file: ${n}`)}catch(e){let t=`Failed to delete task file ${n}: ${e.message}`;a.errors.push(t),a.success=!1,z(`warn`,t)}}}else a.errors.length===0&&a.messages.push(`No tasks found matching the provided IDs.`);let l=a.messages.join(`
|
|
956
|
+
${B.cyan(`1.`)} Run ${B.yellow(`task-master list`)} to view all tasks\n${B.cyan(`2.`)} Run ${B.yellow(`task-master expand --id=<id>`)} to break down a task into subtasks`,{padding:1,borderColor:`cyan`,borderStyle:`round`,margin:{top:1}})),i?.telemetryData&&Ml(i.telemetryData,`cli`)}async function ks(e,t){let n=new ts(e.mcpLog,e.reportProgress),{systemPrompt:r,userPrompt:a}=t,o=vs(r+a),s=null;e.outputFormat===`text`&&!e.isMCP&&(s=J(`Parsing PRD and generating tasks...
|
|
957
|
+
`).start());try{n.report(`Calling AI service to generate tasks from PRD${e.research?` with research-backed analysis`:``}...`,`info`);let t=await i({role:e.research?`research`:`main`,session:e.session,projectRoot:e.projectRoot,schema:$o,objectName:`tasks_data`,systemPrompt:r,prompt:a,commandName:`parse-prd`,outputType:e.isMCP?`mcp`:`cli`}),c=null;if(t?.mainResult&&(typeof t.mainResult==`object`&&t.mainResult!==null&&`tasks`in t.mainResult?c=t.mainResult:typeof t.mainResult.object==`object`&&t.mainResult.object!==null&&`tasks`in t.mainResult.object&&(c=t.mainResult.object)),!c||!Array.isArray(c.tasks))throw Error(`AI service returned unexpected data structure after validation.`);return s&&s.succeed(`Tasks generated successfully!`),{parsedTasks:c.tasks,aiServiceResponse:t,estimatedInputTokens:o}}catch(e){throw s&&s.fail(`Error parsing PRD: ${e.message}`),e}}const[As,js,Ms]=ca,Ns=new Map;var Ps=class{constructor(e,t,n,r=null){this.name=e,this.levels=t,this.colors=n,this.thresholds=r}getColor(e){return this.colors[e]||B.gray}getLevelFromScore(e){if(!this.thresholds)throw Error(`${this.name} does not support score-based levels`);return e>=7?this.levels[0]:e<=3?this.levels[2]:this.levels[1]}};const Fs={cli:{filled:`●`,empty:`○`},statusBar:{high:`⋮`,medium:`:`,low:`.`},mcp:{high:`🔴`,medium:`🟠`,low:`🟢`}},Is=new Ps(`priority`,[As,js,Ms],{[As]:B.hex(`#CC0000`),[js]:B.hex(`#FF8800`),[Ms]:B.yellow});function Ls(e,t){let n=Fs.cli.filled,r=Fs.cli.empty,i=``;for(let a=0;a<3;a++)a<e?i+=t(n):i+=B.white(r);return i}function Rs(e,t){return 3-t.indexOf(e)}function zs(e,t){if(Ns.has(e))return Ns.get(e);let n=t();return Ns.set(e,n),n}function Bs(){return zs(`mcp-priority-all`,()=>({[As]:Fs.mcp.high,[js]:Fs.mcp.medium,[Ms]:Fs.mcp.low}))}function Vs(){return zs(`cli-priority-all`,()=>{let e={};return Is.levels.forEach(t=>{e[t]=Ls(Rs(t,Is.levels),Is.getColor(t))}),e})}function Hs(){return zs(`statusbar-priority-all`,()=>{let e={};return Is.levels.forEach((t,n)=>{let r=n===0?Fs.statusBar.high:n===1?Fs.statusBar.medium:Fs.statusBar.low;e[t]=Is.getColor(t)(r)}),e})}function Us(){return{[As]:Is.colors[As],[js]:Is.colors[js],[Ms]:Is.colors[Ms]}}function Ws(e=!1){return e?Bs():Vs()}function Gs(e,t=!1){let n=Ws(t);return n[e]||n[js]}new Ps(`complexity`,[`high`,`medium`,`low`],{high:B.hex(`#CC0000`),medium:B.hex(`#FF8800`),low:B.green},{high:e=>e>=7,medium:e=>e>=4&&e<=6,low:e=>e<=3});const Ks={clearOnComplete:!1,stopOnComplete:!0,hideCursor:!0,barsize:40},qs={shades_classic:mt.Presets.shades_classic,shades_grey:mt.Presets.shades_grey,rect:mt.Presets.rect,legacy:mt.Presets.legacy},Js=new class{constructor(e={},t=qs.shades_classic){this.defaultOptions={...Ks,...e},this.defaultPreset=t}createSingleBar(e={},t=null){let n=this._mergeConfig(e),r=t||this.defaultPreset;return new mt.SingleBar(n,r)}createMultiBar(e={},t=null){let n=this._mergeConfig(e),r=t||this.defaultPreset;return new mt.MultiBar(n,r)}_mergeConfig(e){return{...this.defaultOptions,...e}}setDefaultOptions(e){this.defaultOptions={...this.defaultOptions,...e}}setDefaultPreset(e){this.defaultPreset=e}};function Ys(e={}){return Js.createMultiBar(e)}var Xs=class{constructor(e={}){this.numUnits=e.numUnits||1,this.unitName=e.unitName||`unit`,this.startTime=null,this.completedUnits=0,this.tokensIn=0,this.tokensOut=0,this.isEstimate=!0,this.bestAvgTimePerUnit=null,this.lastEstimateTime=null,this.lastEstimateSeconds=0,this.multibar=null,this.timeTokensBar=null,this.progressBar=null,this._timerInterval=null,this.isStarted=!1,this.isFinished=!1,this._initializeCustomProperties(e)}_initializeCustomProperties(e){}get unitNamePlural(){return`${this.unitName}s`}start(){this.isStarted||this.isFinished||(this.isStarted=!0,this.startTime=Date.now(),this.multibar=Ys(),this.timeTokensBar=this.multibar.create(1,0,{},{format:this._getTimeTokensBarFormat(),barsize:1,hideCursor:!0,clearOnComplete:!1}),this.progressBar=this.multibar.create(this.numUnits,0,{},{format:this._getProgressBarFormat(),barCompleteChar:`█`,barIncompleteChar:`░`}),this._updateTimeTokensBar(),this.progressBar.update(0,{[this.unitNamePlural]:`0/${this.numUnits}`}),this._timerInterval=setInterval(()=>this._updateTimeTokensBar(),1e3),this._setupCustomUI())}_setupCustomUI(){}_getTimeTokensBarFormat(){return`{clock} {elapsed} | Tokens (I/O): {in}/{out} | Est: {remaining}`}_getProgressBarFormat(){return`${this.unitName.charAt(0).toUpperCase()+this.unitName.slice(1)}s {${this.unitNamePlural}} |{bar}| {percentage}%`}updateTokens(e,t,n=!1){this.tokensIn=e||0,this.tokensOut=t||0,this.isEstimate=n,this._updateTimeTokensBar()}_updateTimeTokensBar(){if(!this.timeTokensBar||this.isFinished)return;let e=this._formatElapsedTime(),t=this._estimateRemainingTime(),n=this.isEstimate?`~ Tokens (I/O)`:`Tokens (I/O)`;this.timeTokensBar.update(1,{clock:`⏱️`,elapsed:e,in:this.tokensIn,out:this.tokensOut,remaining:t,tokensLabel:n,...this._getCustomTimeTokensPayload()})}_getCustomTimeTokensPayload(){return{}}_formatElapsedTime(){if(!this.startTime)return`0m 00s`;let e=Math.floor((Date.now()-this.startTime)/1e3);return`${Math.floor(e/60)}m ${(e%60).toString().padStart(2,`0`)}s`}_estimateRemainingTime(){let e=this._getProgressFraction();if(e>=1)return`~0s`;let t=Date.now(),n=(t-this.startTime)/1e3;if(e===0)return`~calculating...`;let r=n/e;(this.bestAvgTimePerUnit===null||r<this.bestAvgTimePerUnit)&&(this.bestAvgTimePerUnit=r);let i=this.numUnits*(1-e),a=Math.ceil(i*this.bestAvgTimePerUnit);if(this.lastEstimateTime){let e=Math.floor((t-this.lastEstimateTime)/1e3),n=Math.max(0,this.lastEstimateSeconds-e);if(n===0)return`~0s`;a=Math.min(a,n)}return this.lastEstimateTime=t,this.lastEstimateSeconds=a,`~${this._formatDuration(a)}`}_getProgressFraction(){return this.completedUnits/this.numUnits}_formatDuration(e){if(e<60)return`${e}s`;let t=Math.floor(e/60),n=e%60;return t<60?n>0?`${t}m ${n}s`:`${t}m`:`${Math.floor(t/60)}h ${t%60}m`}getElapsedTime(){return this.startTime?Date.now()-this.startTime:0}stop(){this.isFinished||(this.isFinished=!0,this._timerInterval&&=(clearInterval(this._timerInterval),null),this.multibar&&(this._updateTimeTokensBar(),this.multibar.stop()),this.cleanup())}getSummary(){return{completedUnits:this.completedUnits,elapsedTime:this.getElapsedTime()}}cleanup(){if(this._timerInterval&&=(clearInterval(this._timerInterval),null),this.multibar){try{this.multibar.stop()}catch{}this.multibar=null}this.timeTokensBar=null,this.progressBar=null,this.isStarted=!1,this.isFinished=!0,this._performCustomCleanup()}_performCustomCleanup(){}},Zs=class{constructor(e){if(!e)throw Error(`Multibar instance is required`);this.multibar=e}createBar(e,t={}){if(typeof e!=`string`)throw Error(`Format must be a string`);let n=this.multibar.create(1,1,{},{format:e,barsize:1,hideCursor:!0,clearOnComplete:!1});return n.update(1,t),n}createHeader(e,t){this.createBar(t),this.createBar(e),this.createBar(t)}createRow(e,t){if(!t||typeof t!=`object`)throw Error(`Payload must be an object`);return this.createBar(e,t)}createBorder(e){return this.createBar(e)}};function Qs(e,t,n){new Zs(e).createHeader(t,n)}function $s(e,t,n){new Zs(e).createRow(t,n)}function ec(e,t){new Zs(e).createBorder(t)}Vs();const tc=Hs();Us();const nc={DEBOUNCE_DELAY:100,MAX_TITLE_LENGTH:57,TRUNCATED_LENGTH:54,TASK_ID_PAD_START:3,TASK_ID_PAD_END:4,PRIORITY_PAD_END:3,VALID_PRIORITIES:[`high`,`medium`,`low`],DEFAULT_PRIORITY:`medium`};var rc=class{constructor(e=nc.DEBOUNCE_DELAY){this.delay=e,this.pendingTimeout=null}debounce(e){this.clear(),this.pendingTimeout=setTimeout(()=>{e(),this.pendingTimeout=null},this.delay)}clear(){this.pendingTimeout&&=(clearTimeout(this.pendingTimeout),null)}hasPending(){return this.pendingTimeout!==null}},ic=class{constructor(){this.priorities={high:0,medium:0,low:0}}increment(e){let t=this.normalize(e);return this.priorities[t]++,t}normalize(e){let t=e?e.toLowerCase():nc.DEFAULT_PRIORITY;return nc.VALID_PRIORITIES.includes(t)?t:nc.DEFAULT_PRIORITY}getCounts(){return{...this.priorities}}},ac=class{static formatTitle(e,t){return e?e.length>nc.MAX_TITLE_LENGTH?e.substring(0,nc.TRUNCATED_LENGTH)+`...`:e:`Task ${t}`}static formatPriority(e){return Gs(e,!1).padEnd(nc.PRIORITY_PAD_END,` `)}static formatTaskId(e){return e.toString().padStart(nc.TASK_ID_PAD_START,` `).padEnd(nc.TASK_ID_PAD_END,` `)}},oc=class extends Xs{_initializeCustomProperties(e){this.append=e.append,this.priorityManager=new ic,this.debouncer=new rc,this.headerShown=!1}_getTimeTokensBarFormat(){return`{clock} {elapsed} | ${tc.high} {high} ${tc.medium} {medium} ${tc.low} {low} | Tokens (I/O): {in}/{out} | Est: {remaining}`}_getProgressBarFormat(){return`Tasks {tasks} |{bar}| {percentage}%`}_getCustomTimeTokensPayload(){return this.priorityManager.getCounts()}addTaskLine(e,t,n=`medium`){if(!this.multibar||this.isFinished)return;this._ensureHeaderShown();let r=this._updateTaskCounters(e,n);this._updateTimeTokensBar(),this.debouncer.debounce(()=>{this._updateProgressDisplay(e,t,r)})}_ensureHeaderShown(){this.headerShown||(this.headerShown=!0,Qs(this.multibar,` TASK | PRI | TITLE`,`------+-----+----------------------------------------------------------------`))}_updateTaskCounters(e,t){let n=this.priorityManager.increment(t);return this.completedUnits=e,n}_updateProgressDisplay(e,t,n){this.progressBar.update(this.completedUnits,{tasks:`${this.completedUnits}/${this.numUnits}`});let r=ac.formatTitle(t,e),i=ac.formatPriority(n),a=ac.formatTaskId(e);$s(this.multibar,` ${a} | ${i} | {title}`,{title:r}),ec(this.multibar,`------+-----+----------------------------------------------------------------`),this._updateTimeTokensBar()}finish(){this.debouncer.hasPending()&&(this.debouncer.clear(),this._updateTimeTokensBar()),this.cleanup(),super.finish()}_performCustomCleanup(){this.debouncer.clear()}getSummary(){return{...super.getSummary(),taskPriorities:this.priorityManager.getCounts(),actionVerb:this.append?`appended`:`generated`}}};function sc(e={}){return new oc(e)}async function cc(e,t,n){let r=lc(e,t,n);await dc(e,n,r.estimatedInputTokens);let i=await fc(e,t,e.streamingTimeout),{progressTracker:a,priorityMap:o}=await pc(e,n),s=await mc(i.mainResult,e,t,n,a,o,r.defaultPriority,r.estimatedInputTokens,r.logger);if(uc(s),s.usage&&e.projectRoot){let{logAiUsage:t}=await import(`./ai-services-unified-D8U4gub7.js`),{getUserId:n}=await import(`./config-manager-BXmWyJ0Q.js`),a=n(e.projectRoot);if(a&&i.providerName&&i.modelId)try{let n=await t({userId:a,commandName:`parse-prd`,providerName:i.providerName,modelId:i.modelId,inputTokens:s.usage.promptTokens||0,outputTokens:s.usage.completionTokens||0,outputType:e.isMCP?`mcp`:`cli`});n&&(i.telemetryData=n)}catch(e){r.logger.report(`Failed to log telemetry: ${e.message}`,`debug`)}}return wc(s,i,r.estimatedInputTokens,a)}function lc(e,t,n){let{systemPrompt:r,userPrompt:i}=t;return{logger:new ts(e.mcpLog,e.reportProgress),estimatedInputTokens:vs(r+i),defaultPriority:ce(e.projectRoot)||`medium`}}function uc(e){if(e.parsedTasks.length===0)throw Error(`No tasks were generated from the PRD`)}async function dc(e,t,n){e.reportProgress&&await e.reportProgress({progress:0,total:t,message:`Starting PRD analysis (Input: ${n} tokens)${e.research?` with research`:``}...`})}async function fc(e,n,r){let{systemPrompt:i,userPrompt:a}=n;return await Xo.withTimeout(t({role:e.research?`research`:`main`,session:e.session,projectRoot:e.projectRoot,schema:$o,systemPrompt:i,prompt:a,commandName:`parse-prd`,outputType:e.isMCP?`mcp`:`cli`}),r,`Streaming operation`)}async function pc(e,t){let n=Ws(e.isMCP),r=null;if(e.outputFormat===`text`&&!e.isMCP){r=sc({numUnits:t,unitName:`task`,append:e.append});let n=e.research?he():l(),i=v(e.research?`research`:`main`);us({prdFilePath:e.prdPath,outputPath:e.tasksPath,numTasks:t,append:e.append,research:e.research,force:e.force,existingTasks:[],nextId:1,model:n||`Default`,temperature:i?.temperature||.7}),r.start()}return{progressTracker:r,priorityMap:n}}async function mc(e,t,n,r,i,a,o,s,c){let{systemPrompt:l,userPrompt:u}=n,d={config:{...t,schema:$o},numTasks:r,progressTracker:i,priorityMap:a,defaultPriority:o,estimatedInputTokens:s,prompt:u,systemPrompt:l};try{let t={lastPartialObject:null,taskCount:0,estimatedOutputTokens:0,usage:null};if(await hc(e.partialObjectStream,t,d),e.usage)try{t.usage=await e.usage}catch(e){c.report(`Failed to get usage data: ${e.message}`,`debug`)}return yc(t,d)}catch(e){return c.report(`StreamObject processing failed: ${e.message}. Falling back to generateObject.`,`debug`),await Cc(d,c)}}async function hc(e,t,n){for await(let r of e)t.lastPartialObject=r,r&&(t.estimatedOutputTokens=vs(JSON.stringify(r))),await gc(r,t,n)}async function gc(e,t,n){if(!e?.tasks||!Array.isArray(e.tasks))return;let r=e.tasks.length;r>t.taskCount?(await _c(e.tasks,t.taskCount,r,t.estimatedOutputTokens,n),t.taskCount=r):n.progressTracker&&t.estimatedOutputTokens>0&&n.progressTracker.updateTokens(n.estimatedInputTokens,t.estimatedOutputTokens,!0)}async function _c(e,t,n,r,i){for(let a=t;a<n;a++){let t=e[a]||{};t.title?await Es({task:t,currentCount:a+1,totalTasks:i.numTasks,estimatedTokens:r,progressTracker:i.progressTracker,reportProgress:i.config.reportProgress,priorityMap:i.priorityMap,defaultPriority:i.defaultPriority,estimatedInputTokens:i.estimatedInputTokens}):await vc(a+1,r,i)}}async function vc(e,t,n){let{progressTracker:r,config:i,numTasks:a,defaultPriority:o,estimatedInputTokens:s}=n;r&&(r.addTaskLine(e,`Generating task ${e}...`,o),r.updateTokens(s,t,!0)),i.reportProgress&&!r&&await i.reportProgress({progress:e,total:a,message:`Generating task ${e}/${a}...`})}async function yc(e,t){let{lastPartialObject:n,estimatedOutputTokens:r,taskCount:i,usage:a}=e;if(!n?.tasks||!Array.isArray(n.tasks))throw Error(`No tasks generated from streamObject`);let o=a?.completionTokens||r,s=a?.promptTokens||t.estimatedInputTokens;return t.progressTracker&&await bc(n.tasks,i,a?o:r,t,a?s:null),{parsedTasks:n.tasks,estimatedOutputTokens:o,actualInputTokens:s,usage:a,usedFallback:!1}}async function bc(e,t,n,r,i=null){let{progressTracker:a,defaultPriority:o,estimatedInputTokens:s}=r;t>0?xc(e,a,o):await Sc(e,n,r),a.updateTokens(i||s,n,!1),a.stop()}function xc(e,t,n){for(let r=0;r<e.length;r++){let i=e[r];i?.title&&t.addTaskLine(r+1,i.title,i.priority||n)}}async function Sc(e,t,n){for(let r=0;r<e.length;r++){let i=e[r];i?.title&&await Es({task:i,currentCount:r+1,totalTasks:n.numTasks,estimatedTokens:t,progressTracker:n.progressTracker,reportProgress:n.config.reportProgress,priorityMap:n.priorityMap,defaultPriority:n.defaultPriority,estimatedInputTokens:n.estimatedInputTokens})}}async function Cc(e,t){if(t.report(`Using generateObject fallback for PRD parsing`,`info`),e.progressTracker)for(let t=0;t<e.numTasks;t++)e.progressTracker.addTaskLine(t+1,`Generating task ${t+1}...`,e.defaultPriority),e.progressTracker.updateTokens(e.estimatedInputTokens,0,!0);let n=await i({role:e.config.research?`research`:`main`,commandName:`parse-prd`,prompt:e.prompt,systemPrompt:e.systemPrompt,schema:e.config.schema,outputFormat:e.config.outputFormat||`text`,projectRoot:e.config.projectRoot,session:e.config.session}),r=n?.mainResult||n;if(r&&Array.isArray(r.tasks)&&(r.tasks=r.tasks.map(e=>({...e,dependencies:e.dependencies??[],priority:e.priority??null,details:e.details??null,testStrategy:e.testStrategy??null}))),r&&Array.isArray(r.tasks)){if(e.progressTracker){for(let t=0;t<r.tasks.length;t++){let n=r.tasks[t];n&&n.title&&e.progressTracker.addTaskLine(t+1,n.title,n.priority||e.defaultPriority)}let t=n.telemetryData?.outputTokens||vs(JSON.stringify(r)),i=n.telemetryData?.inputTokens||e.estimatedInputTokens;e.progressTracker.updateTokens(i,t,!1)}return{parsedTasks:r.tasks,estimatedOutputTokens:n.telemetryData?.outputTokens||vs(JSON.stringify(r)),actualInputTokens:n.telemetryData?.inputTokens,telemetryData:n.telemetryData,usedFallback:!0}}throw Error(`Failed to generate tasks using generateObject fallback`)}function wc(e,t,n,r){let i=null;if(r&&(i=r.getSummary(),r.cleanup()),e.usage&&t){let n=e.usage;t.usage||={promptTokens:n.promptTokens||0,completionTokens:n.completionTokens||0,totalTokens:n.totalTokens||0}}return{parsedTasks:e.parsedTasks,aiServiceResponse:t,estimatedInputTokens:e.actualInputTokens||n,estimatedOutputTokens:e.estimatedOutputTokens,usedFallback:e.usedFallback,progressTracker:r,summary:i}}async function Tc(e,t,n){let r=new ts(e.mcpLog,e.reportProgress);r.report(`Parsing PRD file: ${e.prdPath}, Force: ${e.force}, Append: ${e.append}, Research: ${e.research}`,`debug`);try{let{existingTasks:i,nextId:a}=bs(e.tasksPath,e.targetTag);xs({existingTasks:i,targetTag:e.targetTag,append:e.append,force:e.force,isMCP:e.isMCP,logger:r});let o=await t(e,await Ts(e,ys(e.prdPath),a),e.numTasks),s=ce(e.projectRoot)||`medium`,c=Ss(o.parsedTasks,a,i,s),l=e.append?[...i,...c]:c;return ws(e.tasksPath,l,e.targetTag,r),await Ec(e,o,c,l,a,n),{success:!0,tasksPath:e.tasksPath,telemetryData:o.aiServiceResponse?.telemetryData,tagInfo:o.aiServiceResponse?.tagInfo}}catch(t){throw r.report(`Error parsing PRD: ${t.message}`,`error`),e.isMCP||(console.error(B.red(`Error: ${t.message}`)),be(e.projectRoot)&&console.error(t)),t}}async function Ec(e,t,n,r,i,a){let{aiServiceResponse:o,estimatedInputTokens:s,estimatedOutputTokens:c}=t;if(e.reportProgress){let t=o?.telemetryData&&(o.telemetryData.inputTokens>0||o.telemetryData.outputTokens>0),n;if(t){let e=o.telemetryData.totalCost||0,t=o.telemetryData.currency||`USD`;n=`✅ Task Generation Completed | Tokens (I/O): ${o.telemetryData.inputTokens}/${o.telemetryData.outputTokens} | Cost: ${t===`USD`?`$`:t}${e.toFixed(4)}`}else n=`✅ Task Generation Completed | ~Tokens (I/O): ${s}/${a?c:`unknown`} | Cost: ~$0.00`;await e.reportProgress({progress:e.numTasks,total:e.numTasks,message:n})}e.outputFormat===`text`&&!e.isMCP&&(a&&t.summary?await Ds({processedTasks:n,nextId:i,summary:t.summary,prdPath:e.prdPath,tasksPath:e.tasksPath,usedFallback:t.usedFallback,aiServiceResponse:o}):a||Os({processedTasks:n,research:e.research,finalTasks:r,tasksPath:e.tasksPath,aiServiceResponse:o}))}async function Dc(e,t,n,r={}){return Tc(new es(e,t,n,r),cc,!0)}async function Oc(e,t,n,r={}){return Tc(new es(e,t,n,r),ks,!1)}async function kc(e,t,n,r={}){let i=new es(e,t,n,r);if(i.useStreaming)try{return await Dc(e,t,n,r)}catch(a){if(a instanceof Jo||a.code===Yo.NOT_ASYNC_ITERABLE||a.code===Yo.STREAM_PROCESSING_FAILED||a.code===Yo.STREAM_NOT_ITERABLE||Xo.isTimeoutError(a)){let o=new ts(i.mcpLog,i.reportProgress);return i.outputFormat===`text`&&!i.isMCP?console.log(B.yellow(`⚠️ Streaming operation ${a.message.includes(`timed out`)?`timed out`:`failed`}. Falling back to non-streaming mode...`)):o.report(`Streaming failed (${a.message}), falling back to non-streaming mode...`,`warn`),await Oc(e,t,n,r)}else throw a}else return await Oc(e,t,n,r)}var Ac=kc;async function jc(e,t,n=!1,r=!1,i={}){let{projectRoot:a,tag:o}=i;try{z(`info`,`Removing subtask ${t}...`);let r=w(e,a,o);if(!r||!r.tasks)throw Error(`Invalid or missing tasks file at ${e}`);if(!t.includes(`.`))throw Error(`Invalid subtask ID format: ${t}. Expected format: "parentId.subtaskId"`);let[i,s]=t.split(`.`),c=parseInt(i,10),l=parseInt(s,10),u=r.tasks.find(e=>e.id===c);if(!u)throw Error(`Parent task with ID ${c} not found`);if(!u.subtasks||u.subtasks.length===0)throw Error(`Parent task ${c} has no subtasks`);let d=u.subtasks.findIndex(e=>e.id===l);if(d===-1)throw Error(`Subtask ${t} not found`);let f={...u.subtasks[d]};u.subtasks.splice(d,1),u.subtasks.length===0&&(u.subtasks=void 0);let p=null;if(n){z(`info`,`Converting subtask ${t} to a standalone task...`);let e=Math.max(...r.tasks.map(e=>e.id))+1;p={id:e,title:f.title,description:f.description||``,details:f.details||``,status:f.status||`pending`,dependencies:f.dependencies||[],priority:u.priority||`medium`},p.dependencies.includes(c)||p.dependencies.push(c),r.tasks.push(p),z(`info`,`Created new task ${e} from subtask ${t}`)}else z(`info`,`Subtask ${t} deleted`);return _(e,r,a,o),p}catch(e){throw z(`error`,`Error removing subtask: ${e.message}`),e}}var Mc=jc;function Nc(e,t){if(typeof t==`string`&&t.includes(`.`)){let n=t.split(`.`);if(n.length!==2||!n[0]||!n[1]){let n=parseInt(t,10);return e.some(e=>e.id===n)}let[r,i]=n,a=parseInt(r,10),o=parseInt(i,10),s=e.find(e=>e.id===a);return s&&s.subtasks&&s.subtasks.some(e=>e.id===o)}let n=parseInt(t,10);return e.some(e=>e.id===n)}var Pc=Nc;async function Fc(e,t,n={}){let{projectRoot:r,tag:i}=n,a={success:!0,messages:[],errors:[],removedTasks:[]},o=t.split(`,`).map(e=>e.trim()).filter(Boolean);if(o.length===0)return a.success=!1,a.errors.push(`No valid task IDs provided.`),a;try{let t=w(e,r,i);if(!t)throw Error(`Could not read tasks file at ${e}`);let n=t._rawTaggedData||t;if(!n[i]||!n[i].tasks)throw Error(`Tag '${i}' not found or has no tasks.`);let s=n[i].tasks,c=[];for(let e of o){if(!Pc(s,e)){let t=`Task with ID ${e} in tag '${i}' not found or already removed.`;a.errors.push(t),a.success=!1;continue}try{if(typeof e==`string`&&e.includes(`.`)){let[t,n]=e.split(`.`).map(e=>parseInt(e,10)),r=s.find(e=>e.id===t);if(!r||!r.subtasks)throw Error(`Parent task ${t} or its subtasks not found for subtask ${e}`);let o=r.subtasks.findIndex(e=>e.id===n);if(o===-1)throw Error(`Subtask ${n} not found in parent task ${t}`);let c={...r.subtasks[o],parentTaskId:t};a.removedTasks.push(c),r.subtasks.splice(o,1),a.messages.push(`Successfully removed subtask ${e} from tag '${i}'`)}else{let t=parseInt(e,10),n=s.findIndex(e=>e.id===t);if(n===-1)throw Error(`Task with ID ${e} not found in tag '${i}'`);let r=s[n];a.removedTasks.push(r),c.push(t),s.splice(n,1),a.messages.push(`Successfully removed task ${e} from tag '${i}'`)}}catch(t){let n=`Error processing ID ${e}: ${t.message}`;a.errors.push(n),a.success=!1,z(`warn`,n)}}if(a.removedTasks.length>0){let t=new Set(o.map(e=>typeof e==`string`&&e.includes(`.`)?e:parseInt(e,10)));for(let e in n[i].tasks=s,n)Object.prototype.hasOwnProperty.call(n,e)&&n[e]&&n[e].tasks&&n[e].tasks.forEach(e=>{e.dependencies&&=e.dependencies.filter(e=>!t.has(e)),e.subtasks&&e.subtasks.forEach(n=>{n.dependencies&&=n.dependencies.filter(n=>!t.has(`${e.id}.${n}`)&&!t.has(n))})});_(e,n,r,i);for(let t of c){let n=H.join(H.dirname(e),`task_${t.toString().padStart(3,`0`)}.txt`);if(Ke.existsSync(n))try{Ke.unlinkSync(n),a.messages.push(`Deleted task file: ${n}`)}catch(e){let t=`Failed to delete task file ${n}: ${e.message}`;a.errors.push(t),a.success=!1,z(`warn`,t)}}}else a.errors.length===0&&a.messages.push(`No tasks found matching the provided IDs.`);let l=a.messages.join(`
|
|
954
958
|
`),u=a.errors.join(`
|
|
955
|
-
`);return{success:a.success,message:l||`No tasks were removed.`,error:u||null,removedTasks:a.removedTasks}}catch(e){return z(`error`,`Error removing tasks: ${e.message}`),{success:!1,message:``,error:`Operation failed: ${e.message}`,removedTasks:[]}}}var
|
|
959
|
+
`);return{success:a.success,message:l||`No tasks were removed.`,error:u||null,removedTasks:a.removedTasks}}catch(e){return z(`error`,`Error removing tasks: ${e.message}`),{success:!1,message:``,error:`Operation failed: ${e.message}`,removedTasks:[]}}}var Ic=Fc;ot.use(st({code:e=>e.split(`
|
|
956
960
|
`).map(e=>` `+B.cyan(e)).join(`
|
|
957
|
-
`),blockquote:B.gray.italic,html:B.gray,heading:B.white.bold,hr:B.gray,listitem:B.white,paragraph:B.white,strong:B.white.bold,em:B.white.italic,codespan:B.cyan,del:B.dim.strikethrough,link:B.blue,href:B.blue.underline,showSectionPrefix:!1,unescape:!0,emoji:!1,tab:4,width:100})),ot.setOptions({breaks:!0,gfm:!0});async function
|
|
961
|
+
`),blockquote:B.gray.italic,html:B.gray,heading:B.white.bold,hr:B.gray,listitem:B.white,paragraph:B.white,strong:B.white.bold,em:B.white.italic,codespan:B.cyan,del:B.dim.strikethrough,link:B.blue,href:B.blue.underline,showSectionPrefix:!1,unescape:!0,emoji:!1,tab:4,width:100})),ot.setOptions({breaks:!0,gfm:!0});async function Lc(t,n={},i={},a=`text`,o=!0){let{taskIds:s=[],filePaths:c=[],customContext:l=``,includeProjectTree:u=!1,detailLevel:d=`medium`,projectRoot:f,tag:p,saveToFile:m=!1}=n,{session:h,mcpLog:g,commandName:_=`research`,outputType:v=`cli`}=i,y=!!g,b=f||Fe();if(!b)throw Error(`Could not determine project root directory`);let x=y?g:{info:(...e)=>z(`info`,...e),warn:(...e)=>z(`warn`,...e),error:(...e)=>z(`error`,...e),debug:(...e)=>z(`debug`,...e),success:(...e)=>z(`success`,...e)};a===`text`&&console.log(W(B.cyan.bold(`🔍 AI Research Query`),{padding:1,borderColor:`cyan`,borderStyle:`round`,margin:{top:1,bottom:1}}));try{let f=new za(b,p),g=[...s],S=[];try{let e=await w(H.join(b,`.taskmaster`,`tasks`,`tasks.json`),b,p);if(e&&e.tasks&&e.tasks.length>0){let n=new qa(ke(e.tasks),`research`),r=n.findRelevantTasks(t,{maxResults:8,includeRecent:!0,includeCategoryMatches:!0});S=n.getTaskIds(r);let i=S.filter(e=>!g.includes(e));if(g=[...g,...i],a===`text`&&g.length>0){let e=g.map(e=>parseInt(e)).sort((e,t)=>e-t).map(e=>e.toString());if(s.length>0){let e=s.map(e=>parseInt(e)).sort((e,t)=>e-t).map(e=>e.toString());if(console.log(B.gray(`Provided tasks: `)+B.cyan(e.join(`, `))),i.length>0){let e=i.map(e=>parseInt(e)).sort((e,t)=>e-t).map(e=>e.toString());console.log(B.gray(`+ Auto-discovered related tasks: `)+B.cyan(e.join(`, `)))}}else console.log(B.gray(`Auto-discovered relevant tasks: `)+B.cyan(e.join(`, `)))}}}catch(e){x.debug(`Could not auto-discover tasks: ${e.message}`)}let C=await f.gather({tasks:g,files:c,customContext:l,includeProjectTree:u,format:`research`,includeTokenCounts:!0}),T=C.context,E=C.tokenBreakdown,D=La(),O={query:t,gatheredContext:T||``,detailLevel:d,projectInfo:{root:b,taskCount:g.length,fileCount:c.length}},{systemPrompt:k,userPrompt:A}=await D.loadPrompt(`research`,O),j=f.countTokens(k),M=f.countTokens(A),N=j+M;a===`text`&&Rc(E,j,M),a!==`text`&&x.info(`Calling AI service with research role, context size: ${E.total} tokens (${T.length} characters)`);let P,ee=``;try{if(a===`text`){console.log(B.cyan(`
|
|
958
962
|
🔍 Researching with AI...
|
|
959
963
|
`)),P=await e({role:`research`,session:h,projectRoot:b,systemPrompt:k,prompt:A,commandName:_,outputType:v,experimental_transform:tt({delayInMs:15,chunking:`word`})});for await(let e of P.mainResult.textStream){ee+=e;let t=``;for(let n=0;n<e.length;n++){if(e.slice(n).startsWith(`<think>`)){n+=6;continue}if(e.slice(n).startsWith(`</think>`)){n+=7;continue}t+=e[n]}t&&process.stdout.write(B.gray.dim(t))}if(console.log(`
|
|
960
964
|
`),P.mainResult.usage){let e=await P.mainResult.usage,t=e.promptTokens||e.inputTokens||0,n=e.completionTokens||e.outputTokens||0,r=e.totalTokens||t+n;P.telemetryData={...P.telemetryData,inputTokens:t,outputTokens:n,totalTokens:r}}let n=process.stdout.columns||80,r=Math.min(n-4,120),i=W(B.green.bold(`Research Results`)+`
|
|
961
965
|
|
|
962
966
|
`+B.gray(`Query: `)+B.white(t)+`
|
|
963
|
-
`+B.gray(`Detail Level: `)+B.cyan(d),{padding:{top:1,bottom:1,left:2,right:2},margin:{top:0,bottom:0},borderStyle:`round`,borderColor:`green`,width:r});console.log(i);let a=ee.replace(/<think>[\s\S]*?<\/think>/g,``).trim(),o=W((await ot.parse(a)).trim(),{padding:{top:1,bottom:1,left:2,right:2},margin:{top:0,bottom:1},borderStyle:`single`,borderColor:`white`,width:r});console.log(o)}else P=await r({role:`research`,session:h,projectRoot:b,systemPrompt:k,prompt:A,commandName:_,outputType:v}),ee=P.mainResult}catch(e){throw e}let te=P.telemetryData,ne=P.tagInfo,re={interactiveSaveOccurred:!1};if(a===`text`&&(te&&
|
|
967
|
+
`+B.gray(`Detail Level: `)+B.cyan(d),{padding:{top:1,bottom:1,left:2,right:2},margin:{top:0,bottom:0},borderStyle:`round`,borderColor:`green`,width:r});console.log(i);let a=ee.replace(/<think>[\s\S]*?<\/think>/g,``).trim(),o=W((await ot.parse(a)).trim(),{padding:{top:1,bottom:1,left:2,right:2},margin:{top:0,bottom:1},borderStyle:`single`,borderColor:`white`,width:r});console.log(o)}else P=await r({role:`research`,session:h,projectRoot:b,systemPrompt:k,prompt:A,commandName:_,outputType:v}),ee=P.mainResult}catch(e){throw e}let te=P.telemetryData,ne=P.tagInfo,re={interactiveSaveOccurred:!1};if(a===`text`&&(te&&Ml(te,`cli`),o&&!y&&(re=await zc(n,i,a,b,x,t,ee))),m&&y){let e=await Vc([{question:t,answer:ee,type:`initial`,timestamp:new Date().toISOString()}],b,i,x);return{query:t,result:ee,contextSize:T.length,contextTokens:E.total,tokenBreakdown:E,systemPromptTokens:j,userPromptTokens:M,totalInputTokens:N,detailLevel:d,telemetryData:te,tagInfo:ne,savedFilePath:e,interactiveSaveOccurred:!1}}return x.success(`Research query completed successfully`),{query:t,result:ee,contextSize:T.length,contextTokens:E.total,tokenBreakdown:E,systemPromptTokens:j,userPromptTokens:M,totalInputTokens:N,detailLevel:d,telemetryData:te,tagInfo:ne,interactiveSaveOccurred:re?.interactiveSaveOccurred||!1}}catch(e){throw x.error(`Research query failed: ${e.message}`),a===`text`&&console.error(B.red(`\n❌ Research failed: ${e.message}`)),e}}function Rc(e,t,n){let r=[];if(e.customContext&&r.push(B.cyan(`Custom: `)+B.yellow(e.customContext.tokens.toLocaleString())),e.tasks&&e.tasks.length>0){let t=e.tasks.reduce((e,t)=>e+t.tokens,0),n=e.tasks.map(e=>{let t=e.title.length>30?e.title.substring(0,30)+`...`:e.title;return` ${B.gray(e.id)} ${B.white(t)} ${B.yellow(e.tokens.toLocaleString())} tokens`}).join(`
|
|
964
968
|
`);r.push(B.cyan(`Tasks: `)+B.yellow(t.toLocaleString())+B.gray(` (${e.tasks.length} items)`)+`
|
|
965
969
|
`+n)}if(e.files&&e.files.length>0){let t=e.files.reduce((e,t)=>e+t.tokens,0),n=e.files.map(e=>{let t=e.path.length>40?`...`+e.path.substring(e.path.length-37):e.path;return` ${B.gray(t)} ${B.yellow(e.tokens.toLocaleString())} tokens ${B.gray(`(${e.sizeKB}KB)`)}`}).join(`
|
|
966
970
|
`);r.push(B.cyan(`Files: `)+B.yellow(t.toLocaleString())+B.gray(` (${e.files.length} files)`)+`
|
|
@@ -968,9 +972,9 @@ ${B.cyan(`1.`)} Run ${B.yellow(`task-master list`)} to view all tasks\n${B.cyan(
|
|
|
968
972
|
`);if(r.push(B.cyan(`Prompts: `)+B.yellow(i.toLocaleString())+B.gray(` (generated)`)+`
|
|
969
973
|
`+a),r.length>0){let e=W(r.join(`
|
|
970
974
|
|
|
971
|
-
`),{title:B.blue.bold(`Context Analysis`),titleAlignment:`left`,padding:{top:1,bottom:1,left:2,right:2},margin:{top:0,bottom:1},borderStyle:`single`,borderColor:`blue`});console.log(e)}}async function
|
|
975
|
+
`),{title:B.blue.bold(`Context Analysis`),titleAlignment:`left`,padding:{top:1,bottom:1,left:2,right:2},margin:{top:0,bottom:1},borderStyle:`single`,borderColor:`blue`});console.log(e)}}async function zc(e,t,n,r,i,a,o){let s=!1;try{let{readJSON:c}=await import(`./utils-B86D4uiR.js`);(await import(`./update-task-by-id-TVSsRUFk.js`)).default;let{updateSubtaskById:l}=await import(`./update-subtask-by-id-BZB0AG2e.js`),u=[{question:a,answer:o,type:`initial`,timestamp:new Date().toISOString()}];for(;;){let{action:a}=await q.prompt([{type:`list`,name:`action`,message:`What would you like to do next?`,choices:[{name:`Ask a follow-up question`,value:`followup`},{name:`Save to file`,value:`savefile`},{name:`Save to task/subtask`,value:`save`},{name:`Quit`,value:`quit`}],pageSize:4}]);if(a===`quit`)break;if(a===`savefile`){await Vc(u,r,t,i);continue}if(a===`save`){await Bc(u,r,t,i)&&(s=!0);continue}if(a===`followup`){let{followUpQuery:r}=await q.prompt([{type:`input`,name:`followUpQuery`,message:`Enter your follow-up question:`,validate:e=>!e||e.trim().length===0?`Please enter a valid question.`:!0}]);if(!r||r.trim().length===0)continue;console.log(`
|
|
972
976
|
`+B.gray(`─`.repeat(60))+`
|
|
973
|
-
`);let i=
|
|
977
|
+
`);let i=Wc(u),a={...e,taskIds:[],customContext:i+(e.customContext?`\n\n--- Original Context ---\n${e.customContext}`:``)},o=await Lc(r.trim(),a,t,n,!1);u.push({question:r.trim(),answer:o.result,type:`followup`,timestamp:new Date().toISOString()})}}}catch(e){i.debug(`Follow-up questions not available: ${e.message}`)}return{interactiveSaveOccurred:s}}async function Bc(e,t,n,r){try{let{readJSON:r}=await import(`./utils-B86D4uiR.js`),i=(await import(`./update-task-by-id-TVSsRUFk.js`)).default,{updateSubtaskById:a}=await import(`./update-subtask-by-id-BZB0AG2e.js`),{taskId:o}=await q.prompt([{type:`input`,name:`taskId`,message:`Enter task ID (e.g., "15" for task or "15.2" for subtask):`,validate:e=>{if(!e||e.trim().length===0)return`Please enter a task ID.`;let t=e.trim();return/^\d+(\.\d+)?$/.test(t)?!0:`Invalid format. Use "15" for task or "15.2" for subtask.`}}]),s=o.trim(),c=Uc(e),l=s.includes(`.`),u=H.join(t,`.taskmaster`,`tasks`,`tasks.json`);if(!V.existsSync(u)){console.log(B.red(`❌ Tasks file not found. Please run task-master init first.`));return}let d=r(u,t,n.tag);if(!d||!d.tasks){console.log(B.red(`❌ No valid tasks found.`));return}if(l){let[e,t]=s.split(`.`).map(e=>parseInt(e,10)),r=d.tasks.find(t=>t.id===e);if(!r){console.log(B.red(`❌ Parent task ${e} not found.`));return}if(!r.subtasks||!r.subtasks.find(e=>e.id===t)){console.log(B.red(`❌ Subtask ${s} not found.`));return}console.log(B.blue(`💾 Saving research conversation to subtask...`)),await a(u,s,c,!1,n,`text`),console.log(B.green(`✅ Research conversation saved to subtask ${s}`))}else{let e=parseInt(s,10);if(!d.tasks.find(t=>t.id===e)){console.log(B.red(`❌ Task ${s} not found.`));return}console.log(B.blue(`💾 Saving research conversation to task...`)),await i(u,e,c,!1,n,`text`,!0),console.log(B.green(`✅ Research conversation saved to task ${s}`))}return!0}catch(e){return console.log(B.red(`❌ Error saving conversation: ${e.message}`)),r.error(`Error saving conversation: ${e.message}`),!1}}async function Vc(e,t,n,r){try{let n=H.join(t,`.taskmaster`,`docs`,`research`);V.existsSync(n)||V.mkdirSync(n,{recursive:!0});let i=e[0]?.question||`research-query`,a=`${new Date().toISOString().split(`T`)[0]}_${i.toLowerCase().replace(/[^a-z0-9\s-]/g,``).replace(/\s+/g,`-`).replace(/-+/g,`-`).substring(0,50).replace(/^-+|-+$/g,``)}.md`,o=H.join(n,a),s=Hc(e,i);V.writeFileSync(o,s,`utf8`);let c=H.relative(t,o);return console.log(B.green(`✅ Research saved to: ${B.cyan(c)}`)),r.success(`Research conversation saved to ${c}`),o}catch(e){throw console.log(B.red(`❌ Error saving research file: ${e.message}`)),r.error(`Error saving research file: ${e.message}`),e}}function Hc(e,t){let n=new Date().toISOString(),r=`---
|
|
974
978
|
title: Research Session
|
|
975
979
|
query: "${t}"
|
|
976
980
|
date: ${new Date().toLocaleDateString()}
|
|
@@ -983,10 +987,10 @@ exchanges: ${e.length}
|
|
|
983
987
|
|
|
984
988
|
`;return e.forEach((t,n)=>{t.type===`initial`?r+=`## Initial Query\n\n**Question:** ${t.question}\n\n**Response:**\n\n${t.answer}\n\n`:r+=`## Follow-up ${n}\n\n**Question:** ${t.question}\n\n**Response:**\n\n${t.answer}\n\n`,n<e.length-1&&(r+=`---
|
|
985
989
|
|
|
986
|
-
`)}),r+=`\n---\n\n*Generated by Task Master Research Command* \n*Timestamp: ${n}*\n`,r}function
|
|
990
|
+
`)}),r+=`\n---\n\n*Generated by Task Master Research Command* \n*Timestamp: ${n}*\n`,r}function Uc(e){new Date().toISOString();let t=`## Research Session - ${new Date().toLocaleDateString()} ${new Date().toLocaleTimeString()}\n\n`;return e.forEach((n,r)=>{n.type===`initial`?(t+=`**Initial Query:** ${n.question}\n\n`,t+=`**Response:** ${n.answer}\n\n`):(t+=`**Follow-up ${r}:** ${n.question}\n\n`,t+=`**Response:** ${n.answer}\n\n`),r<e.length-1&&(t+=`---
|
|
987
991
|
|
|
988
|
-
`)}),t}function
|
|
989
|
-
`)}const
|
|
992
|
+
`)}),t}function Wc(e){if(e.length===0)return``;let t=[`--- Conversation History ---`];return e.forEach((e,n)=>{let r=e.type===`initial`?`Initial Question`:`Follow-up ${n}`,i=e.type===`initial`?`Initial Answer`:`Answer ${n}`;t.push(`\n${r}: ${e.question}`),t.push(`${i}: ${e.answer}`)}),t.join(`
|
|
993
|
+
`)}const Gc=[`light`,`regular`,`heavy`],Kc=[`done`,`in-progress`,`review`,`cancelled`,`deferred`,`blocked`],qc=[`pending`];function Jc(e){return Gc.includes(e)}async function Yc(e,t,n){let{projectRoot:r,tag:i,session:a}=n;try{let n={tasks:[e],metadata:{analyzedAt:new Date().toISOString()}},o=D(null,{projectRoot:r,tag:i},null);if(!o)return z(`warn`,`No complexity report found - cannot re-analyze complexity`),null;await Ya({file:t,output:o,id:e.id.toString(),projectRoot:r,tag:i,_filteredTasksData:n,_originalTaskCount:1},{session:a});let s=Be(o);if(s){let t=se(s,e.id);if(t)return z(`info`,`Re-analyzed task ${e.id} complexity: ${t.complexityScore}/10`),t.complexityScore}return z(`warn`,`Could not find updated complexity analysis for task ${e.id}`),null}catch(e){return z(`error`,`Failed to re-analyze task complexity: ${e.message}`),null}}function Xc(e,t){let{projectRoot:n,tag:r}=t;try{let t=D(null,{projectRoot:n,tag:r},null);if(!t)return null;let i=Be(t);if(!i)return null;let a=se(i,e);return a?a.complexityScore:null}catch(e){return z(`debug`,`Could not read current complexity score: ${e.message}`),null}}async function Zc(e,t,n,r,a=`regular`,o=null){let{projectRoot:s,tag:c,session:l}=n;if(!e.subtasks||!Array.isArray(e.subtasks)||e.subtasks.length===0)return{updatedTask:e,regenerated:!1,preserved:0,generated:0};let u=e.subtasks.filter(e=>Kc.includes(e.status)),d=e.subtasks.filter(e=>qc.includes(e.status));if(d.length===0)return{updatedTask:e,regenerated:!1,preserved:u.length,generated:0};let f,p=u.length,m=d.length,h=o?Math.max(.5,o/10):1,g=o?` (original complexity: ${o}/10)`:``;if(r===`up`)if(a===`light`){let e=Math.max(5,p+Math.ceil(m*1.1));f=Math.ceil(e*(.8+.4*h))}else if(a===`regular`){let e=Math.max(6,p+Math.ceil(m*1.3));f=Math.ceil(e*(.8+.4*h))}else{let e=Math.max(8,p+Math.ceil(m*1.6));f=Math.ceil(e*(.8+.6*h))}else{let e=o>=8?.7:o>=6?.85:1;if(a===`light`){let t=Math.max(3,p+Math.ceil(m*.8));f=Math.ceil(t*e)}else if(a===`regular`){let t=Math.max(3,p+Math.ceil(m*.5));f=Math.ceil(t*e)}else{let e=o>=9?.3:o>=7?.5:.7,t=Math.max(2,p+Math.ceil(m*.25));f=Math.max(1,Math.ceil(t*e))}}z(`debug`,`Complexity-aware subtask calculation${g}: ${m} pending -> target ${f} total`),z(`debug`,`Complexity-aware calculation${g}: ${m} pending -> ${f} total subtasks (${a} ${r})`);let _=Math.max(1,f-p);try{let t=`Based on this updated task, generate ${_} NEW subtasks that reflect the ${r===`up`?`increased`:`decreased`} complexity level:
|
|
990
994
|
|
|
991
995
|
**Task Title**: ${e.title}
|
|
992
996
|
**Task Description**: ${e.description}
|
|
@@ -1033,7 +1037,7 @@ IMPORTANT:
|
|
|
1033
1037
|
- The 'id' field must be a NUMBER, not a string!
|
|
1034
1038
|
- Dependencies must be strings, not numbers!
|
|
1035
1039
|
|
|
1036
|
-
Ensure the JSON is valid and properly formatted.`,s=U.object({subtasks:U.array(U.object({id:U.int().positive(),title:U.string().min(5),description:U.string().min(10),dependencies:U.array(U.string()),details:U.string().min(20),status:U.string(),testStrategy:U.string()}))}),c=(await i({role:n.research?`research`:`main`,session:n.session,systemPrompt:`You are an expert project manager who creates task breakdowns that match complexity levels.`,prompt:t,schema:s,objectName:`subtask_regeneration`,commandName:n.commandName||`subtask-regen-${r}`,outputType:n.outputType||`cli`})).mainResult.subtasks||[];
|
|
1040
|
+
Ensure the JSON is valid and properly formatted.`,s=U.object({subtasks:U.array(U.object({id:U.int().positive(),title:U.string().min(5),description:U.string().min(10),dependencies:U.array(U.string()),details:U.string().min(20),status:U.string(),testStrategy:U.string()}))}),c=(await i({role:n.research?`research`:`main`,session:n.session,systemPrompt:`You are an expert project manager who creates task breakdowns that match complexity levels.`,prompt:t,schema:s,objectName:`subtask_regeneration`,commandName:n.commandName||`subtask-regen-${r}`,outputType:n.outputType||`cli`})).mainResult.subtasks||[];Qc(c);let l=c.map(e=>({...e,status:e.status||`pending`,testStrategy:e.testStrategy||``})),d=u.reduce((e,t)=>Math.max(e,t.id||0),0)+1,f=new Map,m=l.map(e=>{let t=e.id,n=d++;return f.set(t,n),{...e,id:n}}).map(t=>({...t,dependencies:(t.dependencies||[]).map(t=>{if(typeof t!=`string`||!t.startsWith(`${e.id}.`))return t;let[,n]=t.split(`.`),r=Number.parseInt(n,10),i=f.get(r);return i?`${e.id}.${i}`:t})}));return e.subtasks=[...u,...m],{updatedTask:e,regenerated:!0,preserved:u.length,generated:m.length}}catch(t){return z(`warn`,`Failed to regenerate subtasks for task ${e.id}: ${t.message}`),{updatedTask:e,regenerated:!1,preserved:u.length,generated:0,error:t.message}}}function Qc(e){if(!Array.isArray(e)||e.length===0)return;let t=e.map(e=>e.id);if(t.some(e=>!Number.isInteger(e)||e<1))throw Error(`Generated subtask ids must be positive integers`);let n=new Set(t);if(n.size!==t.length)throw Error(`Generated subtasks must have unique ids`);let r=[...n].sort((e,t)=>e-t);for(let e=0;e<r.length;e+=1)if(r[e]!==e+1)throw Error(`Generated subtask ids must be sequential starting from 1`)}function $c(e,t,n,r){let i=t===`up`,a={light:i?`minor enhancements`:`slight simplifications`,regular:i?`moderate complexity increases`:`moderate simplifications`,heavy:i?`significant complexity additions`:`major simplifications`},o=`You are tasked with adjusting the complexity of a task.
|
|
1037
1041
|
|
|
1038
1042
|
CURRENT TASK:
|
|
1039
1043
|
Title: ${e.title}
|
|
@@ -1062,63 +1066,63 @@ Return a JSON object with the updated task containing these fields:
|
|
|
1062
1066
|
- testStrategy: Updated test strategy
|
|
1063
1067
|
- priority: Task priority ('low', 'medium', or 'high')
|
|
1064
1068
|
|
|
1065
|
-
Ensure the JSON is valid and properly formatted.`,o}async function
|
|
1066
|
-
From: ${B.yellow(n)}\nTo: ${B.green(r)}`,{padding:1,borderColor:`green`,borderStyle:`round`}))}return{success:!0,updatedTasks:u.map(({id:e,oldStatus:t,newStatus:n})=>({id:e,oldStatus:t,newStatus:n}))}}catch(e){if(z(`error`,`Error setting task status: ${e.message}`),!r?.mcpLog)console.error(B.red(`Error: ${e.message}`)),be(r?.session)&&console.error(e),process.exit(1);else throw e}}var
|
|
1069
|
+
Ensure the JSON is valid and properly formatted.`,o}async function el(e,t,n,r,a){let o=$c(e,t,n,r),s=U.object({title:U.string().min(1).describe(`Updated task title reflecting scope adjustment`),description:U.string().min(1).describe(`Updated task description with adjusted scope`),details:U.string().min(1).describe(`Updated implementation details with adjusted complexity`),testStrategy:U.string().min(1).describe(`Updated testing approach for the adjusted scope`),priority:U.enum([`low`,`medium`,`high`]).describe(`Task priority level`)}),c=await i({role:a.research?`research`:`main`,session:a.session,systemPrompt:`You are an expert software project manager who helps adjust task complexity while maintaining clarity and actionability.`,prompt:o,schema:s,objectName:`updated_task`,commandName:a.commandName||`scope-${t}`,outputType:a.outputType||`cli`}),l=c.mainResult,u={...l,priority:l.priority||e.priority||`medium`};return{updatedTask:{...e,...u},telemetryData:c.telemetryData}}async function tl(e,t,n=`regular`,r=null,i={},a=`text`){if(!Jc(n))throw Error(`Invalid strength level: ${n}. Must be one of: ${Gc.join(`, `)}`);let{projectRoot:o=`.`,tag:s=`master`}=i,c=w(e,o,s),l=c?.tasks||[];for(let e of t)if(!Pc(l,e))throw Error(`Task with ID ${e} not found`);let u=[],d=null;for(let f of t){let t=ie(l,f).task;if(!t)throw Error(`Task with ID ${f} not found`);a===`text`&&z(`info`,`Scoping up task ${f}: ${t.title}`);let p=Xc(f,i);p&&a===`text`&&z(`info`,`Original complexity: ${p}/10`);let m=await el(t,`up`,n,r,i),h=await Zc(m.updatedTask,e,i,`up`,n,p);a===`text`&&h.regenerated&&z(`info`,`Regenerated ${h.generated} pending subtasks (preserved ${h.preserved} completed)`);let g=c.tasks.findIndex(e=>e.id===f);if(g!==-1&&(c.tasks[g]=h.updatedTask,u.push(h.updatedTask)),i.session&&p)try{_(e,c,o,s);let t=await Yc(h.updatedTask,e,i);if(t&&a===`text`){let e=t-p;z(`info`,`New complexity: ${p}/10 ${e>0?`↗️`:e<0?`↘️`:`➡️`} ${t}/10 (${e>0?`+`:``}${e})`)}}catch(e){a===`text`&&z(`warn`,`Could not re-analyze complexity: ${e.message}`)}m.telemetryData&&(d?(d.inputTokens+=m.telemetryData.inputTokens||0,d.outputTokens+=m.telemetryData.outputTokens||0,d.totalTokens+=m.telemetryData.totalTokens||0,d.totalCost+=m.telemetryData.totalCost||0):d={...m.telemetryData})}return _(e,c,o,s),a===`text`&&z(`info`,`Successfully scoped up ${u.length} task(s)`),{updatedTasks:u,telemetryData:d}}async function nl(e,t,n=`regular`,r=null,i={},a=`text`){if(!Jc(n))throw Error(`Invalid strength level: ${n}. Must be one of: ${Gc.join(`, `)}`);let{projectRoot:o=`.`,tag:s=`master`}=i,c=w(e,o,s),l=c?.tasks||[];for(let e of t)if(!Pc(l,e))throw Error(`Task with ID ${e} not found`);let u=[],d=null;for(let f of t){let t=ie(l,f).task;if(!t)throw Error(`Task with ID ${f} not found`);a===`text`&&z(`info`,`Scoping down task ${f}: ${t.title}`);let p=Xc(f,i);p&&a===`text`&&z(`info`,`Original complexity: ${p}/10`);let m=await el(t,`down`,n,r,i),h=await Zc(m.updatedTask,e,i,`down`,n,p);a===`text`&&h.regenerated&&z(`info`,`Regenerated ${h.generated} pending subtasks (preserved ${h.preserved} completed)`);let g=c.tasks.findIndex(e=>e.id===f);if(g!==-1&&(c.tasks[g]=h.updatedTask,u.push(h.updatedTask)),i.session&&p)try{_(e,c,o,s);let t=await Yc(h.updatedTask,e,i);if(t&&a===`text`){let e=t-p;z(`info`,`New complexity: ${p}/10 ${e>0?`↗️`:e<0?`↘️`:`➡️`} ${t}/10 (${e>0?`+`:``}${e})`)}}catch(e){a===`text`&&z(`warn`,`Could not re-analyze complexity: ${e.message}`)}m.telemetryData&&(d?(d.inputTokens+=m.telemetryData.inputTokens||0,d.outputTokens+=m.telemetryData.outputTokens||0,d.totalTokens+=m.telemetryData.totalTokens||0,d.totalCost+=m.telemetryData.totalCost||0):d={...m.telemetryData})}return _(e,c,o,s),a===`text`&&z(`info`,`Successfully scoped down ${u.length} task(s)`),{updatedTasks:u,telemetryData:d}}async function rl(e,t,n,r,i=!0){if(!ea(n))throw Error(`Error: Invalid status value: ${n}. Use one of: ${TASK_STATUS_OPTIONS.join(`, `)}`);if(t.includes(`.`)){let[e,a]=t.split(`.`).map(e=>parseInt(e,10)),o=r.tasks.find(t=>t.id===e);if(!o)throw Error(`Parent task ${e} not found`);if(!o.subtasks)throw Error(`Parent task ${e} has no subtasks`);let s=o.subtasks.find(e=>e.id===a);if(!s)throw Error(`Subtask ${a} not found in parent task ${e}`);let c=s.status||`pending`;s.status=n,z(`info`,`Updated subtask ${e}.${a} status from '${c}' to '${n}'`),(n.toLowerCase()===`done`||n.toLowerCase()===`completed`)&&o.subtasks.every(e=>e.status===`done`||e.status===`completed`)&&o.status!==`done`&&o.status!==`completed`&&i&&(console.log(B.yellow(`All subtasks of parent task ${e} are now marked as done.`)),console.log(B.yellow(`Consider updating the parent task status with: task-master set-status --id=${e} --status=done`)))}else{let e=parseInt(t,10),i=r.tasks.find(t=>t.id===e);if(!i)throw Error(`Task ${e} not found`);let a=i.status||`pending`;if(i.status=n,z(`info`,`Updated task ${e} status from '${a}' to '${n}'`),(n.toLowerCase()===`done`||n.toLowerCase()===`completed`)&&i.subtasks&&i.subtasks.length>0){let e=i.subtasks.filter(e=>e.status!==`done`&&e.status!==`completed`);e.length>0&&(z(`info`,`Also marking ${e.length} subtasks as '${n}'`),e.forEach(e=>{e.status=n}))}}}var il=rl;async function al(e,t,n,r={}){let{projectRoot:i,tag:a}=r;try{if(!ea(n))throw Error(`Error: Invalid status value: ${n}. Use one of: ${$i.join(`, `)}`);let o=!!r?.mcpLog;o||console.log(W(B.white.bold(`Updating Task Status to: ${n}`),{padding:1,borderColor:`blue`,borderStyle:`round`})),z(`info`,`Reading tasks from ${e}...`);let s=w(e,i,a);if(s&&s._rawTaggedData&&(s=s._rawTaggedData),!s||!s[a]||!Array.isArray(s[a].tasks))throw Error(`Invalid tasks file or tag "${a}" not found at ${e}`);let c={tasks:s[a].tasks,tag:a,_rawTaggedData:s};if(!c||!c.tasks)throw Error(`No valid tasks found in ${e}`);let l=t.split(`,`).map(e=>e.trim()),u=[];for(let t of l){let r=`unknown`;if(t.includes(`.`)){let[e,n]=t.split(`.`).map(e=>parseInt(e,10)),i=c.tasks.find(t=>t.id===e);i?.subtasks&&(r=i.subtasks.find(e=>e.id===n)?.status||`pending`)}else{let e=parseInt(t,10);r=c.tasks.find(t=>t.id===e)?.status||`pending`}await il(e,t,n,c,!o),u.push({id:t,oldStatus:r,newStatus:n})}if(s[a].tasks=c.tasks,ne(s[a],{description:`Tasks for ${a} context`}),_(e,s,i,a),z(`info`,`Validating dependencies after status update...`),Wl(c.tasks),!o)for(let e of u){let{id:t,oldStatus:n,newStatus:r}=e;console.log(W(B.white.bold(`Successfully updated task ${t} status:`)+`
|
|
1070
|
+
From: ${B.yellow(n)}\nTo: ${B.green(r)}`,{padding:1,borderColor:`green`,borderStyle:`round`}))}return{success:!0,updatedTasks:u.map(({id:e,oldStatus:t,newStatus:n})=>({id:e,oldStatus:t,newStatus:n}))}}catch(e){if(z(`error`,`Error setting task status: ${e.message}`),!r?.mcpLog)console.error(B.red(`Error: ${e.message}`)),be(r?.session)&&console.error(e),process.exit(1);else throw e}}var ol=al;async function sl(e,t,n,i=!1,a={},s=a.mcpLog?`json`:`text`){let{session:c,mcpLog:l,projectRoot:u,tag:d,metadata:f}=a,p=l||z,m=!!l,h=(e,...t)=>{m?typeof p[e]==`function`?p[e](...t):p.info(...t):L()||p(e,...t)},g=null;try{if(h(`info`,`Updating subtask ${t} with prompt: "${n}"`),!t||typeof t!=`string`)throw Error(`Subtask ID cannot be empty.`);if((!n||typeof n!=`string`||n.trim()===``)&&!f)throw Error(`Prompt cannot be empty unless metadata is provided. Please provide context for the subtask update or metadata to merge.`);let a=u||Fe();if(!a)throw Error(`Could not determine project root directory`);let l=await Hr({taskId:t,prompt:n,projectRoot:a,tag:d,appendMode:!0,useResearch:i,metadata:f,isMCP:m,outputFormat:s,report:h});if(l)return{updatedSubtask:{id:t},telemetryData:l.telemetryData,tagInfo:l.tagInfo};if(!t.includes(`.`))throw Error(`Invalid subtask ID format: ${t}. In solo mode, subtask ID must be in format "parentId.subtaskId" (e.g., "5.2").`);if(!V.existsSync(e))throw Error(`Tasks file not found at path: ${e}`);let p=w(e,a,d);if(!p||!p.tasks)throw Error(`No valid tasks found in ${e}. The file may be corrupted or have an invalid format.`);let[v,y]=t.split(`.`),x=parseInt(v,10),S=parseInt(y,10);if(Number.isNaN(x)||x<=0||Number.isNaN(S)||S<=0)throw Error(`Invalid subtask ID format: ${t}. Both parent ID and subtask ID must be positive integers.`);let C=p.tasks.find(e=>e.id===x);if(!C)throw Error(`Parent task with ID ${x} not found. Please verify the task ID and try again.`);if(!C.subtasks||!Array.isArray(C.subtasks))throw Error(`Parent task ${x} has no subtasks.`);let T=C.subtasks.findIndex(e=>e.id===S);if(T===-1)throw Error(`Subtask with ID ${t} not found. Please verify the subtask ID and try again.`);let E=C.subtasks[T];if(f&&(!n||n.trim()===``))return h(`info`,`Metadata-only update for subtask ${t}`),E.metadata={...E.metadata||{},...f},C.subtasks[T]=E,_(e,p,a,d),h(`success`,`Successfully updated metadata for subtask ${t}`),{updatedSubtask:E,telemetryData:null,tagInfo:{tag:d}};let D=``;try{let e=new za(a,d),r=new qa(ke(p.tasks),`update-subtask`),i=`${C.title} ${E.title} ${n}`,o=r.findRelevantTasks(i,{maxResults:5,includeSelf:!0}),s=r.getTaskIds(o),c=[...new Set([t.toString(),...s])];c.length>0&&(D=(await e.gather({tasks:c,format:`research`})).context||``)}catch(e){h(`warn`,`Could not gather context: ${e.message}`)}if(s===`text`){let e=new K({head:[B.cyan.bold(`ID`),B.cyan.bold(`Title`),B.cyan.bold(`Status`)],colWidths:[10,55,10]});e.push([t,o(E.title,52),xl(E.status)]),console.log(W(B.white.bold(`Updating Subtask #${t}`),{padding:1,borderColor:`blue`,borderStyle:`round`,margin:{top:1,bottom:0}})),console.log(e.toString()),g=_l(i?`Updating subtask with research...`:`Updating subtask...`)}let O=``,k=``,A=null;try{let e={id:C.id,title:C.title},t=T>0?{id:`${C.id}.${C.subtasks[T-1].id}`,title:C.subtasks[T-1].title,status:C.subtasks[T-1].status}:void 0,o=T<C.subtasks.length-1?{id:`${C.id}.${C.subtasks[T+1].id}`,title:C.subtasks[T+1].title,status:C.subtasks[T+1].status}:void 0,l=La(),u={parentTask:e,prevSubtask:t,nextSubtask:o,currentDetails:E.details||`(No existing details)`,updatePrompt:n,useResearch:i,gatheredContext:D||``,hasCodebaseAnalysis:b(i,a,c,{command:`update-subtask`,updatePrompt:n,task:C}),projectRoot:a},d=i?`research`:`default`,{systemPrompt:f,userPrompt:p}=await l.loadPrompt(`update-subtask`,u,d),_=i?`research`:`main`;h(`info`,`Using AI text service with role: ${_}`),A=await r({prompt:p,systemPrompt:f,role:_,session:c,projectRoot:a,maxRetries:2,commandName:`update-subtask`,outputType:m?`mcp`:`cli`}),A&&A.mainResult&&typeof A.mainResult==`string`?O=A.mainResult:(O=``,h(`warn`,`AI service response did not contain expected text string.`)),s===`text`&&g&&($(g),g=null)}catch(e){throw h(`error`,`AI service call failed: ${e.message}`),s===`text`&&g&&($(g),g=null),e}if(O&&O.trim()){let e=new Date().toISOString(),t=`<info added on ${e}>\n${O.trim()}\n</info added on ${e}>`;k=t,E.details=(E.details?E.details+`
|
|
1067
1071
|
`:``)+t}else h(`warn`,`AI response was empty or whitespace after trimming. Original details remain unchanged.`),k=`No new details were added by the AI.`;let j=C.subtasks[T];return f&&(j.metadata={...j.metadata||{},...f}),s===`text`&&be(c)&&console.log(`>>> DEBUG: Subtask details AFTER AI update:`,j.details),j.description&&n.length<100&&(s===`text`&&be(c)&&console.log(`>>> DEBUG: Subtask description BEFORE append:`,j.description),j.description+=` [Updated: ${new Date().toLocaleDateString()}]`,s===`text`&&be(c)&&console.log(`>>> DEBUG: Subtask description AFTER append:`,j.description)),s===`text`&&be(c)&&console.log(`>>> DEBUG: About to call writeJSON with updated data...`),_(e,p,a,d),s===`text`&&be(c)&&console.log(`>>> DEBUG: writeJSON call completed.`),h(`success`,`Successfully updated subtask ${t}`),s===`text`&&(g&&=($(g),null),console.log(W(B.green(`Successfully updated subtask #${t}`)+`
|
|
1068
1072
|
|
|
1069
1073
|
`+B.white.bold(`Title:`)+` `+j.title+`
|
|
1070
1074
|
|
|
1071
1075
|
`+B.white.bold(`Newly Added Snippet:`)+`
|
|
1072
|
-
`+B.white(k),{padding:1,borderColor:`green`,borderStyle:`round`}))),s===`text`&&A.telemetryData&&
|
|
1076
|
+
`+B.white(k),{padding:1,borderColor:`green`,borderStyle:`round`}))),s===`text`&&A.telemetryData&&Ml(A.telemetryData,`cli`),{updatedSubtask:j,telemetryData:A.telemetryData,tagInfo:A.tagInfo}}catch(e){if(s===`text`&&g&&($(g),g=null),h(`error`,`Error updating subtask: ${e.message}`),s===`text`)console.error(B.red(`Error: ${e.message}`)),e.message?.includes(`ANTHROPIC_API_KEY`)?(console.log(B.yellow(`
|
|
1073
1077
|
To fix this issue, set your Anthropic API key:`)),console.log(` export ANTHROPIC_API_KEY=your_api_key_here`)):e.message?.includes(`PERPLEXITY_API_KEY`)?(console.log(B.yellow(`
|
|
1074
1078
|
To fix this issue:`)),console.log(` 1. Set your Perplexity API key: export PERPLEXITY_API_KEY=your_api_key_here`),console.log(` 2. Or run without the research flag: task-master update-subtask --id=<id> --prompt="..."`)):e.message?.includes(`overloaded`)?(console.log(B.yellow(`
|
|
1075
1079
|
AI model overloaded, and fallback failed or was unavailable:`)),console.log(` 1. Try again in a few minutes.`),console.log(` 2. Ensure PERPLEXITY_API_KEY is set for fallback.`)):e.message?.includes(`not found`)?(console.log(B.yellow(`
|
|
1076
1080
|
To fix this issue:`)),console.log(` 1. Run task-master list --with-subtasks to see all available subtask IDs`),console.log(` 2. Use a valid subtask ID with the --id parameter in format "parentId.subtaskId"`)):(e.message?.includes(`empty stream response`)||e.message?.includes(`AI did not return a valid text string`))&&console.log(B.yellow(`
|
|
1077
|
-
The AI model returned an empty or invalid response. This might be due to the prompt or API issues. Try rephrasing or trying again later.`)),be(c)&&console.error(e);else throw e;return null}}var
|
|
1081
|
+
The AI model returned an empty or invalid response. This might be due to the prompt or API issues. Try rephrasing or trying again later.`)),be(c)&&console.error(e);else throw e;return null}}var cl=sl;async function ll(e,t,n,a=!1,s={},c=`text`,l=!1){let{session:u,mcpLog:d,projectRoot:f,tag:p,metadata:m}=s,{report:h,isMCP:g}=Qa(d,u);try{if(h(`info`,`Updating single task ${t} with prompt: "${n}"`),t==null||String(t).trim()===``)throw Error(`Task ID cannot be empty.`);if((!n||typeof n!=`string`||n.trim()===``)&&!m)throw Error(`Prompt cannot be empty unless metadata is provided for update.`);let s=f||Fe();if(!s)throw Error(`Could not determine project root directory`);a&&!Ue(`perplexity`,u)&&(h(`warn`,`Perplexity research requested but API key not set. Falling back.`),c===`text`&&console.log(B.yellow(`Perplexity AI not available. Falling back to main AI.`)),a=!1);let d=await Hr({taskId:t,prompt:n,projectRoot:s,tag:p,appendMode:l,useResearch:a,metadata:m,isMCP:g,outputFormat:c,report:h});if(d)return d;if(!V.existsSync(e))throw Error(`Tasks file not found: ${e}`);let v=w(e,s,p);if(!v||!v.tasks)throw Error(`No valid tasks found in ${e}.`);let y=String(t).trim();if(!/^\d+$/.test(y))throw Error(`For file storage, taskId must be a positive integer. Use update-subtask-by-id for IDs like "1.2", or run in API storage for display IDs (e.g., "HAM-123").`);let x=Number(y),S=v.tasks.findIndex(e=>e.id===x);if(S===-1)throw h(`error`,`Task with ID ${x} not found`),Error(`Task with ID ${x} not found.`);let C=v.tasks[S];if(C.status===`done`||C.status===`completed`)return h(`warn`,`Task ${t} is already marked as done and cannot be updated`),c===`text`&&console.log(W(B.yellow(`Task ${t} is already marked as ${C.status} and cannot be updated.`)+`
|
|
1078
1082
|
|
|
1079
1083
|
`+B.white(`Completed tasks are locked to maintain consistency. To modify a completed task, you must first:`)+`
|
|
1080
1084
|
`+B.white(`1. Change its status to "pending" or "in-progress"`)+`
|
|
1081
|
-
`+B.white(`2. Then run the update-task command`),{padding:1,borderColor:`yellow`,borderStyle:`round`})),null;if(m&&(!n||n.trim()===``))return h(`info`,`Metadata-only update for task ${t}`),C.metadata={...C.metadata||{},...m},v.tasks[S]=C,_(e,v,s,p),h(`success`,`Successfully updated metadata for task ${t}`),{updatedTask:C,telemetryData:null,tagInfo:{tag:p}};let T=``;try{let e=new
|
|
1085
|
+
`+B.white(`2. Then run the update-task command`),{padding:1,borderColor:`yellow`,borderStyle:`round`})),null;if(m&&(!n||n.trim()===``))return h(`info`,`Metadata-only update for task ${t}`),C.metadata={...C.metadata||{},...m},v.tasks[S]=C,_(e,v,s,p),h(`success`,`Successfully updated metadata for task ${t}`),{updatedTask:C,telemetryData:null,tagInfo:{tag:p}};let T=``;try{let e=new za(s,p),r=new qa(ke(v.tasks),`update-task`),i=`${C.title} ${C.description} ${n}`,a=r.findRelevantTasks(i,{maxResults:5,includeSelf:!0}),o=r.getTaskIds(a),c=[...new Set([t.toString(),...o])];c.length>0&&(T=(await e.gather({tasks:c,format:`research`})).context||``)}catch(e){h(`warn`,`Could not gather context: ${e.message}`)}if(c===`text`){let e=new K({head:[B.cyan.bold(`ID`),B.cyan.bold(`Title`),B.cyan.bold(`Status`)],colWidths:[5,60,10]});e.push([C.id,o(C.title,57),xl(C.status)]),console.log(W(B.white.bold(`Updating Task #${t}`),{padding:1,borderColor:`blue`,borderStyle:`round`,margin:{top:1,bottom:0}})),console.log(e.toString()),console.log(W(B.cyan.bold(`How Completed Subtasks Are Handled:`)+`
|
|
1082
1086
|
|
|
1083
1087
|
`+B.white(`• Subtasks marked as "done" or "completed" will be preserved
|
|
1084
1088
|
`)+B.white(`• New subtasks will build upon what has already been completed
|
|
1085
1089
|
`)+B.white(`• If completed work needs revision, a new subtask will be created instead of modifying done items
|
|
1086
|
-
`)+B.white(`• This approach maintains a clear record of completed work and new requirements`),{padding:1,borderColor:`blue`,borderStyle:`round`,margin:{top:1,bottom:1}}))}let E=
|
|
1090
|
+
`)+B.white(`• This approach maintains a clear record of completed work and new requirements`),{padding:1,borderColor:`blue`,borderStyle:`round`,margin:{top:1,bottom:1}}))}let E=La(),D={task:C,taskJson:JSON.stringify(C,null,2),updatePrompt:n,appendMode:l,useResearch:a,currentDetails:C.details||`(No existing details)`,gatheredContext:T||``,hasCodebaseAnalysis:b(a,s,u,{command:`update-task`,updatePrompt:n,task:C}),projectRoot:s},O=l?`append`:a?`research`:`default`;h(`info`,`Loading prompt template with variant: ${O}, appendMode: ${l}, useResearch: ${a}`);let k,A;try{let e=E.loadPrompt(`update-task`,D,O);h(`info`,`Prompt result type: ${typeof e}, keys: ${e?Object.keys(e).join(`, `):`null`}`),k=e.systemPrompt,A=e.userPrompt,h(`info`,`Loaded prompts - systemPrompt length: ${k?.length}, userPrompt length: ${A?.length}`)}catch(e){throw h(`error`,`Failed to load prompt template: ${e.message}`),Error(`Failed to load prompt template: ${e.message}`)}if(!k||!A)throw Error(`Failed to load prompts: systemPrompt=${!!k}, userPrompt=${!!A}`);let j=null,M=null;!g&&c===`text`&&(j=_l(a?`Updating task with research...
|
|
1087
1091
|
`:`Updating task...
|
|
1088
|
-
`));try{let o=a?`research`:`main`;if(M=l?await r({role:o,session:u,projectRoot:s,systemPrompt:k,prompt:A,commandName:`update-task`,outputType:g?`mcp`:`cli`}):await i({role:o,session:u,projectRoot:s,systemPrompt:k,prompt:A,schema:
|
|
1092
|
+
`));try{let o=a?`research`:`main`;if(M=l?await r({role:o,session:u,projectRoot:s,systemPrompt:k,prompt:A,commandName:`update-task`,outputType:g?`mcp`:`cli`}):await i({role:o,session:u,projectRoot:s,systemPrompt:k,prompt:A,schema:Ta[`update-task-by-id`],objectName:`task`,commandName:`update-task`,outputType:g?`mcp`:`cli`}),j&&$(j,`AI update complete.`),l){let r=M.mainResult,i=``;if(r&&r.trim()){let e=new Date().toISOString(),t=`<info added on ${e}>\n${r.trim()}\n</info added on ${e}>`;i=t,C.details=(C.details?C.details+`
|
|
1089
1093
|
`:``)+t}else h(`warn`,`AI response was empty or whitespace after trimming. Original details remain unchanged.`),i=`No new details were added by the AI.`;return n.length<100&&C.description&&(C.description+=` [Updated: ${new Date().toLocaleDateString()}]`),m&&(C.metadata={...C.metadata||{},...m}),v.tasks[S]=C,_(e,v,s,p),h(`success`,`Successfully appended to task ${t}`),c===`text`&&console.log(W(B.green(`Successfully appended to task #${t}`)+`
|
|
1090
1094
|
|
|
1091
1095
|
`+B.white.bold(`Title:`)+` `+C.title+`
|
|
1092
1096
|
|
|
1093
1097
|
`+B.white.bold(`Newly Added Content:`)+`
|
|
1094
|
-
`+B.white(i),{padding:1,borderColor:`green`,borderStyle:`round`})),c===`text`&&M.telemetryData&&
|
|
1098
|
+
`+B.white(i),{padding:1,borderColor:`green`,borderStyle:`round`})),c===`text`&&M.telemetryData&&Ml(M.telemetryData,`cli`),{updatedTask:C,telemetryData:M.telemetryData,tagInfo:M.tagInfo}}let d=M.mainResult?.task;if(!d||typeof d!=`object`)throw Error(`Received invalid task object from AI.`);let f={...d,dependencies:d.dependencies??[],priority:d.priority??null,details:d.details??null,testStrategy:d.testStrategy??null};if(!f.title||!f.description)throw Error(`Updated task missing required fields.`);if(f.id!==t&&(h(`warn`,`AI changed task ID. Restoring original ID ${t}.`),f.id=t),f.status!==C.status&&!n.toLowerCase().includes(`status`)&&(h(`warn`,`AI changed task status. Restoring original status '${C.status}'.`),f.status=C.status),f.subtasks&&Array.isArray(f.subtasks)){let e=1;f.subtasks=f.subtasks.map(t=>{let n=C.subtasks?.find(e=>String(e.id)===String(t.id)||t.title&&e.title===t.title),r={...t,id:e,dependencies:Array.isArray(t.dependencies)?t.dependencies.map(e=>typeof e==`string`?parseInt(e,10):e).filter(t=>!Number.isNaN(t)&&t>=1&&t<e):[],status:t.status||`pending`,testStrategy:t.testStrategy??null,...n?.metadata&&{metadata:n.metadata}};return e++,r}),h(`info`,`Fixed ${f.subtasks.length} subtask IDs to be sequential numeric IDs.`)}if(C.subtasks?.length>0)if(!f.subtasks)h(`warn`,`Subtasks removed by AI. Restoring original subtasks.`),f.subtasks=C.subtasks;else{C.subtasks.filter(e=>e.status===`done`||e.status===`completed`).forEach(e=>{let t=f.subtasks.find(t=>t.id===e.id);(!t||JSON.stringify(t)!==JSON.stringify(e))&&(h(`warn`,`Completed subtask ${e.id} was modified or removed. Restoring.`),f.subtasks=f.subtasks.filter(t=>t.id!==e.id),f.subtasks.push(e))});let e=new Set;f.subtasks=f.subtasks.filter(t=>e.has(t.id)?(h(`warn`,`Duplicate subtask ID ${t.id} removed.`),!1):(e.add(t.id),!0))}return(C.metadata||m)&&(f.metadata={...C.metadata||{},...m||{}}),v.tasks[S]=f,_(e,v,s,p),h(`success`,`Successfully updated task ${t}`),c===`text`&&M.telemetryData&&Ml(M.telemetryData,`cli`),{updatedTask:f,telemetryData:M.telemetryData,tagInfo:M.tagInfo}}catch(e){throw j&&$(j),h(`error`,`Error during AI service call: ${e.message}`),e.message.includes(`API key`)&&h(`error`,`Please ensure API keys are configured correctly.`),e}}catch(e){throw h(`error`,`Error updating task: ${e.message}`),c===`text`&&(console.error(B.red(`Error: ${e.message}`)),be(u)&&console.error(e),process.exit(1)),e}}var ul=ll;async function dl(e,t,n,r=!1,a={},s=`text`){let{session:c,mcpLog:l,projectRoot:u,tag:d}=a,f=l||z,p=!!l;p?f.info(`updateTasks called with context: session=${!!c}`):f(`info`,`updateTasks called`);try{p?f.info(`Updating tasks from ID ${t}`):f(`info`,`Updating tasks from ID ${t} with prompt: "${n}"`);let a=u||Fe();if(!a)throw Error(`Could not determine project root directory`);let l=w(e,a,d);if(!l||!l.tasks)throw Error(`No valid tasks found in ${e}`);let m=l.tasks.filter(e=>e.id>=t&&e.status!==`done`);if(m.length===0){p?f.info(`No tasks to update (ID >= ${t} and not 'done').`):f(`info`,`No tasks to update (ID >= ${t} and not 'done').`),s===`text`&&console.log();return}let h=``;try{let e=new za(a,d),t=new qa(ke(l.tasks),`update`),r=t.findRelevantTasks(n,{maxResults:5,includeSelf:!0}),i=t.getTaskIds(r),o=m.map(e=>e.id.toString()),s=[...new Set([...o,...i])];s.length>0&&(h=(await e.gather({tasks:s,format:`research`})).context||``)}catch(e){f(`warn`,`Could not gather additional context: ${e.message}`)}if(s===`text`){let e=new K({head:[B.cyan.bold(`ID`),B.cyan.bold(`Title`),B.cyan.bold(`Status`)],colWidths:[5,70,20]});m.forEach(t=>{e.push([t.id,o(t.title,57),xl(t.status)])}),console.log(W(B.white.bold(`Updating ${m.length} tasks`),{padding:1,borderColor:`blue`,borderStyle:`round`,margin:{top:1,bottom:0}})),console.log(e.toString()),console.log(W(B.cyan.bold(`How Completed Subtasks Are Handled:`)+`
|
|
1095
1099
|
|
|
1096
1100
|
`+B.white(`• Subtasks marked as "done" or "completed" will be preserved
|
|
1097
1101
|
`)+B.white(`• New subtasks will build upon what has already been completed
|
|
1098
1102
|
`)+B.white(`• If completed work needs revision, a new subtask will be created instead of modifying done items
|
|
1099
|
-
`)+B.white(`• This approach maintains a clear record of completed work and new requirements`),{padding:1,borderColor:`blue`,borderStyle:`round`,margin:{top:1,bottom:1}}))}let{systemPrompt:g,userPrompt:v}=await
|
|
1100
|
-
`));try{x=await i({role:r?`research`:`main`,session:c,projectRoot:a,systemPrompt:g,prompt:v,schema:Sa[`update-tasks`],objectName:`tasks`,commandName:`update-tasks`,outputType:p?`mcp`:`cli`}),y&&$(y,`AI update complete.`);let t=x.mainResult.tasks.map(e=>({...e,dependencies:e.dependencies??[],priority:e.priority??null,details:e.details??null,testStrategy:e.testStrategy??null,subtasks:e.subtasks?e.subtasks.map(e=>({...e,dependencies:e.dependencies??[],status:e.status??`pending`,testStrategy:e.testStrategy??null})):null}));if(!Array.isArray(t))throw Error(`Parsed AI response for updated tasks was not an array.`);p?f.info(`Received ${t.length} updated tasks from AI.`):f(`info`,`Received ${t.length} updated tasks from AI.`);let n=new Map(t.map(e=>[e.id,e])),o=0;return l.tasks.forEach((e,t)=>{if(n.has(e.id)){let r=n.get(e.id);l.tasks[t]={...e,...r,subtasks:r.subtasks===void 0?e.subtasks:r.subtasks},o++}}),p?f.info(`Applied updates to ${o} tasks in the dataset.`):f(`info`,`Applied updates to ${o} tasks in the dataset.`),_(e,l,a,d),p?f.info(`Successfully updated ${o} tasks in ${e}`):f(`success`,`Successfully updated ${o} tasks in ${e}`),s===`text`&&x.telemetryData&&kl(x.telemetryData,`cli`),{success:!0,updatedTasks:t,telemetryData:x.telemetryData,tagInfo:x.tagInfo}}catch(e){throw y&&$(y),p?f.error(`Error during AI service call: ${e.message}`):f(`error`,`Error during AI service call: ${e.message}`),e.message.includes(`API key`)&&(p?f.error(`Please ensure API keys are configured correctly in .env or mcp.json.`):f(`error`,`Please ensure API keys are configured correctly in .env or mcp.json.`)),e}finally{y&&$(y)}}catch(e){if(p?f.error(`Error updating tasks: ${e.message}`):f(`error`,`Error updating tasks: ${e.message}`),s===`text`)console.error(B.red(`Error: ${e.message}`)),be(c)&&console.error(e),process.exit(1);else throw e}}var ll=cl;const ul=it([`#fb8b24`,`#e36414`,`#9a031e`]);function dl(e){L()||!e||!e._migrationHappened||console.log(W(B.white.bold(`FYI: `)+B.gray(`Taskmaster now supports separate task lists per tag. `)+B.cyan(`Use the --tag flag to create/read/update/filter tasks by tag.`),{padding:{top:0,bottom:0,left:2,right:2},borderColor:`cyan`,borderStyle:`round`,margin:{top:1,bottom:1}}))}async function fl(e,t={}){if(L())return;let{skipIfMaster:n=!1,dim:r=!1,storageType:i,briefInfo:a}=t;if(n&&e===`master`)return;if(!i||!a)try{let t=de.getInstance().getContext();t&&t.briefId?(i=`api`,a={briefId:t.briefId,briefName:t.briefName||e}):i=`file`}catch(e){z(`debug`,`Failed to detect storage type: ${e.message}`),i=`file`}i!==`api`&&i!==`file`&&(i=`file`);let o;o=i===`api`&&a?`[brief] ${B.cyan(a.briefName)} ${B.gray(`(${a.briefId})`)}`:r?B.gray(`[tag] ${e}`):B.dim(`[tag] `)+B.cyan(e),console.log(o)}function pl(){L()||Ot({version:na(),projectName:ge(null)})}function ml(e){return L()?null:J({text:e,color:`cyan`}).start()}function $(e){e&&typeof e.stop==`function`&&e.stop()}function hl(e,t=null){e&&typeof e.succeed==`function`&&(t?e.succeed(t):e.succeed())}function gl(e,t=null){e&&typeof e.fail==`function`&&(t?e.fail(t):e.fail())}function _l(e,t=30,n=null){let r=n?Math.min(100,e+(n.deferred||0)+(n.cancelled||0)):e,i=Math.round(e*t/100),a=Math.round(r*t/100),o=a-i,s=t-a,c;c=e<25?B.red:e<50?B.hex(`#FFA500`):e<75?B.yellow:e<100?B.green:B.hex(`#006400`);let l=c(`█`.repeat(i)),u=B.gray(`█`.repeat(o)),d=``;if(n&&s>0){let e={pending:B.yellow,"in-progress":B.hex(`#FFA500`),blocked:B.red,review:B.magenta},t=Object.entries(n).filter(([e])=>![`deferred`,`cancelled`,`done`,`completed`].includes(e)).reduce((e,[t,n])=>e+n,0);if(t<=0)d=B.gray(`░`.repeat(s));else{let r=0;for(let[i,a]of Object.entries(n)){if([`deferred`,`cancelled`,`done`,`completed`].includes(i))continue;let n=Math.round(a/t*s),o=Math.min(n,s-r),c=e[i]||B.gray;d+=c(`░`.repeat(o)),r+=o}r<s&&(d+=B.gray(`░`.repeat(s-r)))}}else d=B.gray(`░`.repeat(s));let f=e===100?B.hex(`#006400`):r===100?B.gray:c;return`${l}${u}${d} ${f(`${r.toFixed(0)}%`)}`}function vl(e,t=!1){if(!e)return B.gray(`❓ unknown`);let n={done:{color:B.green,icon:`✓`,tableIcon:`✓`},completed:{color:B.green,icon:`✓`,tableIcon:`✓`},pending:{color:B.yellow,icon:`○`,tableIcon:`⏱`},"in-progress":{color:B.hex(`#FFA500`),icon:`🔄`,tableIcon:`►`},deferred:{color:B.gray,icon:`x`,tableIcon:`⏱`},blocked:{color:B.red,icon:`!`,tableIcon:`✗`},review:{color:B.magenta,icon:`?`,tableIcon:`?`},cancelled:{color:B.gray,icon:`❌`,tableIcon:`x`}}[e.toLowerCase()]||{color:B.red,icon:`❌`,tableIcon:`✗`};if(t){let t={done:`✓`,completed:`✓`,pending:`○`,"in-progress":`►`,deferred:`x`,blocked:`!`,review:`?`}[e.toLowerCase()]||`x`;return n.color(`${t} ${e}`)}return n.color(`${n.icon} ${e}`)}function yl(e,t,n=!1,r=null){return!e||!Array.isArray(e)||e.length===0?n?B.gray(`None`):`None`:e.map(e=>{let i=e.toString();if(i.includes(`.`)){let a=i.split(`.`);if(a.length!==2||!a[0]||!a[1]){let a=ie(t,typeof e==`string`?parseInt(e,10):e,r).task;if(!a)return n?B.red(`${i} (Not found)`):`${i} (Not found)`;let o=a.status||`pending`,s=o.toLowerCase()===`done`||o.toLowerCase()===`completed`,c=o.toLowerCase()===`in-progress`;return n?s?B.green.bold(i):c?B.yellow.bold(i):B.red.bold(i):i}let[o,s]=a.map(e=>parseInt(e,10)),c=t.find(e=>e.id===o);if(!c||!c.subtasks)return n?B.red(`${i} (Not found)`):`${i} (Not found)`;let l=c.subtasks.find(e=>e.id===s);if(!l)return n?B.red(`${i} (Not found)`):`${i} (Not found)`;let u=l.status||`pending`,d=u.toLowerCase()===`done`||u.toLowerCase()===`completed`,f=u.toLowerCase()===`in-progress`;return n?d?B.green.bold(i):f?B.hex(`#FFA500`).bold(i):B.red.bold(i):i}let a=ie(t,typeof e==`string`?parseInt(e,10):e,r).task;if(!a)return n?B.red(`${i} (Not found)`):`${i} (Not found)`;let o=a.status||`pending`,s=o.toLowerCase()===`done`||o.toLowerCase()===`completed`,c=o.toLowerCase()===`in-progress`;return n?s?B.green.bold(i):c?B.yellow.bold(i):B.red.bold(i):i}).join(`, `)}function bl(){let e=process.stdout.columns||100;console.log(W(B.white.bold(`Task Master CLI`),{padding:1,borderColor:`blue`,borderStyle:`round`,margin:{top:1,bottom:1}})),[{title:`Project Setup & Configuration`,color:`blue`,commands:[{name:`init`,args:`[--name=<name>] [--description=<desc>] [-y]`,desc:`Initialize a new project with Task Master structure`},{name:`models`,args:``,desc:`View current AI model configuration and available models`},{name:`models --setup`,args:``,desc:`Run interactive setup to configure AI models`},{name:`models --set-main`,args:`<model_id>`,desc:`Set the primary model for task generation`},{name:`models --set-research`,args:`<model_id>`,desc:`Set the model for research operations`},{name:`models --set-fallback`,args:`<model_id>`,desc:`Set the fallback model (optional)`}]},{title:`Task Generation`,color:`cyan`,commands:[{name:`parse-prd`,args:`--input=<file.txt> [--num-tasks=10]`,desc:`Generate tasks from a PRD document`},{name:`generate`,args:``,desc:`Create individual task files from tasks.json`}]},{title:`Task Management`,color:`green`,commands:[{name:`list`,args:`[<status>|all] [-s <status>] [-t <tag>]`,desc:`List all tasks - use "all" to show with subtasks`},{name:`list`,args:`[--with-subtasks] [-f <format>] [--json] [-c]`,desc:`Options: format (text/json/compact), subtasks`},{name:`list`,args:`[-w] [--ready] [--blocking] [--all-tags]`,desc:`Options: watch mode, ready/blocking filters, all tags`},{name:`set-status`,args:`<id> <status>`,desc:`Update task status (${Xi.join(`, `)})`},{name:`sync-readme`,args:`[--with-subtasks] [--status=<status>]`,desc:`Export tasks to README.md with professional formatting`},{name:`update`,args:`--from=<id> --prompt="<context>"`,desc:`Update multiple tasks based on new requirements`},{name:`update-task`,args:`<id> <prompt...>`,desc:`Update a single task (no quotes needed for multi-word prompts)`},{name:`update-subtask`,args:`--id=<parentId.subtaskId> --prompt="<context>"`,desc:`Append additional information to a subtask`},{name:`add-task`,args:`--prompt="<text>" [--dependencies=<ids>] [--priority=<priority>]`,desc:`Add a new task using AI`},{name:`remove-task`,args:`--id=<id> [-y]`,desc:`Permanently remove a task or subtask`}]},{title:`Subtask Management`,color:`yellow`,commands:[{name:`add-subtask`,args:`--parent=<id> --title="<title>" [--description="<desc>"]`,desc:`Add a new subtask to a parent task`},{name:`add-subtask`,args:`--parent=<id> --task-id=<id>`,desc:`Convert an existing task into a subtask`},{name:`remove-subtask`,args:`--id=<parentId.subtaskId> [--convert]`,desc:`Remove a subtask (optionally convert to standalone task)`},{name:`clear-subtasks`,args:`--id=<id>`,desc:`Remove all subtasks from specified tasks`},{name:`clear-subtasks --all`,args:``,desc:`Remove subtasks from all tasks`}]},{title:`Task Analysis & Breakdown`,color:`magenta`,commands:[{name:`analyze-complexity`,args:`[--research] [--threshold=5]`,desc:`Analyze tasks and generate expansion recommendations`},{name:`complexity-report`,args:`[--file=<path>]`,desc:`Display the complexity analysis report`},{name:`expand`,args:`--id=<id> [--num=5] [--research] [--prompt="<context>"]`,desc:`Break down tasks into detailed subtasks`},{name:`expand --all`,args:`[--force] [--research]`,desc:`Expand all pending tasks with subtasks`},{name:`research`,args:`"<prompt>" [-i=<task_ids>] [-f=<file_paths>] [-c="<context>"] [--tree] [-s=<save_file>] [-d=<detail_level>]`,desc:`Perform AI-powered research queries with project context`}]},{title:`Task Navigation & Viewing`,color:`cyan`,commands:[{name:`next`,args:``,desc:`Show the next task to work on based on dependencies`},{name:`show`,args:`<id>`,desc:`Display detailed information about a specific task`}]},{title:`Tag Management`,color:`magenta`,commands:[{name:`tags`,args:`[list] [--show-metadata] [--ready]`,desc:`List all available tags with task counts`},{name:`tags add`,args:`<name> [--description <desc>] [--copy-from <tag>]`,desc:`Create a new tag (--from-branch for git branch name)`},{name:`tags use`,args:`<name>`,desc:`Switch to a different tag context`},{name:`tags remove`,args:`<name> [-y]`,desc:`Delete an existing tag and all its tasks`},{name:`tags rename`,args:`<oldName> <newName>`,desc:`Rename an existing tag`},{name:`tags copy`,args:`<source> <target> [--description <desc>]`,desc:`Copy a tag with all its tasks`}]},{title:`Dependency Management`,color:`blue`,commands:[{name:`add-dependency`,args:`--id=<id> --depends-on=<id>`,desc:`Add a dependency to a task`},{name:`remove-dependency`,args:`--id=<id> --depends-on=<id>`,desc:`Remove a dependency from a task`},{name:`validate-dependencies`,args:``,desc:`Identify invalid dependencies without fixing them`},{name:`fix-dependencies`,args:``,desc:`Fix invalid dependencies automatically`}]}].forEach(t=>{console.log(W(B[t.color].bold(t.title),{padding:{left:2,right:2,top:0,bottom:0},margin:{top:1,bottom:0},borderColor:t.color,borderStyle:`round`}));let n=new K({colWidths:[Math.max(25,Math.floor(e*.2)),Math.max(40,Math.floor(e*.35)),Math.max(45,Math.floor(e*.45)-10)],chars:{top:``,"top-mid":``,"top-left":``,"top-right":``,bottom:``,"bottom-mid":``,"bottom-left":``,"bottom-right":``,left:``,"left-mid":``,mid:``,"mid-mid":``,right:``,"right-mid":``,middle:` `},style:{border:[],"padding-left":4},wordWrap:!0});t.commands.forEach((e,t)=>{n.push([`${B.yellow.bold(e.name)}${B.reset(``)}`,`${B.white(e.args)}${B.reset(``)}`,`${B.dim(e.desc)}${B.reset(``)}`])}),console.log(n.toString()),console.log(``)}),console.log(W(B.cyan.bold(`Configuration`),{padding:{left:2,right:2,top:0,bottom:0},margin:{top:1,bottom:0},borderColor:`cyan`,borderStyle:`round`}));let t=e||process.stdout.columns||100,n=new K({colWidths:[Math.max(30,Math.floor(t*.25)),Math.max(50,Math.floor(t*.45)),Math.max(30,Math.floor(t*.3)-10)],chars:{top:``,"top-mid":``,"top-left":``,"top-right":``,bottom:``,"bottom-mid":``,"bottom-left":``,"bottom-right":``,left:``,"left-mid":``,mid:``,"mid-mid":``,right:``,"right-mid":``,middle:` `},style:{border:[],"padding-left":4},wordWrap:!0});n.push([`${B.yellow(c)}${B.reset(``)}`,`${B.white(`AI model configuration file (project root)`)}${B.reset(``)}`,`${B.dim(`Managed by models cmd`)}${B.reset(``)}`],[`${B.yellow(`API Keys (.env)`)}${B.reset(``)}`,`${B.white(`API keys for AI providers (ANTHROPIC_API_KEY, etc.)`)}${B.reset(``)}`,`${B.dim(`Required in .env file`)}${B.reset(``)}`],[`${B.yellow(`MCP Keys (mcp.json)`)}${B.reset(``)}`,`${B.white(`API keys for Cursor integration`)}${B.reset(``)}`,`${B.dim(`Required in .cursor/`)}${B.reset(``)}`]),console.log(n.toString()),console.log(``),console.log(W(B.white.bold(`Quick Start:`)+`
|
|
1103
|
+
`)+B.white(`• This approach maintains a clear record of completed work and new requirements`),{padding:1,borderColor:`blue`,borderStyle:`round`,margin:{top:1,bottom:1}}))}let{systemPrompt:g,userPrompt:v}=await La().loadPrompt(`update-tasks`,{tasks:m,updatePrompt:n,useResearch:r,projectContext:h,hasCodebaseAnalysis:b(r,a,c,{command:`update-tasks`,updatePrompt:n,tasks:m}),projectRoot:a}),y=null,x=null;!p&&s===`text`&&(y=_l(`Updating tasks with AI...
|
|
1104
|
+
`));try{x=await i({role:r?`research`:`main`,session:c,projectRoot:a,systemPrompt:g,prompt:v,schema:Ta[`update-tasks`],objectName:`tasks`,commandName:`update-tasks`,outputType:p?`mcp`:`cli`}),y&&$(y,`AI update complete.`);let t=x.mainResult.tasks.map(e=>({...e,dependencies:e.dependencies??[],priority:e.priority??null,details:e.details??null,testStrategy:e.testStrategy??null,subtasks:e.subtasks?e.subtasks.map(e=>({...e,dependencies:e.dependencies??[],status:e.status??`pending`,testStrategy:e.testStrategy??null})):null}));if(!Array.isArray(t))throw Error(`Parsed AI response for updated tasks was not an array.`);p?f.info(`Received ${t.length} updated tasks from AI.`):f(`info`,`Received ${t.length} updated tasks from AI.`);let n=new Map(t.map(e=>[e.id,e])),o=0;return l.tasks.forEach((e,t)=>{if(n.has(e.id)){let r=n.get(e.id);l.tasks[t]={...e,...r,subtasks:r.subtasks===void 0?e.subtasks:r.subtasks},o++}}),p?f.info(`Applied updates to ${o} tasks in the dataset.`):f(`info`,`Applied updates to ${o} tasks in the dataset.`),_(e,l,a,d),p?f.info(`Successfully updated ${o} tasks in ${e}`):f(`success`,`Successfully updated ${o} tasks in ${e}`),s===`text`&&x.telemetryData&&Ml(x.telemetryData,`cli`),{success:!0,updatedTasks:t,telemetryData:x.telemetryData,tagInfo:x.tagInfo}}catch(e){throw y&&$(y),p?f.error(`Error during AI service call: ${e.message}`):f(`error`,`Error during AI service call: ${e.message}`),e.message.includes(`API key`)&&(p?f.error(`Please ensure API keys are configured correctly in .env or mcp.json.`):f(`error`,`Please ensure API keys are configured correctly in .env or mcp.json.`)),e}finally{y&&$(y)}}catch(e){if(p?f.error(`Error updating tasks: ${e.message}`):f(`error`,`Error updating tasks: ${e.message}`),s===`text`)console.error(B.red(`Error: ${e.message}`)),be(c)&&console.error(e),process.exit(1);else throw e}}var fl=dl;const pl=it([`#fb8b24`,`#e36414`,`#9a031e`]);function ml(e){L()||!e||!e._migrationHappened||console.log(W(B.white.bold(`FYI: `)+B.gray(`Taskmaster now supports separate task lists per tag. `)+B.cyan(`Use the --tag flag to create/read/update/filter tasks by tag.`),{padding:{top:0,bottom:0,left:2,right:2},borderColor:`cyan`,borderStyle:`round`,margin:{top:1,bottom:1}}))}async function hl(e,t={}){if(L())return;let{skipIfMaster:n=!1,dim:r=!1,storageType:i,briefInfo:a}=t;if(n&&e===`master`)return;if(!i||!a)try{let t=de.getInstance().getContext();t&&t.briefId?(i=`api`,a={briefId:t.briefId,briefName:t.briefName||e}):i=`file`}catch(e){z(`debug`,`Failed to detect storage type: ${e.message}`),i=`file`}i!==`api`&&i!==`file`&&(i=`file`);let o;o=i===`api`&&a?`[brief] ${B.cyan(a.briefName)} ${B.gray(`(${a.briefId})`)}`:r?B.gray(`[tag] ${e}`):B.dim(`[tag] `)+B.cyan(e),console.log(o)}function gl(){L()||Ot({version:aa(),projectName:ge(null)})}function _l(e){return L()?null:J({text:e,color:`cyan`}).start()}function $(e){e&&typeof e.stop==`function`&&e.stop()}function vl(e,t=null){e&&typeof e.succeed==`function`&&(t?e.succeed(t):e.succeed())}function yl(e,t=null){e&&typeof e.fail==`function`&&(t?e.fail(t):e.fail())}function bl(e,t=30,n=null){let r=n?Math.min(100,e+(n.deferred||0)+(n.cancelled||0)):e,i=Math.round(e*t/100),a=Math.round(r*t/100),o=a-i,s=t-a,c;c=e<25?B.red:e<50?B.hex(`#FFA500`):e<75?B.yellow:e<100?B.green:B.hex(`#006400`);let l=c(`█`.repeat(i)),u=B.gray(`█`.repeat(o)),d=``;if(n&&s>0){let e={pending:B.yellow,"in-progress":B.hex(`#FFA500`),blocked:B.red,review:B.magenta},t=Object.entries(n).filter(([e])=>![`deferred`,`cancelled`,`done`,`completed`].includes(e)).reduce((e,[t,n])=>e+n,0);if(t<=0)d=B.gray(`░`.repeat(s));else{let r=0;for(let[i,a]of Object.entries(n)){if([`deferred`,`cancelled`,`done`,`completed`].includes(i))continue;let n=Math.round(a/t*s),o=Math.min(n,s-r),c=e[i]||B.gray;d+=c(`░`.repeat(o)),r+=o}r<s&&(d+=B.gray(`░`.repeat(s-r)))}}else d=B.gray(`░`.repeat(s));let f=e===100?B.hex(`#006400`):r===100?B.gray:c;return`${l}${u}${d} ${f(`${r.toFixed(0)}%`)}`}function xl(e,t=!1){if(!e)return B.gray(`❓ unknown`);let n={done:{color:B.green,icon:`✓`,tableIcon:`✓`},completed:{color:B.green,icon:`✓`,tableIcon:`✓`},pending:{color:B.yellow,icon:`○`,tableIcon:`⏱`},"in-progress":{color:B.hex(`#FFA500`),icon:`🔄`,tableIcon:`►`},deferred:{color:B.gray,icon:`x`,tableIcon:`⏱`},blocked:{color:B.red,icon:`!`,tableIcon:`✗`},review:{color:B.magenta,icon:`?`,tableIcon:`?`},cancelled:{color:B.gray,icon:`❌`,tableIcon:`x`}}[e.toLowerCase()]||{color:B.red,icon:`❌`,tableIcon:`✗`};if(t){let t={done:`✓`,completed:`✓`,pending:`○`,"in-progress":`►`,deferred:`x`,blocked:`!`,review:`?`}[e.toLowerCase()]||`x`;return n.color(`${t} ${e}`)}return n.color(`${n.icon} ${e}`)}function Sl(e,t,n=!1,r=null){return!e||!Array.isArray(e)||e.length===0?n?B.gray(`None`):`None`:e.map(e=>{let i=e.toString();if(i.includes(`.`)){let a=i.split(`.`);if(a.length!==2||!a[0]||!a[1]){let a=ie(t,typeof e==`string`?parseInt(e,10):e,r).task;if(!a)return n?B.red(`${i} (Not found)`):`${i} (Not found)`;let o=a.status||`pending`,s=o.toLowerCase()===`done`||o.toLowerCase()===`completed`,c=o.toLowerCase()===`in-progress`;return n?s?B.green.bold(i):c?B.yellow.bold(i):B.red.bold(i):i}let[o,s]=a.map(e=>parseInt(e,10)),c=t.find(e=>e.id===o);if(!c||!c.subtasks)return n?B.red(`${i} (Not found)`):`${i} (Not found)`;let l=c.subtasks.find(e=>e.id===s);if(!l)return n?B.red(`${i} (Not found)`):`${i} (Not found)`;let u=l.status||`pending`,d=u.toLowerCase()===`done`||u.toLowerCase()===`completed`,f=u.toLowerCase()===`in-progress`;return n?d?B.green.bold(i):f?B.hex(`#FFA500`).bold(i):B.red.bold(i):i}let a=ie(t,typeof e==`string`?parseInt(e,10):e,r).task;if(!a)return n?B.red(`${i} (Not found)`):`${i} (Not found)`;let o=a.status||`pending`,s=o.toLowerCase()===`done`||o.toLowerCase()===`completed`,c=o.toLowerCase()===`in-progress`;return n?s?B.green.bold(i):c?B.yellow.bold(i):B.red.bold(i):i}).join(`, `)}function Cl(){let e=process.stdout.columns||100;console.log(W(B.white.bold(`Task Master CLI`),{padding:1,borderColor:`blue`,borderStyle:`round`,margin:{top:1,bottom:1}})),[{title:`Project Setup & Configuration`,color:`blue`,commands:[{name:`init`,args:`[--name=<name>] [--description=<desc>] [-y]`,desc:`Initialize a new project with Task Master structure`},{name:`models`,args:``,desc:`View current AI model configuration and available models`},{name:`models --setup`,args:``,desc:`Run interactive setup to configure AI models`},{name:`models --set-main`,args:`<model_id>`,desc:`Set the primary model for task generation`},{name:`models --set-research`,args:`<model_id>`,desc:`Set the model for research operations`},{name:`models --set-fallback`,args:`<model_id>`,desc:`Set the fallback model (optional)`}]},{title:`Task Generation`,color:`cyan`,commands:[{name:`parse-prd`,args:`--input=<file.txt> [--num-tasks=10]`,desc:`Generate tasks from a PRD document`},{name:`generate`,args:``,desc:`Create individual task files from tasks.json`}]},{title:`Task Management`,color:`green`,commands:[{name:`list`,args:`[<status>|all] [-s <status>] [-t <tag>]`,desc:`List all tasks - use "all" to show with subtasks`},{name:`list`,args:`[--with-subtasks] [-f <format>] [--json] [-c]`,desc:`Options: format (text/json/compact), subtasks`},{name:`list`,args:`[-w] [--ready] [--blocking] [--all-tags]`,desc:`Options: watch mode, ready/blocking filters, all tags`},{name:`set-status`,args:`<id> <status>`,desc:`Update task status (${$i.join(`, `)})`},{name:`sync-readme`,args:`[--with-subtasks] [--status=<status>]`,desc:`Export tasks to README.md with professional formatting`},{name:`update`,args:`--from=<id> --prompt="<context>"`,desc:`Update multiple tasks based on new requirements`},{name:`update-task`,args:`<id> <prompt...>`,desc:`Update a single task (no quotes needed for multi-word prompts)`},{name:`update-subtask`,args:`--id=<parentId.subtaskId> --prompt="<context>"`,desc:`Append additional information to a subtask`},{name:`add-task`,args:`--prompt="<text>" [--dependencies=<ids>] [--priority=<priority>]`,desc:`Add a new task using AI`},{name:`remove-task`,args:`--id=<id> [-y]`,desc:`Permanently remove a task or subtask`}]},{title:`Subtask Management`,color:`yellow`,commands:[{name:`add-subtask`,args:`--parent=<id> --title="<title>" [--description="<desc>"]`,desc:`Add a new subtask to a parent task`},{name:`add-subtask`,args:`--parent=<id> --task-id=<id>`,desc:`Convert an existing task into a subtask`},{name:`remove-subtask`,args:`--id=<parentId.subtaskId> [--convert]`,desc:`Remove a subtask (optionally convert to standalone task)`},{name:`clear-subtasks`,args:`--id=<id>`,desc:`Remove all subtasks from specified tasks`},{name:`clear-subtasks --all`,args:``,desc:`Remove subtasks from all tasks`}]},{title:`Task Analysis & Breakdown`,color:`magenta`,commands:[{name:`analyze-complexity`,args:`[--research] [--threshold=5]`,desc:`Analyze tasks and generate expansion recommendations`},{name:`complexity-report`,args:`[--file=<path>]`,desc:`Display the complexity analysis report`},{name:`expand`,args:`--id=<id> [--num=5] [--research] [--prompt="<context>"]`,desc:`Break down tasks into detailed subtasks`},{name:`expand --all`,args:`[--force] [--research]`,desc:`Expand all pending tasks with subtasks`},{name:`research`,args:`"<prompt>" [-i=<task_ids>] [-f=<file_paths>] [-c="<context>"] [--tree] [-s=<save_file>] [-d=<detail_level>]`,desc:`Perform AI-powered research queries with project context`}]},{title:`Task Navigation & Viewing`,color:`cyan`,commands:[{name:`next`,args:``,desc:`Show the next task to work on based on dependencies`},{name:`show`,args:`<id>`,desc:`Display detailed information about a specific task`}]},{title:`Tag Management`,color:`magenta`,commands:[{name:`tags`,args:`[list] [--show-metadata] [--ready]`,desc:`List all available tags with task counts`},{name:`tags add`,args:`<name> [--description <desc>] [--copy-from <tag>]`,desc:`Create a new tag (--from-branch for git branch name)`},{name:`tags use`,args:`<name>`,desc:`Switch to a different tag context`},{name:`tags remove`,args:`<name> [-y]`,desc:`Delete an existing tag and all its tasks`},{name:`tags rename`,args:`<oldName> <newName>`,desc:`Rename an existing tag`},{name:`tags copy`,args:`<source> <target> [--description <desc>]`,desc:`Copy a tag with all its tasks`}]},{title:`Dependency Management`,color:`blue`,commands:[{name:`add-dependency`,args:`--id=<id> --depends-on=<id>`,desc:`Add a dependency to a task`},{name:`remove-dependency`,args:`--id=<id> --depends-on=<id>`,desc:`Remove a dependency from a task`},{name:`validate-dependencies`,args:``,desc:`Identify invalid dependencies without fixing them`},{name:`fix-dependencies`,args:``,desc:`Fix invalid dependencies automatically`}]}].forEach(t=>{console.log(W(B[t.color].bold(t.title),{padding:{left:2,right:2,top:0,bottom:0},margin:{top:1,bottom:0},borderColor:t.color,borderStyle:`round`}));let n=new K({colWidths:[Math.max(25,Math.floor(e*.2)),Math.max(40,Math.floor(e*.35)),Math.max(45,Math.floor(e*.45)-10)],chars:{top:``,"top-mid":``,"top-left":``,"top-right":``,bottom:``,"bottom-mid":``,"bottom-left":``,"bottom-right":``,left:``,"left-mid":``,mid:``,"mid-mid":``,right:``,"right-mid":``,middle:` `},style:{border:[],"padding-left":4},wordWrap:!0});t.commands.forEach((e,t)=>{n.push([`${B.yellow.bold(e.name)}${B.reset(``)}`,`${B.white(e.args)}${B.reset(``)}`,`${B.dim(e.desc)}${B.reset(``)}`])}),console.log(n.toString()),console.log(``)}),console.log(W(B.cyan.bold(`Configuration`),{padding:{left:2,right:2,top:0,bottom:0},margin:{top:1,bottom:0},borderColor:`cyan`,borderStyle:`round`}));let t=e||process.stdout.columns||100,n=new K({colWidths:[Math.max(30,Math.floor(t*.25)),Math.max(50,Math.floor(t*.45)),Math.max(30,Math.floor(t*.3)-10)],chars:{top:``,"top-mid":``,"top-left":``,"top-right":``,bottom:``,"bottom-mid":``,"bottom-left":``,"bottom-right":``,left:``,"left-mid":``,mid:``,"mid-mid":``,right:``,"right-mid":``,middle:` `},style:{border:[],"padding-left":4},wordWrap:!0});n.push([`${B.yellow(c)}${B.reset(``)}`,`${B.white(`AI model configuration file (project root)`)}${B.reset(``)}`,`${B.dim(`Managed by models cmd`)}${B.reset(``)}`],[`${B.yellow(`API Keys (.env)`)}${B.reset(``)}`,`${B.white(`API keys for AI providers (ANTHROPIC_API_KEY, etc.)`)}${B.reset(``)}`,`${B.dim(`Required in .env file`)}${B.reset(``)}`],[`${B.yellow(`MCP Keys (mcp.json)`)}${B.reset(``)}`,`${B.white(`API keys for Cursor integration`)}${B.reset(``)}`,`${B.dim(`Required in .cursor/`)}${B.reset(``)}`]),console.log(n.toString()),console.log(``),console.log(W(B.white.bold(`Quick Start:`)+`
|
|
1101
1105
|
|
|
1102
1106
|
`+B.cyan(`1. Create Project: `)+B.white(`task-master init`)+`
|
|
1103
1107
|
`+B.cyan(`2. Setup Models: `)+B.white(`task-master models --setup`)+`
|
|
1104
1108
|
`+B.cyan(`3. Parse PRD: `)+B.white(`task-master parse-prd --input=<prd-file>`)+`
|
|
1105
1109
|
`+B.cyan(`4. List Tasks: `)+B.white(`task-master list`)+`
|
|
1106
|
-
`+B.cyan(`5. Find Next Task: `)+B.white(`task-master next`),{padding:1,borderColor:`yellow`,borderStyle:`round`,margin:{top:1},width:Math.min(t-10,100)}))}function
|
|
1110
|
+
`+B.cyan(`5. Find Next Task: `)+B.white(`task-master next`),{padding:1,borderColor:`yellow`,borderStyle:`round`,margin:{top:1},width:Math.min(t-10,100)}))}function wl(e){return e<=3?B.green(`● ${e}`):e<=6?B.yellow(`● ${e}`):B.red(`● ${e}`)}async function Tl(e){if(!V.existsSync(e)){console.log(W(B.yellow(`No complexity report found at ${e}\n\n`)+`Would you like to generate one now?`,{padding:1,borderColor:`yellow`,borderStyle:`round`,margin:{top:1}}));let t=nt.createInterface({input:process.stdin,output:process.stdout}),n=await new Promise(e=>{t.question(B.cyan(`Generate complexity report? (y/n): `),e)});if(t.close(),n.toLowerCase()===`y`||n.toLowerCase()===`yes`){console.log(B.blue(`Generating complexity report...`));let t=m;return V.existsSync(t)?(await Ya({output:e,research:!1,file:t}),Tl(e)):(console.error(`❌ No tasks.json file found. Please run "task-master init" or create a tasks.json file.`),null)}else{console.log(B.yellow(`Report generation cancelled.`));return}}let t;try{t=JSON.parse(V.readFileSync(e,`utf8`))}catch(e){z(`error`,`Error reading complexity report: ${e.message}`);return}console.log(W(B.white.bold(`Task Complexity Analysis Report`),{padding:1,borderColor:`blue`,borderStyle:`round`,margin:{top:1,bottom:1}}));let n=new K({style:{head:[],border:[],"padding-top":0,"padding-bottom":0,compact:!0},chars:{mid:``,"left-mid":``,"mid-mid":``,"right-mid":``},colWidths:[20,50]});n.push([B.cyan.bold(`Generated:`),new Date(t.meta.generatedAt).toLocaleString()],[B.cyan.bold(`Tasks Analyzed:`),t.meta.tasksAnalyzed],[B.cyan.bold(`Threshold Score:`),t.meta.thresholdScore],[B.cyan.bold(`Project:`),t.meta.projectName],[B.cyan.bold(`Research-backed:`),t.meta.usedResearch?`Yes`:`No`]),console.log(n.toString());let r=[...t.complexityAnalysis].sort((e,t)=>t.complexityScore-e.complexityScore),i=r.filter(e=>e.complexityScore>=t.meta.thresholdScore),a=r.filter(e=>e.complexityScore<t.meta.thresholdScore),s=[0,0,0];r.forEach(e=>{e.complexityScore<5?s[0]++:e.complexityScore<8?s[1]++:s[2]++});let c=Math.round(s[0]/r.length*100),l=Math.round(s[1]/r.length*100),u=Math.round(s[2]/r.length*100);console.log(W(B.white.bold(`Complexity Distribution
|
|
1107
1111
|
|
|
1108
|
-
`)+`${B.green.bold(`Low (1-4):`)} ${s[0]} tasks (${c}%)\n${B.yellow.bold(`Medium (5-7):`)} ${s[1]} tasks (${l}%)\n${B.red.bold(`High (8-10):`)} ${s[2]} tasks (${u}%)`,{padding:1,borderColor:`cyan`,borderStyle:`round`,margin:{top:1,bottom:1}}));let d=process.stdout.columns||100,f=Math.floor(d*.25),p=d-12-f-8-8-10,h=new K({head:[B.yellow.bold(`ID`),B.yellow.bold(`Title`),B.yellow.bold(`Score`),B.yellow.bold(`Subtasks`),B.yellow.bold(`Expansion Command`)],colWidths:[12,f,8,8,p],style:{head:[],border:[]},wordWrap:!0,wrapOnWordBoundary:!0});if(i.forEach(e=>{let t=`task-master expand --id=${e.taskId} --num=${e.recommendedSubtasks}${e.expansionPrompt?` --prompt="${e.expansionPrompt}"`:``}`;h.push([e.taskId,o(e.taskTitle,f-3),
|
|
1112
|
+
`)+`${B.green.bold(`Low (1-4):`)} ${s[0]} tasks (${c}%)\n${B.yellow.bold(`Medium (5-7):`)} ${s[1]} tasks (${l}%)\n${B.red.bold(`High (8-10):`)} ${s[2]} tasks (${u}%)`,{padding:1,borderColor:`cyan`,borderStyle:`round`,margin:{top:1,bottom:1}}));let d=process.stdout.columns||100,f=Math.floor(d*.25),p=d-12-f-8-8-10,h=new K({head:[B.yellow.bold(`ID`),B.yellow.bold(`Title`),B.yellow.bold(`Score`),B.yellow.bold(`Subtasks`),B.yellow.bold(`Expansion Command`)],colWidths:[12,f,8,8,p],style:{head:[],border:[]},wordWrap:!0,wrapOnWordBoundary:!0});if(i.forEach(e=>{let t=`task-master expand --id=${e.taskId} --num=${e.recommendedSubtasks}${e.expansionPrompt?` --prompt="${e.expansionPrompt}"`:``}`;h.push([e.taskId,o(e.taskTitle,f-3),wl(e.complexityScore),e.recommendedSubtasks,B.cyan(t)])}),console.log(h.toString()),a.length>0){console.log(W(B.green.bold(`Simple Tasks (${a.length})`),{padding:{left:2,right:2,top:0,bottom:0},margin:{top:1,bottom:0},borderColor:`green`,borderStyle:`round`}));let e=new K({head:[B.green.bold(`ID`),B.green.bold(`Title`),B.green.bold(`Score`),B.green.bold(`Reasoning`)],colWidths:[5,40,8,50],style:{head:[],border:[]}});a.forEach(t=>{e.push([t.taskId,o(t.taskTitle,37),wl(t.complexityScore),o(t.reasoning,47)])}),console.log(e.toString())}console.log(W(B.white.bold(`Suggested Actions:`)+`
|
|
1109
1113
|
|
|
1110
|
-
${B.cyan(`1.`)} Expand all complex tasks: ${B.yellow(`task-master expand --all`)}\n${B.cyan(`2.`)} Expand a specific task: ${B.yellow(`task-master expand --id=<id>`)}\n${B.cyan(`3.`)} Regenerate with research: ${B.yellow(`task-master analyze-complexity --research`)}`,{padding:1,borderColor:`cyan`,borderStyle:`round`,margin:{top:1}}))}async function
|
|
1111
|
-
`)+B.yellow(`Executing this command will overwrite any existing tasks.`),{padding:1,borderColor:`yellow`,borderStyle:`round`,margin:{top:1}}));let t=nt.createInterface({input:process.stdin,output:process.stdout}),n=await new Promise(e=>{t.question(B.cyan(`Are you sure you wish to continue? (y/N): `),e)});return t.close(),n.toLowerCase()===`y`||n.toLowerCase()===`yes`}function
|
|
1112
|
-
🔑 API Key Status:`)),console.log(t.toString()),console.log(B.gray(` Note: Some providers (e.g., Azure, Ollama) may require additional endpoint configuration in ${c}.`))}const
|
|
1113
|
-
Active Model Configuration:`));let n=e.activeModels,r=new K({head:[`Role`,`Provider`,`Model ID`,`SWE Score`,`Cost ($/1M tkns)`].map(e=>B.cyan.bold(e)),colWidths:[10,14,30,18,20],style:{head:[`cyan`,`bold`]}});r.push([B.white(`Main`),n.main.provider,n.main.modelId,
|
|
1114
|
+
${B.cyan(`1.`)} Expand all complex tasks: ${B.yellow(`task-master expand --all`)}\n${B.cyan(`2.`)} Expand a specific task: ${B.yellow(`task-master expand --id=<id>`)}\n${B.cyan(`3.`)} Regenerate with research: ${B.yellow(`task-master analyze-complexity --research`)}`,{padding:1,borderColor:`cyan`,borderStyle:`round`,margin:{top:1}}))}async function El(e){console.log(W(B.yellow(`It looks like you've already generated tasks for this project.
|
|
1115
|
+
`)+B.yellow(`Executing this command will overwrite any existing tasks.`),{padding:1,borderColor:`yellow`,borderStyle:`round`,margin:{top:1}}));let t=nt.createInterface({input:process.stdin,output:process.stdout}),n=await new Promise(e=>{t.question(B.cyan(`Are you sure you wish to continue? (y/N): `),e)});return t.close(),n.toLowerCase()===`y`||n.toLowerCase()===`yes`}function Dl(e){if(!e||e.length===0){console.log(B.yellow(`No API key status information available.`));return}let t=new K({head:[B.cyan(`Provider`),B.cyan(`CLI Key (.env)`),B.cyan(`MCP Key (mcp.json)`)],colWidths:[15,20,25],chars:{mid:``,"left-mid":``,"mid-mid":``,"right-mid":``}});e.forEach(({provider:e,cli:n,mcp:r})=>{let i=n?B.green(`✅ Found`):B.red(`❌ Missing`),a=r?B.green(`✅ Found`):B.red(`❌ Missing`),o=e.charAt(0).toUpperCase()+e.slice(1);t.push([o,i,a])}),console.log(B.bold(`
|
|
1116
|
+
🔑 API Key Status:`)),console.log(t.toString()),console.log(B.gray(` Note: Some providers (e.g., Azure, Ollama) may require additional endpoint configuration in ${c}.`))}const Ol=(e,t)=>{if(e==null||e<=0)return`N/A`;let n=`${(e*100).toFixed(1)}%`,r=[...t.map(e=>e.sweScore).filter(e=>e!=null&&e>0)].sort((e,t)=>t-e),i=r.length,a=B.gray(`☆☆☆`);if(i>0){let t=Math.max(0,Math.floor(i/3)-1),n=Math.max(0,Math.floor(2*i/3)-1);a=e>=r[t]?B.yellow(`★★★`):e>=r[n]?B.yellow(`★★`)+B.gray(`☆`):B.yellow(`★`)+B.gray(`☆☆`)}return`${n} ${a}`},kl=e=>{if(!e)return`N/A`;if(e.input===0&&e.output===0)return B.green(`Free`);let t=e=>{if(e==null)return`N/A`;let t=Number.isInteger(e);return`$${e.toFixed(t?0:2)}`};return`${t(e.input)} in, ${t(e.output)} out`};function Al(e,t=[]){console.log(B.cyan.bold(`
|
|
1117
|
+
Active Model Configuration:`));let n=e.activeModels,r=new K({head:[`Role`,`Provider`,`Model ID`,`SWE Score`,`Cost ($/1M tkns)`].map(e=>B.cyan.bold(e)),colWidths:[10,14,30,18,20],style:{head:[`cyan`,`bold`]}});r.push([B.white(`Main`),n.main.provider,n.main.modelId,Ol(n.main.sweScore,t),kl(n.main.cost)]),r.push([B.white(`Research`),n.research.provider,n.research.modelId,Ol(n.research.sweScore,t),kl(n.research.cost)]),n.fallback&&n.fallback.provider&&n.fallback.modelId?r.push([B.white(`Fallback`),n.fallback.provider,n.fallback.modelId,Ol(n.fallback.sweScore,t),kl(n.fallback.cost)]):r.push([B.white(`Fallback`),B.gray(`-`),B.gray(`(Not Set)`),B.gray(`-`),B.gray(`-`)]),console.log(r.toString())}function jl(e){if(!e||e.length===0){console.log(B.gray(`
|
|
1114
1118
|
(No other models available or all are configured)`));return}console.log(B.cyan.bold(`
|
|
1115
|
-
Other Available Models:`));let t=new K({head:[`Provider`,`Model ID`,`SWE Score`,`Cost ($/1M tkns)`].map(e=>B.cyan.bold(e)),colWidths:[15,40,18,25],style:{head:[`cyan`,`bold`]}});e.forEach(n=>{t.push([n.provider,n.modelId,
|
|
1119
|
+
Other Available Models:`));let t=new K({head:[`Provider`,`Model ID`,`SWE Score`,`Cost ($/1M tkns)`].map(e=>B.cyan.bold(e)),colWidths:[15,40,18,25],style:{head:[`cyan`,`bold`]}});e.forEach(n=>{t.push([n.provider,n.modelId,Ol(n.sweScore,e),kl(n.cost)])}),console.log(t.toString()),console.log(W(B.white.bold(`Next Steps:`)+`
|
|
1116
1120
|
`+B.cyan(`1. Set main model: ${B.yellow(`task-master models --set-main <model_id>`)}`)+`
|
|
1117
1121
|
`+B.cyan(`2. Set research model: ${B.yellow(`task-master models --set-research <model_id>`)}`)+`
|
|
1118
1122
|
`+B.cyan(`3. Set fallback model: ${B.yellow(`task-master models --set-fallback <model_id>`)}`)+`
|
|
1119
1123
|
`+B.cyan(`4. Run interactive setup: ${B.yellow(`task-master models --setup`)}`)+`
|
|
1120
|
-
`+B.cyan(`5. Use custom ollama/openrouter models: ${B.yellow(`task-master models --openrouter|ollama --set-main|research|fallback <model_id>`)}`),{padding:1,borderColor:`yellow`,borderStyle:`round`,margin:{top:1}}))}function
|
|
1121
|
-
`;u+=B.gray(` Command: ${c}\n`),u+=B.gray(` Provider: ${r}\n`),u+=B.gray(` Model: ${n}\n`),u+=B.gray(` Tokens: ${o} (Input: ${i}, Output: ${a})\n`);let d=l?`Unknown`:`$${s.toFixed(6)}`;u+=B.gray(` Est. Cost: ${d}`),console.log(W(u,{padding:1,margin:{top:1},borderColor:`blue`,borderStyle:`round`,title:`💡 Telemetry`,titleAlignment:`center`}))}function
|
|
1124
|
+
`+B.cyan(`5. Use custom ollama/openrouter models: ${B.yellow(`task-master models --openrouter|ollama --set-main|research|fallback <model_id>`)}`),{padding:1,borderColor:`yellow`,borderStyle:`round`,margin:{top:1}}))}function Ml(e,t=`cli`){if(t!==`cli`&&t!==`text`||!e||L())return;let{modelUsed:n,providerName:r,inputTokens:i,outputTokens:a,totalTokens:o,totalCost:s,commandName:c,isUnknownCost:l}=e,u=B.bold.blue(`AI Usage Summary:`)+`
|
|
1125
|
+
`;u+=B.gray(` Command: ${c}\n`),u+=B.gray(` Provider: ${r}\n`),u+=B.gray(` Model: ${n}\n`),u+=B.gray(` Tokens: ${o} (Input: ${i}, Output: ${a})\n`);let d=l?`Unknown`:`$${s.toFixed(6)}`;u+=B.gray(` Est. Cost: ${d}`),console.log(W(u,{padding:1,margin:{top:1},borderColor:`blue`,borderStyle:`round`,title:`💡 Telemetry`,titleAlignment:`center`}))}function Nl(e,t,n){if(L()||!e)return;let{highRelevance:r,mediumRelevance:i,recentTasks:a,allRelevantTasks:s}=e,c=B.white.bold(`Context Analysis`)+`
|
|
1122
1126
|
|
|
1123
1127
|
`;c+=B.gray(`Query: `)+B.white(`"${t}"`)+`
|
|
1124
1128
|
`,c+=B.gray(`Context size: `)+B.cyan(`${n.toLocaleString()} characters`)+`
|
|
@@ -1135,27 +1139,27 @@ Other Available Models:`));let t=new K({head:[`Provider`,`Model ID`,`SWE Score`,
|
|
|
1135
1139
|
`);let l=a.filter(e=>!r.some(t=>t.id===e.id)&&!i.some(t=>t.id===e.id));l.length>0&&(c+=B.cyan.bold(`🕒 Recent Tasks (for context):`)+`
|
|
1136
1140
|
`,l.slice(0,2).forEach(e=>{c+=B.cyan(` • Task ${e.id}: ${o(e.title,50)}`)+`
|
|
1137
1141
|
`}),l.length>2&&(c+=B.cyan(` • ... and ${l.length-2} more recent tasks`)+`
|
|
1138
|
-
`)),console.log(W(c,{padding:{top:1,bottom:1,left:2,right:2},margin:{top:1,bottom:0},borderStyle:`round`,borderColor:`blue`,title:B.blue(`🔍 Context Gathering`),titleAlignment:`center`}))}function
|
|
1142
|
+
`)),console.log(W(c,{padding:{top:1,bottom:1,left:2,right:2},margin:{top:1,bottom:0},borderStyle:`round`,borderColor:`blue`,title:B.blue(`🔍 Context Gathering`),titleAlignment:`center`}))}function Pl(e,t,n,r){console.log(B.red(`\n❌ Cannot move tasks from "${t}" to "${n}"`)),console.log(B.yellow(`
|
|
1139
1143
|
Cross-tag dependency conflicts detected:`)),e.length>0&&e.forEach(e=>{console.log(` • ${e.message}`)}),console.log(B.cyan(`
|
|
1140
|
-
Resolution options:`)),console.log(` 1. Move with dependencies: task-master move --from=${r} --from-tag=${t} --to-tag=${n} --with-dependencies`),console.log(` 2. Break dependencies: task-master move --from=${r} --from-tag=${t} --to-tag=${n} --ignore-dependencies`),console.log(` 3. Validate and fix dependencies: task-master validate-dependencies && task-master fix-dependencies`),e.length>0&&console.log(` 4. Move dependencies first: task-master move --from=${e.map(e=>e.dependencyId).join(`,`)} --from-tag=${e[0].dependencyTag} --to-tag=${n}`)}function
|
|
1144
|
+
Resolution options:`)),console.log(` 1. Move with dependencies: task-master move --from=${r} --from-tag=${t} --to-tag=${n} --with-dependencies`),console.log(` 2. Break dependencies: task-master move --from=${r} --from-tag=${t} --to-tag=${n} --ignore-dependencies`),console.log(` 3. Validate and fix dependencies: task-master validate-dependencies && task-master fix-dependencies`),e.length>0&&console.log(` 4. Move dependencies first: task-master move --from=${e.map(e=>e.dependencyId).join(`,`)} --from-tag=${e[0].dependencyTag} --to-tag=${n}`)}function Fl(e){return e===null?`null`:e===void 0?`undefined`:e===``?`(empty)`:Se(e)||`unknown`}function Il(e,t,n){let r=Fl(e),i=e||`unknown`,a=i;if(i.includes(`.`)){let e=i.split(`.`);e.length===2&&e[0]&&e[1]?a=e[0]:(console.log(B.yellow(`\n⚠️ Warning: Unexpected taskId format "${i}". Using as-is for command suggestions.`)),a=i)}console.log(B.red(`\n❌ Cannot move subtask ${r} directly between tags`)),console.log(B.yellow(`
|
|
1141
1145
|
Subtask movement restriction:`)),console.log(` • Subtasks cannot be moved directly between tags`),console.log(` • They must be promoted to full tasks first`),console.log(` • Source tag: "${t}"`),console.log(` • Target tag: "${n}"`),console.log(B.cyan(`
|
|
1142
|
-
Resolution options:`)),console.log(` 1. Promote subtask to full task: task-master remove-subtask --id=${r} --convert`),console.log(` 2. Then move the promoted task: task-master move --from=${a} --from-tag=${t} --to-tag=${n}`),console.log(` 3. Or move the parent task with all subtasks: task-master move --from=${a} --from-tag=${t} --to-tag=${n} --with-dependencies`)}function
|
|
1146
|
+
Resolution options:`)),console.log(` 1. Promote subtask to full task: task-master remove-subtask --id=${r} --convert`),console.log(` 2. Then move the promoted task: task-master move --from=${a} --from-tag=${t} --to-tag=${n}`),console.log(` 3. Or move the parent task with all subtasks: task-master move --from=${a} --from-tag=${t} --to-tag=${n} --with-dependencies`)}function Ll(e,t,n){console.log(B.red(`
|
|
1143
1147
|
❌ Invalid tag combination`)),console.log(B.yellow(`
|
|
1144
1148
|
Error details:`)),console.log(` • Source tag: "${e}"`),console.log(` • Target tag: "${t}"`),console.log(` • Reason: ${n}`),console.log(B.cyan(`
|
|
1145
|
-
Resolution options:`)),console.log(` 1. Use different tags for cross-tag moves`),console.log(` 2. Use within-tag move: task-master move --from=<id> --to=<id> --tag=${e}`),console.log(` 3. Check available tags: task-master tags`)}function
|
|
1146
|
-
Helpful hints:`)),new Set(n).forEach(e=>{console.log(` ${e}`)})}var
|
|
1149
|
+
Resolution options:`)),console.log(` 1. Use different tags for cross-tag moves`),console.log(` 2. Use within-tag move: task-master move --from=<id> --to=<id> --tag=${e}`),console.log(` 3. Check available tags: task-master tags`)}function Rl(e=`general`){let t={"before-move":[`💡 Tip: Run "task-master validate-dependencies" to check for dependency issues before moving tasks`,`💡 Tip: Use "task-master fix-dependencies" to automatically resolve common dependency problems`,`💡 Tip: Consider using --with-dependencies flag to move dependent tasks together`],"after-error":[`🔧 Quick fix: Run "task-master validate-dependencies" to identify specific issues`,`🔧 Quick fix: Use "task-master fix-dependencies" to automatically resolve problems`,`🔧 Quick fix: Check "task-master show <id>" to see task dependencies before moving`],general:[`💡 Use "task-master validate-dependencies" to check for dependency issues`,`💡 Use "task-master fix-dependencies" to automatically resolve problems`,`💡 Use "task-master show <id>" to view task dependencies`,`💡 Use --with-dependencies flag to move dependent tasks together`]},n=t[e]||t.general;console.log(B.cyan(`
|
|
1150
|
+
Helpful hints:`)),new Set(n).forEach(e=>{console.log(` ${e}`)})}var zl=class extends Error{constructor(e,t,n={}){super(t),this.name=`DependencyError`,this.code=e,this.data=n}};const Bl={CANNOT_MOVE_SUBTASK:`CANNOT_MOVE_SUBTASK`,INVALID_TASK_ID:`INVALID_TASK_ID`,INVALID_SOURCE_TAG:`INVALID_SOURCE_TAG`,INVALID_TARGET_TAG:`INVALID_TARGET_TAG`};async function Vl(e,t,n,r={}){z(`info`,`Adding dependency ${n} to task ${t}...`);let i=w(e,r.projectRoot,r.tag);(!i||!i.tasks)&&(z(`error`,`No valid tasks found in tasks.json`),process.exit(1));let a=typeof t==`string`&&t.includes(`.`)?t:parseInt(t,10),o=Se(n);y(i.tasks,o)||(z(`error`,`Dependency target ${o} does not exist in tasks.json`),process.exit(1));let s=null;if(typeof a==`string`&&a.includes(`.`)){let[e,t]=a.split(`.`).map(e=>parseInt(e,10)),n=i.tasks.find(t=>t.id===e);n||(z(`error`,`Parent task ${e} not found.`),process.exit(1)),n.subtasks||(z(`error`,`Parent task ${e} has no subtasks.`),process.exit(1)),s=n.subtasks.find(e=>e.id===t),s||(z(`error`,`Subtask ${a} not found.`),process.exit(1))}else s=i.tasks.find(e=>e.id===a),s||(z(`error`,`Task ${a} not found.`),process.exit(1));if(s.dependencies||=[],s.dependencies.some(e=>String(e)===String(o))){z(`warn`,`Dependency ${o} already exists in task ${a}.`);return}String(a)===String(o)&&(z(`error`,`Task ${a} cannot depend on itself.`),process.exit(1));let c=!1;if(typeof a==`string`&&typeof o==`string`&&a.includes(`.`)&&o.includes(`.`)){let[e]=a.split(`.`),[t]=o.split(`.`);c=a===o,z(`debug`,`Adding dependency between subtasks: ${a} depends on ${o}`),z(`debug`,`Parent IDs: ${e} and ${t}, Self-dependency check: ${c}`)}c&&(z(`error`,`Subtask ${a} cannot depend on itself.`),process.exit(1));let l=[a];Ul(i.tasks,o,l)?(z(`error`,`Cannot add dependency ${o} to task ${a} as it would create a circular dependency.`),process.exit(1)):(s.dependencies.push(o),s.dependencies.sort((e,t)=>{if(typeof e==`number`&&typeof t==`number`)return e-t;if(typeof e==`string`&&typeof t==`string`){let[n,r]=e.split(`.`).map(Number),[i,a]=t.split(`.`).map(Number);return n===i?r-a:n-i}else if(typeof e==`number`)return-1;else return 1}),_(e,i,r.projectRoot,r.tag),z(`success`,`Added dependency ${o} to task ${a}`),L()||console.log(W(B.green(`Successfully added dependency:
|
|
1147
1151
|
|
|
1148
|
-
`)+`Task ${B.bold(a)} now depends on ${B.bold(o)}`,{padding:1,borderColor:`green`,borderStyle:`round`,margin:{top:1}})),z(`info`,`Task files regenerated with updated dependencies.`))}async function
|
|
1152
|
+
`)+`Task ${B.bold(a)} now depends on ${B.bold(o)}`,{padding:1,borderColor:`green`,borderStyle:`round`,margin:{top:1}})),z(`info`,`Task files regenerated with updated dependencies.`))}async function Hl(e,t,n,r={}){z(`info`,`Removing dependency ${n} from task ${t}...`);let i=w(e,r.projectRoot,r.tag);(!i||!i.tasks)&&(z(`error`,`No valid tasks found.`),process.exit(1));let a=typeof t==`string`&&t.includes(`.`)?t:parseInt(t,10),o=Se(n),s=null,c=!1;if(typeof a==`string`&&a.includes(`.`)){let[e,t]=a.split(`.`).map(e=>parseInt(e,10)),n=i.tasks.find(t=>t.id===e);n||(z(`error`,`Parent task ${e} not found.`),process.exit(1)),n.subtasks||(z(`error`,`Parent task ${e} has no subtasks.`),process.exit(1)),s=n.subtasks.find(e=>e.id===t),c=!0,s||(z(`error`,`Subtask ${a} not found.`),process.exit(1))}else s=i.tasks.find(e=>e.id===a),s||(z(`error`,`Task ${a} not found.`),process.exit(1));if(!s.dependencies||s.dependencies.length===0){z(`info`,`Task ${a} has no dependencies, nothing to remove.`);return}let l=String(o),u=s.dependencies.findIndex(e=>{if(String(e)===l)return!0;if(typeof e==`number`&&e<100&&c){let[t]=a.split(`.`);if(`${t}.${e}`===l)return!0}return!1});if(u===-1){z(`info`,`Task ${a} does not depend on ${o}, no changes made.`);return}s.dependencies.splice(u,1),_(e,i,r.projectRoot,r.tag),z(`success`,`Removed dependency: Task ${a} no longer depends on ${o}`),L()||console.log(W(B.green(`Successfully removed dependency:
|
|
1149
1153
|
|
|
1150
|
-
`)+`Task ${B.bold(a)} no longer depends on ${B.bold(o)}`,{padding:1,borderColor:`green`,borderStyle:`round`,margin:{top:1}}))}function
|
|
1154
|
+
`)+`Task ${B.bold(a)} no longer depends on ${B.bold(o)}`,{padding:1,borderColor:`green`,borderStyle:`round`,margin:{top:1}}))}function Ul(e,t,n=[]){let r=String(t);if(n.some(e=>String(e)===r))return!0;let i=null,a=null;if(r.includes(`.`)){let[t,n]=r.split(`.`).map(Number),o=e.find(e=>e.id===t);a=t,o&&o.subtasks&&(i=o.subtasks.find(e=>e.id===n))}else{let t=parseInt(r,10);i=e.find(e=>e.id===t||String(e.id)===r)}if(!i||!i.dependencies||i.dependencies.length===0)return!1;let o=[...n,r];return i.dependencies.some(t=>{let n=String(t);return typeof t==`number`&&a!==null&&(n=`${a}.${t}`),Ul(e,n,o)})}function Wl(e){let t=[];return e.forEach(n=>{n.dependencies&&(n.dependencies.forEach(r=>{if(String(r)===String(n.id)){t.push({type:`self`,taskId:n.id,message:`Task ${n.id} depends on itself`});return}y(e,r)||t.push({type:`missing`,taskId:n.id,dependencyId:r,message:`Task ${n.id} depends on non-existent task ${r}`})}),Ul(e,n.id)&&t.push({type:`circular`,taskId:n.id,message:`Task ${n.id} is part of a circular dependency chain`}),n.subtasks&&n.subtasks.length>0&&n.subtasks.forEach(r=>{if(!r.dependencies)return;let i=`${n.id}.${r.id}`;r.dependencies.forEach(n=>{if(String(n)===String(i)||typeof n==`number`&&n===r.id){t.push({type:`self`,taskId:i,message:`Subtask ${i} depends on itself`});return}y(e,n)||t.push({type:`missing`,taskId:i,dependencyId:n,message:`Subtask ${i} depends on non-existent task/subtask ${n}`})}),Ul(e,i)&&t.push({type:`circular`,taskId:i,message:`Subtask ${i} is part of a circular dependency chain`})}))}),{valid:t.length===0,issues:t}}async function Gl(e,t={}){let{context:n={}}=t;z(`info`,`Checking for invalid dependencies in task files...`);let r=w(e,n.projectRoot,n.tag);(!r||!r.tasks)&&(z(`error`,`No valid tasks found in tasks.json`),process.exit(1));let i=r.tasks.length,a=0;r.tasks.forEach(e=>{e.subtasks&&Array.isArray(e.subtasks)&&(a+=e.subtasks.length)}),z(`info`,`Analyzing dependencies for ${i} tasks and ${a} subtasks...`);try{let e=Wl(r.tasks);e.valid?(z(`success`,`No invalid dependencies found - all dependencies are valid`),L()||console.log(W(B.green(`All Dependencies Are Valid
|
|
1151
1155
|
|
|
1152
|
-
`)+`${B.cyan(`Tasks checked:`)} ${i}\n${B.cyan(`Subtasks checked:`)} ${a}\n${B.cyan(`Total dependencies verified:`)} ${
|
|
1156
|
+
`)+`${B.cyan(`Tasks checked:`)} ${i}\n${B.cyan(`Subtasks checked:`)} ${a}\n${B.cyan(`Total dependencies verified:`)} ${Kl(r.tasks)}`,{padding:1,borderColor:`green`,borderStyle:`round`,margin:{top:1,bottom:1}}))):(z(`error`,`Dependency validation failed. Found ${e.issues.length} issue(s):`),e.issues.forEach(e=>{let t=` [${e.type.toUpperCase()}] Task ${e.taskId}: ${e.message}`;e.dependencyId&&(t+=` (Dependency: ${e.dependencyId})`),z(`error`,t)}),L()||console.log(W(B.red(`Dependency Validation FAILED
|
|
1153
1157
|
|
|
1154
|
-
`)+`${B.cyan(`Tasks checked:`)} ${i}\n${B.cyan(`Subtasks checked:`)} ${a}\n${B.red(`Issues found:`)} ${e.issues.length}`,{padding:1,borderColor:`red`,borderStyle:`round`,margin:{top:1,bottom:1}})))}catch(e){z(`error`,`Error validating dependencies:`,e),process.exit(1)}}function
|
|
1158
|
+
`)+`${B.cyan(`Tasks checked:`)} ${i}\n${B.cyan(`Subtasks checked:`)} ${a}\n${B.red(`Issues found:`)} ${e.issues.length}`,{padding:1,borderColor:`red`,borderStyle:`round`,margin:{top:1,bottom:1}})))}catch(e){z(`error`,`Error validating dependencies:`,e),process.exit(1)}}function Kl(e){let t=0;return e.forEach(e=>{e.dependencies&&Array.isArray(e.dependencies)&&(t+=e.dependencies.length),e.subtasks&&Array.isArray(e.subtasks)&&e.subtasks.forEach(e=>{e.dependencies&&Array.isArray(e.dependencies)&&(t+=e.dependencies.length)})}),t}async function ql(e,t={}){let{context:n={}}=t;z(`info`,`Checking for and fixing invalid dependencies in tasks.json...`);try{let t=w(e,n.projectRoot,n.tag);(!t||!t.tasks)&&(z(`error`,`No valid tasks found in tasks.json`),process.exit(1));let r=JSON.parse(JSON.stringify(t)),i={nonExistentDependenciesRemoved:0,selfDependenciesRemoved:0,duplicateDependenciesRemoved:0,circularDependenciesFixed:0,tasksFixed:0,subtasksFixed:0};t.tasks.forEach(e=>{if(e.dependencies&&Array.isArray(e.dependencies)){let t=new Set,n=e.dependencies.length;e.dependencies=e.dependencies.filter(n=>{let r=String(n);return t.has(r)?(z(`info`,`Removing duplicate dependency from task ${e.id}: ${n}`),i.duplicateDependenciesRemoved++,!1):(t.add(r),!0)}),e.dependencies.length<n&&i.tasksFixed++}e.subtasks&&Array.isArray(e.subtasks)&&e.subtasks.forEach(t=>{if(t.dependencies&&Array.isArray(t.dependencies)){let n=new Set,r=t.dependencies.length;t.dependencies=t.dependencies.filter(r=>{let a=String(r);return typeof r==`number`&&r<100&&(a=`${e.id}.${r}`),n.has(a)?(z(`info`,`Removing duplicate dependency from subtask ${e.id}.${t.id}: ${r}`),i.duplicateDependenciesRemoved++,!1):(n.add(a),!0)}),t.dependencies.length<r&&i.subtasksFixed++}})});let a=new Set(t.tasks.map(e=>e.id)),o=new Set;t.tasks.forEach(e=>{e.subtasks&&Array.isArray(e.subtasks)&&e.subtasks.forEach(t=>{o.add(`${e.id}.${t.id}`)})}),t.tasks.forEach(e=>{if(e.dependencies&&Array.isArray(e.dependencies)){let t=e.dependencies.length;e.dependencies=e.dependencies.filter(t=>{if(typeof t==`string`&&t.includes(`.`))return o.has(t)?!0:(z(`info`,`Removing invalid subtask dependency from task ${e.id}: ${t} (subtask does not exist)`),i.nonExistentDependenciesRemoved++,!1);{let n=typeof t==`string`?parseInt(t,10):t;return a.has(n)?!0:(z(`info`,`Removing invalid task dependency from task ${e.id}: ${t} (task does not exist)`),i.nonExistentDependenciesRemoved++,!1)}}),e.dependencies.length<t&&i.tasksFixed++}e.subtasks&&Array.isArray(e.subtasks)&&e.subtasks.forEach(t=>{if(t.dependencies&&Array.isArray(t.dependencies)){let n=t.dependencies.length,r=`${e.id}.${t.id}`;t.dependencies.some(e=>typeof e==`string`&&e.includes(`.`)?e===r:typeof e==`number`&&e<100?e===t.id:!1)&&(t.dependencies=t.dependencies.filter(t=>(typeof t==`number`&&t<100?`${e.id}.${t}`:String(t))===r?(z(`info`,`Removing self-dependency from subtask ${r}`),i.selfDependenciesRemoved++,!1):!0)),t.dependencies=t.dependencies.filter(t=>{if(typeof t==`string`&&t.includes(`.`))return o.has(t)?!0:(z(`info`,`Removing invalid subtask dependency from subtask ${r}: ${t} (subtask does not exist)`),i.nonExistentDependenciesRemoved++,!1);let n=typeof t==`number`?t:parseInt(t,10);if(n<100){let t=`${e.id}.${n}`;return o.has(t)?!0:(z(`info`,`Removing invalid subtask dependency from subtask ${r}: ${n}`),i.nonExistentDependenciesRemoved++,!1)}return a.has(n)?!0:(z(`info`,`Removing invalid task dependency from subtask ${r}: ${n}`),i.nonExistentDependenciesRemoved++,!1)}),t.dependencies.length<n&&i.subtasksFixed++}})}),z(`info`,`Checking for circular dependencies...`);let s=new Map;t.tasks.forEach(e=>{e.subtasks&&Array.isArray(e.subtasks)&&e.subtasks.forEach(t=>{let n=`${e.id}.${t.id}`;if(t.dependencies&&Array.isArray(t.dependencies)){let r=t.dependencies.map(t=>typeof t==`string`&&t.includes(`.`)?t:typeof t==`number`&&t<100?`${e.id}.${t}`:String(t));s.set(n,r)}else s.set(n,[])})});for(let[e,n]of s.entries()){let n=ye(e,s,new Set,new Set);if(n.length>0){let[r,a]=e.split(`.`).map(e=>Number(e)),o=t.tasks.find(e=>e.id===r);if(o&&o.subtasks){let t=o.subtasks.find(e=>e.id===a);if(t&&t.dependencies){let a=t.dependencies.length,o=n.map(e=>{if(e.includes(`.`)){let[t,n]=e.split(`.`).map(e=>Number(e));return t===r?n:e}return Number(e)});t.dependencies=t.dependencies.filter(t=>{let n=typeof t==`number`&&t<100?`${r}.${t}`:String(t);return o.includes(t)||o.includes(n)?(z(`info`,`Breaking circular dependency: Removing ${n} from subtask ${e}`),i.circularDependenciesFixed++,!1):!0}),t.dependencies.length<a&&i.subtasksFixed++}}}}JSON.stringify(t)===JSON.stringify(r)?z(`info`,`No changes needed to fix dependencies`):(_(e,t,n.projectRoot,n.tag),z(`success`,`Fixed dependency issues in tasks.json`),z(`info`,`Regenerating task files to reflect dependency changes...`));let c=i.nonExistentDependenciesRemoved+i.selfDependenciesRemoved+i.duplicateDependenciesRemoved+i.circularDependenciesFixed;L()||(c>0?(z(`success`,`Fixed ${c} dependency issues in total!`),console.log(W(B.green(`Dependency Fixes Summary:
|
|
1155
1159
|
|
|
1156
1160
|
`)+`${B.cyan(`Invalid dependencies removed:`)} ${i.nonExistentDependenciesRemoved}\n${B.cyan(`Self-dependencies removed:`)} ${i.selfDependenciesRemoved}\n${B.cyan(`Duplicate dependencies removed:`)} ${i.duplicateDependenciesRemoved}\n${B.cyan(`Circular dependencies fixed:`)} ${i.circularDependenciesFixed}\n\n${B.cyan(`Tasks fixed:`)} ${i.tasksFixed}\n${B.cyan(`Subtasks fixed:`)} ${i.subtasksFixed}\n`,{padding:1,borderColor:`green`,borderStyle:`round`,margin:{top:1,bottom:1}}))):(z(`success`,`No dependency issues found - all dependencies are valid`),console.log(W(B.green(`All Dependencies Are Valid
|
|
1157
1161
|
|
|
1158
|
-
`)+`${B.cyan(`Tasks checked:`)} ${t.tasks.length}\n${B.cyan(`Total dependencies verified:`)} ${
|
|
1162
|
+
`)+`${B.cyan(`Tasks checked:`)} ${t.tasks.length}\n${B.cyan(`Total dependencies verified:`)} ${Kl(t.tasks)}`,{padding:1,borderColor:`green`,borderStyle:`round`,margin:{top:1,bottom:1}}))))}catch(e){z(`error`,`Error in fix-dependencies command:`,e),process.exit(1)}}function Jl(e,t,n,r=!1){let i=parseInt(e,10),a=n.find(e=>e.id===i);if(a&&a.subtasks&&Array.isArray(a.subtasks)){let n=a.subtasks.find(e=>r?String(e.id)===String(t):e.id===t);if(n)return{...n,id:`${e}.${n.id}`}}return null}function Yl(e,t,n){if(!e)return null;let r=String(e),i=null;if(i=n.find(e=>String(e.id)===r),!i&&r.includes(`.`)){let[e,t]=r.split(`.`);i=Jl(e,t,n,!0)}if(!i&&!isNaN(e)){let r=parseInt(e,10);if(t&&typeof t==`string`&&t.includes(`.`)){let[e]=t.split(`.`);i=Jl(e,r,n,!1)}}return i}function Xl(e,t,n){let r=[];return!Array.isArray(e.dependencies)||e.dependencies.length===0||e.dependencies.filter(e=>e!=null).forEach(i=>{let a=Yl(i,e.id,n);a&&a.tag!==t&&r.push({taskId:e.id,dependencyId:i,dependencyTag:a.tag,message:`Task ${e.id} depends on ${i} (in ${a.tag})`})}),r}function Zl(e,t,n,r){if(!Array.isArray(e))throw Error(`Source tasks parameter must be an array`);if(!t||typeof t!=`string`)throw Error(`Source tag must be a valid string`);if(!n||typeof n!=`string`)throw Error(`Target tag must be a valid string`);if(!Array.isArray(r))throw Error(`All tasks parameter must be an array`);let i=[];return e.forEach(e=>{if(!e||typeof e!=`object`||!Array.isArray(e.dependencies)||e.dependencies.length===0)return;let t=Xl(e,n,r);i.push(...t)}),i}function Ql(e,t,n){if(!e||typeof e!=`string`)throw new zl(Bl.INVALID_TASK_ID,`Task ID must be a valid string`);if(!t||typeof t!=`string`)throw new zl(Bl.INVALID_SOURCE_TAG,`Source tag must be a valid string`);if(!n||typeof n!=`string`)throw new zl(Bl.INVALID_TARGET_TAG,`Target tag must be a valid string`);if(e.includes(`.`))throw new zl(Bl.CANNOT_MOVE_SUBTASK,`Cannot move subtask ${e} directly between tags.
|
|
1159
1163
|
|
|
1160
1164
|
First promote it to a full task using:
|
|
1161
|
-
task-master remove-subtask --id=${e} --convert`,{taskId:e,sourceTag:t,targetTag:n})}export{
|
|
1165
|
+
task-master remove-subtask --id=${e} --convert`,{taskId:e,sourceTag:t,targetTag:n})}export{sa as $,Lc as A,yo as B,ul as C,Jn as Ct,nl as D,St as Dt,il as E,xt as Et,Go as F,ho as G,_o as H,qo as I,no as J,po as K,To as L,Pc as M,Mc as N,tl as O,Ac as P,Ua as Q,So as R,fl as S,Qn as St,ol as T,kt as Tt,go as U,xo as V,vo as W,Za as X,eo as Y,Ya as Z,ml as _,Br as _t,El as a,Fi as at,$ as b,Or as bt,jl as c,Yr as ct,hl as d,ei as dt,aa as et,Rl as f,ni as ft,Il as g,Jr as gt,Al as h,$r as ht,Gl as i,Ni as it,Ic as j,Jc as k,Tl as l,ii as lt,Ll as m,ri as mt,ql as n,Ii as nt,Dl as o,Ti as ot,Cl as p,Qr as pt,io as q,Hl as r,Pi as rt,gl as s,ti as st,Vl as t,Qi as tt,Pl as u,Xr as ut,xl as v,zr as vt,cl as w,X as wt,pl as x,vr as xt,_l as y,kr as yt,bo as z};
|