taskgraph-ai 0.54.13 → 0.54.22

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,125 @@
1
+ import{_ as e,c as t,g as n,s as r,u as i}from"./src-BQZsjzA5.js";import{$ as a,Ct as o,Et as s,G as c,I as l,K as u,O as d,T as f,Tt as p,_t as m,b as h,g,it as _,kt as v,pt as y,s as ee,t as te,vt as b,wt as x}from"./config-manager-DTkRerDn.js";import{C as ne,S as re,T as ie,_ as ae,a as oe,b as S,c as se,d as C,f as ce,g as le,h as ue,i as de,l as fe,n as pe,o as w,p as me,r as he,s as ge,t as _e,u as ve,v as ye,w as be,x as xe,y as Se}from"./task-manager-CHSNsnL1.js";import{C as T,D as E,E as Ce,H as D,M as we,O as Te,S as Ee,T as De,V as O,_ as Oe,a as ke,b as Ae,g as je,i as Me,k as Ne,l as Pe,m as Fe,n as Ie,o as Le,r as Re,s as ze,t as Be,tt as k,u as Ve,v as He,x as A,y as j}from"./src-CpPJ2WS1.js";import{D as Ue,E as We,S as Ge,T as M,b as Ke,c as qe,f as Je,l as Ye,m as N,o as Xe,p as Ze,s as Qe,v as P,w as F}from"./research-DbaGD34z.js";import{t as $e}from"./response-language-CbtAaYK6.js";import{n as I,r as et,t as tt}from"./init-DyCHcgGz.js";import L from"chalk";import nt from"node:path";import R from"node:fs";import z from"path";import rt from"node:os";import B from"fs";import{Command as it,Option as V}from"commander";import H from"boxen";import at from"process";import U from"https";import W from"inquirer";function ot(){let e=at.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 G(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 st(e){return new Promise(t=>{let n={hostname:`raw.githubusercontent.com`,path:`/${Ae}/main/CHANGELOG.md`,method:`GET`,headers:{"User-Agent":`${j}/${e}`}},r=U.request(n,n=>{let r=``;n.on(`data`,e=>{r+=e}),n.on(`end`,()=>{try{if(n.statusCode!==200){t([]);return}t(ct(r,e))}catch{t([])}})});r.on(`error`,()=>{t([])}),r.setTimeout(3e3,()=>{r.destroy(),t([])}),r.end()})}function ct(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(`
2
+ ## `,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 K=()=>nt.join(rt.tmpdir(),`taskgraph-update-cache.json`);function lt(){try{let e=K();if(!R.existsSync(e))return null;let t=JSON.parse(R.readFileSync(e,`utf-8`));return Date.now()-t.timestamp>36e5?null:t}catch{return null}}function ut(e,t){try{R.writeFileSync(K(),JSON.stringify({timestamp:Date.now(),latestVersion:e,highlights:t},null,2))}catch{}}function dt(e){return new Promise(t=>{let n=U.request({hostname:`registry.npmjs.org`,path:`/${j}`,method:`GET`,headers:{Accept:`application/vnd.npm.install-v1+json`,"User-Agent":`${j}/${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 q(e,t,n){return{currentVersion:e,latestVersion:t,needsUpdate:G(e,t)<0,highlights:n}}async function ft(e){let t=e||ot(),n=lt();if(n)return q(t,n.latestVersion,n.highlights);let r=await dt(t);if(!r)return q(t,t);let i=G(t,r)<0?await st(r):void 0;return ut(r,i),q(t,r,i)}function pt(e){return`# ${e}
3
+
4
+ This project is managed using TaskGraph.
5
+
6
+ `}function mt(e){let t=z.basename(e).toLowerCase().replace(/[^a-z0-9]/g,`-`).replace(/-+/g,`-`).replace(/^-|-$/g,``);return`https://github.com/stephennmiller/taskgraph-ai?${new URLSearchParams({utm_source:`github-readme`,utm_medium:`readme-export`,utm_campaign:t||`task-sync`,utm_content:`task-export-link`}).toString()}`}function ht(e){let{timestamp:t,withSubtasks:n,status:r,projectRoot:i}=e,a=r?`Status filter: ${r}`:`Status filter: none`;return`<!-- TASKGRAPH_EXPORT_START -->\n> ${`🎯 **TaskGraph Export** - ${t}\n📋 Export: ${n?`with subtasks`:`without subtasks`} • ${a}\n🔗 Powered by [TaskGraph](${mt(i)})`.split(`
7
+ `).join(`
8
+ > `)}\n\n`}function gt(){return`
9
+ > 📋 **End of TaskGraph Export** - Tasks are synced from your project using the \`sync-readme\` command.
10
+ <!-- TASKGRAPH_EXPORT_END -->
11
+ `}async function _t(e=null,t={}){try{let n=e||c()||`.`,{withSubtasks:r=!1,status:i,tasksPath:a,tag:o}=t,s=await me(a||z.join(n,`.taskgraph`,`tasks`,`tasks.json`),i,null,r,`markdown-readme`,{projectRoot:e,tag:o});if(!s)return console.log(L.red(`❌ Failed to generate task output`)),!1;let l=(/* @__PURE__ */ new Date()).toISOString().replace(`T`,` `).substring(0,19)+` UTC`,u=g(n),d=ht({timestamp:l,withSubtasks:r,status:i,projectRoot:n}),f=gt(),p=d+s+f,m=z.join(n,`README.md`),h=``;try{h=B.readFileSync(m,`utf8`)}catch(e){if(e.code===`ENOENT`)h=pt(u);else throw e}let _,v=h.indexOf(`<!-- TASKGRAPH_EXPORT_START -->`),y=h.indexOf(`<!-- TASKGRAPH_EXPORT_END -->`);if(v!==-1&&y!==-1){let e=h.substring(0,v),t=h.substring(y+29);_=e+p+t}else _=h+`
12
+ `+p;return B.writeFileSync(m,_,`utf8`),console.log(L.green(`✅ Successfully synced tasks to README.md`)),console.log(L.cyan(`📋 Export details: ${r?`with`:`without`} subtasks${i?`, status: ${i}`:``}`)),console.log(L.dim(`📍 Location: ${m}`)),!0}catch(e){return console.log(L.red(`❌ Failed to sync tasks to README:`),e.message),a(`error`,`README sync error: ${e.message}`),!1}}var J=class{#e;#t;constructor(e,t){this.#e=Object.freeze({...e}),this.#t=t}getProjectRoot(){return this.#e.projectRoot}getTaskGraphDir(){return this.#e.taskGraphDir}getTasksPath(){return this.#e.tasksPath}getPrdPath(){return this.#e.prdPath}getComplexityReportPath(){if(this.#e.complexityReportPath)return this.#e.complexityReportPath;let e=this.getCurrentTag()===`master`?b:b.replace(`.json`,`_${this.getCurrentTag()}.json`);return z.join(this.#e.projectRoot,e)}getConfigPath(){return this.#e.configPath}getStatePath(){return this.#e.statePath}getAllPaths(){return this.#e}getCurrentTag(){if(this.#t)return this.#t;try{if(B.existsSync(this.#e.statePath)){let e=B.readFileSync(this.#e.statePath,`utf8`),t=JSON.parse(e);if(t&&t.currentTag)return t.currentTag}}catch{}try{if(B.existsSync(this.#e.configPath)){let e=B.readFileSync(this.#e.configPath,`utf8`),t=JSON.parse(e);if(t&&t.global&&t.global.defaultTag)return t.global.defaultTag}}catch{}return`master`}};function Y(e={}){let t=(e,t,n=[],r=null,i=!1)=>{if(typeof t==`string`){let n=z.isAbsolute(t)?t:z.resolve(r||process.cwd(),t);if(i){let t=z.dirname(n);if(!B.existsSync(t))try{B.mkdirSync(t,{recursive:!0})}catch(n){throw Error(`Could not create directory for ${e}: ${t}. Error: ${n.message}`)}}else if(!B.existsSync(n))throw Error(`${e} override path does not exist: ${n}`);return n}if(t===!0){for(let e of n){let t=z.isAbsolute(e)?e:z.join(r||process.cwd(),e);if(B.existsSync(t))return t}throw Error(`Required ${e} not found. Searched: ${n.join(`, `)}`)}for(let e of n){let t=z.isAbsolute(e)?e:z.join(r||process.cwd(),e);if(B.existsSync(t))return t}return null},n={};if(e.projectRoot){let t=z.resolve(e.projectRoot);if(!B.existsSync(t))throw Error(`Project root override path does not exist: ${t}`);if(!B.existsSync(z.join(t,`.taskgraph`)))throw Error(`Project root override is not a valid taskgraph project: ${t}`);n.projectRoot=t}else n.projectRoot=l();return n.taskGraphDir=`taskGraphDir`in e?t(`taskgraph directory`,e.taskGraphDir,[x],n.projectRoot):t(`taskgraph directory`,!1,[x],n.projectRoot),n.configPath=z.join(n.projectRoot,o),n.statePath=z.join(n.taskGraphDir||z.join(n.projectRoot,`.taskgraph`),`state.json`),n.tasksPath=z.join(n.projectRoot,v),`configPath`in e&&(n.configPath=t(`config file`,e.configPath,[o],n.projectRoot)),`statePath`in e&&(n.statePath=t(`state file`,e.statePath,[`state.json`],n.taskGraphDir)),`tasksPath`in e&&(n.tasksPath=t(`tasks file`,e.tasksPath,[v],n.projectRoot)),`prdPath`in e&&(n.prdPath=t(`PRD file`,e.prdPath,[z.join(p,`PRD.md`),z.join(p,`prd.md`),z.join(p,`PRD.txt`),z.join(p,`prd.txt`)],n.projectRoot)),`complexityReportPath`in e&&(n.complexityReportPath=t(`complexity report`,e.complexityReportPath,[z.join(s,`task-complexity-report.json`),z.join(s,`complexity-report.json`)],n.projectRoot,!0)),new J(n,e.tag)}function X(e){let t=e?.message??``;if(/overloaded|rate limit|\b(429|529)\b/i.test(t))return`Claude is busy. Wait a minute and try again`;if(/empty stream response|did not return a valid/i.test(t))return`Try again, or reword the prompt`}async function Z(e){try{return await e()}catch(e){if(!(e instanceof xe))throw e;T(e.message,e.data?.hint),process.exit(1)}}function vt(e){e.on(`option:unknown`,function(e){let t=this._name||`unknown`;T(`Unknown option '${e}'`,`Run \`taskgraph ${t} --help\` to see its options`),process.exit(1)}),e.command(`help`).description(`Show help information`).action(()=>{e.help()}),e.configureHelp({helpWidth:120,sortSubcommands:!1}),e.command(`parse-prd`).description(`Parse a PRD file and generate tasks`).argument(`[file]`,`Path to the PRD file`).option(`-i, --input <file>`,`Path to the PRD file (alternative to positional argument)`).option(`-o, --output <file>`,`Output file path`).option(`-n, --num-tasks <number>`,`Number of tasks to generate`,ee()).option(`-f, --force`,`Skip confirmation when overwriting existing tasks`).option(`--append`,`Append new tasks to existing tasks.json instead of overwriting`).option(`-r, --research`,`Use Claude Code web research for research-backed task generation, providing more comprehensive and accurate task breakdown`).option(`--tag <tag>`,`Specify tag context for task operations`).action(async(e,t)=>{let n=t.input||e;n&&!B.existsSync(z.resolve(n))&&(T(`${n} not found`,`Check the spelling; paths are relative to this folder`),process.exit(1));let r;try{let e={prdPath:n||!0,tag:t.tag};t.output&&(e.tasksPath=t.output),r=Y(e)}catch(e){A(e,{hint:n?void 0:"Try `taskgraph parse-prd prd.md`"}),process.exit(1)}let i=parseInt(t.numTasks,10),o=t.force||!1,s=t.append||!1,c=t.research||!1,l=o,u=s,d=r.getCurrentTag();await M(d,{tasksPath:r.getTasksPath()});async function f(){let e=!1,t=r.getTasksPath();if(B.existsSync(t))try{let n=B.readFileSync(t,`utf8`),r=JSON.parse(n);r[d]&&Array.isArray(r[d].tasks)&&r[d].tasks.length>0&&(e=!0)}catch{e=!1}if(e&&!l&&!u){if(!await Je(t))return a(`info`,`Operation cancelled.`),!1;l=!0}return!0}try{if(!await f())return;let e=r.getTasksPath()||z.join(r.getProjectRoot(),`.taskgraph/tasks/tasks.json`);await ve(r.getPrdPath(),e,i,{append:u,force:l,research:c,projectRoot:r.getProjectRoot(),tag:d})}catch(e){console.error(L.red(`Error parsing PRD: ${e.message}`)),process.exit(1)}}),e.command(`update`).description(`Update multiple tasks with ID >= "from" based on new information or implementation changes`).option(`-f, --file <file>`,`Path to the tasks file`,v).option(`--from <id>`,`Task ID to start updating from (tasks with ID >= this value will be updated)`,`1`).option(`-p, --prompt <text>`,`Prompt explaining the changes or new context (required)`).option(`-r, --research`,`Use Claude Code web research for research-backed task updates`).option(`--tag <tag>`,`Specify tag context for task operations`).action(async e=>{let t=Y({tasksPath:e.file||!0,tag:e.tag}),n=parseInt(e.from,10),r=e.prompt,i=e.research||!1;t.getTasksPath();let a=t.getCurrentTag();await M(a,{tasksPath:t.getTasksPath()}),(process.argv.includes(`--id`)||process.argv.some(e=>e.startsWith(`--id=`)))&&(console.error(L.red(`Error: The update command uses --from=<id>, not --id=<id>`)),console.log(L.yellow(`
13
+ To update multiple tasks:`)),console.log(` taskgraph update --from=${n} --prompt="Your prompt here"`),console.log(L.yellow(`
14
+ To update a single specific task, use the update-task command instead:`)),console.log(` taskgraph update-task --id=<id> --prompt="Your prompt here"`),process.exit(1)),r||(console.error(L.red(`Error: --prompt parameter is required. Please provide information about the changes.`)),process.exit(1)),await _e(t.getTasksPath(),n,r,i,{projectRoot:t.getProjectRoot(),tag:a})}),e.command(`update-task`).description(`Update a single specific task by ID with new information`).argument(`[id]`,`Task ID to update (e.g., 1, 1.1, TAS-123)`).argument(`[prompt...]`,`Update prompt - multiple words, no quotes needed`).option(`-f, --file <file>`,`Path to the tasks file`,v).option(`-i, --id <id>`,`Task ID to update (fallback if not using positional)`).option(`-p, --prompt <text>`,`Prompt (fallback if not using positional)`).option(`-r, --research`,`Use Claude Code web research for research-backed task updates`).option(`--append`,`Append timestamped information to task details instead of full update`).option(`--tag <tag>`,`Specify tag context for task operations`).action(async(e,t,n)=>{try{let r=Y({tasksPath:n.file||!0,tag:n.tag}),i=r.getTasksPath(),a=r.getCurrentTag();await M(a,{tasksPath:r.getTasksPath()});let o=e||n.id,s=t.length>0?t.join(` `):n.prompt;o||(T(`Missing task ID`,'Try `taskgraph update-task --id=3 --prompt="what changed"`'),process.exit(1)),/^\d+$/.test(o)||(T(`"${o}" isn't a task ID`,o.includes(`.`)?"Update subtasks with `taskgraph update-subtask`":"Use a number like `3`"),process.exit(1)),s||(T(`Missing prompt`,`Try \`taskgraph update-task --id=${o} --prompt="what changed"\``),process.exit(1));let c=n.research||!1;B.existsSync(i)||(console.error(L.red(`Error: Tasks file not found at path: ${i}`)),console.log(i===`.taskgraph/tasks/tasks.json`?L.yellow(`Hint: Run taskgraph init or taskgraph parse-prd to create tasks.json first`):L.yellow(`Hint: Check if the file path is correct: ${i}`)),process.exit(1));let l=n.append||!1;await pe(r.getTasksPath(),o,s,c,{projectRoot:r.getProjectRoot(),tag:a},`text`,l)||(T(`Task ${o} is done, so it can't be updated`,`Run \`taskgraph set-status --id=${o} --status=pending\` first`),process.exitCode=1)}catch(e){A(e,{hint:X(e)})}}),e.command(`update-subtask`).description(`Update a subtask by appending additional timestamped information`).option(`-f, --file <file>`,`Path to the tasks file`,v).option(`-i, --id <id>`,`Subtask ID to update (required)`).option(`-p, --prompt <text>`,`Prompt explaining what information to add (required)`).option(`-r, --research`,`Use Claude Code web research for research-backed updates`).option(`--tag <tag>`,`Specify tag context for task operations`).action(async e=>{try{let t=Y({tasksPath:e.file||!0,tag:e.tag}),n=t.getTasksPath(),r=t.getCurrentTag();await M(r,{tasksPath:t.getTasksPath()}),e.id||(console.error(L.red(`Error: --id parameter is required`)),console.log(L.yellow(`Usage example: taskgraph update-subtask --id=5.2 --prompt="Add more details about the API endpoint"`)),process.exit(1));let i=e.id;e.prompt||(console.error(L.red(`Error: --prompt parameter is required. Please provide information to add to the subtask.`)),console.log(L.yellow(`Usage example: taskgraph update-subtask --id=5.2 --prompt="Add more details about the API endpoint"`)),process.exit(1));let a=e.prompt,o=e.research||!1;B.existsSync(n)||(console.error(L.red(`Error: Tasks file not found at path: ${n}`)),console.log(n===`.taskgraph/tasks/tasks.json`?L.yellow(`Hint: Run taskgraph init or taskgraph parse-prd to create tasks.json first`):L.yellow(`Hint: Check if the file path is correct: ${n}`)),process.exit(1)),await he(t.getTasksPath(),i,a,o,{projectRoot:t.getProjectRoot(),tag:r})}catch(e){A(e,{hint:X(e)})}}),e.command(`scope-up`).description(`Increase task complexity with AI assistance`).option(`-f, --file <file>`,`Path to the tasks file`,v).option(`-i, --id <ids>`,`Comma-separated task/subtask IDs to scope up (required)`).option(`-s, --strength <level>`,`Complexity increase strength: light, regular, heavy`,`regular`).option(`-p, --prompt <text>`,`Custom instructions for targeted scope adjustments`).option(`-r, --research`,`Use research AI for more informed adjustments`).option(`--tag <tag>`,`Specify tag context for task operations`).action(async e=>{try{let t=Y({tasksPath:e.file||!0,tag:e.tag}),n=t.getTasksPath(),r=t.getCurrentTag();await M(r,{tasksPath:t.getTasksPath()}),e.id||(console.error(L.red(`Error: --id parameter is required`)),console.log(L.yellow(`Usage example: taskgraph scope-up --id=1,2,3 --strength=regular`)),process.exit(1));let i=e.id.split(`,`).map(e=>{let t=parseInt(e.trim(),10);return(Number.isNaN(t)||t<=0)&&(console.error(L.red(`Error: Invalid task ID: ${e.trim()}`)),process.exit(1)),t});w(e.strength)||(console.error(L.red(`Error: Invalid strength level: ${e.strength}. Must be one of: light, regular, heavy`)),process.exit(1)),B.existsSync(n)||(console.error(L.red(`Error: Tasks file not found at path: ${n}`)),process.exit(1)),console.log(m.brand(`Scoping up ${i.length===1?`task`:`tasks`} ${i.join(`, `)}`));let a={projectRoot:t.getProjectRoot(),tag:r,commandName:`scope-up`,outputType:`cli`,research:e.research||!1},o=await oe(n,i,e.strength,e.prompt||null,a,`text`);console.log(L.green(`✓ Scoped up ${o.updatedTasks.length} ${o.updatedTasks.length===1?`task`:`tasks`}`))}catch(e){A(e,{hint:X(e)})}}),e.command(`scope-down`).description(`Decrease task complexity with AI assistance`).option(`-f, --file <file>`,`Path to the tasks file`,v).option(`-i, --id <ids>`,`Comma-separated task/subtask IDs to scope down (required)`).option(`-s, --strength <level>`,`Complexity decrease strength: light, regular, heavy`,`regular`).option(`-p, --prompt <text>`,`Custom instructions for targeted scope adjustments`).option(`-r, --research`,`Use research AI for more informed adjustments`).option(`--tag <tag>`,`Specify tag context for task operations`).action(async e=>{try{let t=Y({tasksPath:e.file||!0,tag:e.tag}),n=t.getTasksPath(),r=t.getCurrentTag();await M(r,{tasksPath:t.getTasksPath()}),e.id||(console.error(L.red(`Error: --id parameter is required`)),console.log(L.yellow(`Usage example: taskgraph scope-down --id=1,2,3 --strength=regular`)),process.exit(1));let i=e.id.split(`,`).map(e=>{let t=parseInt(e.trim(),10);return(Number.isNaN(t)||t<=0)&&(console.error(L.red(`Error: Invalid task ID: ${e.trim()}`)),process.exit(1)),t});w(e.strength)||(console.error(L.red(`Error: Invalid strength level: ${e.strength}. Must be one of: light, regular, heavy`)),process.exit(1)),B.existsSync(n)||(console.error(L.red(`Error: Tasks file not found at path: ${n}`)),process.exit(1)),console.log(m.brand(`Scoping down ${i.length===1?`task`:`tasks`} ${i.join(`, `)}`));let a={projectRoot:t.getProjectRoot(),tag:r,commandName:`scope-down`,outputType:`cli`,research:e.research||!1},o=await de(n,i,e.strength,e.prompt||null,a,`text`);console.log(L.green(`✓ Scoped down ${o.updatedTasks.length} ${o.updatedTasks.length===1?`task`:`tasks`}`))}catch(e){A(e,{hint:X(e)})}}),ke(e),e.command(`expand`).description(`Expand a task into subtasks using AI`).option(`-i, --id <id>`,`ID of the task to expand`).option(`-a, --all`,`Expand all pending tasks based on complexity analysis`).option(`-n, --num <number>`,`Number of subtasks to generate (uses complexity analysis by default if available)`).option(`-r, --research`,`Enable research-backed generation (web research via Claude Code)`,!1).option(`-p, --prompt <text>`,`Additional context for subtask generation`).option(`-f, --force`,`Force expansion even if subtasks exist`,!1).option(`--file <file>`,`Path to the tasks file (relative to project root)`,v).option(`--complexity-report <file>`,`Path to the complexity report file (use this to specify the complexity report, not --file)`).option(`--tag <tag>`,`Specify tag context for task operations`).action(async e=>{let t={tasksPath:e.file||!0,tag:e.tag};e.complexityReport&&(t.complexityReportPath=e.complexityReport);let n=Y(t),r=n.getCurrentTag();if(await M(r,{tasksPath:n.getTasksPath()}),e.all)try{(await ue(n.getTasksPath(),e.num,e.research,e.prompt,e.force,{projectRoot:n.getProjectRoot(),tag:r,complexityReportPath:n.getComplexityReportPath()}))?.failedCount>0&&(process.exitCode=1)}catch(e){A(e,{hint:X(e)})}else if(e.id){e.id||(console.error(L.red(`Error: Task ID is required unless using --all.`)),process.exit(1));try{await le(n.getTasksPath(),e.id,e.num,e.research,e.prompt,{projectRoot:n.getProjectRoot(),tag:r,complexityReportPath:n.getComplexityReportPath()},e.force)}catch(e){A(e,{hint:X(e)})}}else T(`Missing task ID`,"Try `taskgraph expand --id=3`, or `--all` for every pending task"),process.exit(1)}),e.command(`analyze-complexity`).description(`Analyze tasks and generate expansion recommendations${L.reset(``)}`).option(`-o, --output <file>`,`Output file path for the report`).option(`-m, --model <model>`,`LLM model to use for analysis (defaults to configured model)`).option(`-t, --threshold <number>`,`Minimum complexity score to recommend expansion (1-10)`,`5`).option(`-f, --file <file>`,`Path to the tasks file`,v).option(`-r, --research`,`Use configured research model for research-backed complexity analysis`).option(`-i, --id <ids>`,`Comma-separated list of specific task IDs to analyze (e.g., "1,3,5")`).option(`--from <id>`,`Starting task ID in a range to analyze`).option(`--to <id>`,`Ending task ID in a range to analyze`).option(`--tag <tag>`,`Specify tag context for task operations`).action(async e=>{let t={tasksPath:e.file||!0,tag:e.tag};e.output&&(t.complexityReportPath=e.output);let n=Y(t),r=n.getCurrentTag();await M(r,{tasksPath:n.getTasksPath()});let i=n.getComplexityReportPath(),a={...e,output:i,tag:r,projectRoot:n.getProjectRoot(),file:n.getTasksPath()};await ye(a)}),e.command(`research`).description(`Perform AI-powered research queries with project context`).argument(`[prompt]`,`Research prompt to investigate`).option(`--file <file>`,`Path to the tasks file`).option(`-i, --id <ids>`,`Comma-separated task/subtask IDs to include as context (e.g., "15,16.2")`).option(`-f, --files <paths>`,`Comma-separated file paths to include as context`).option(`-c, --context <text>`,`Additional custom context to include in the research prompt`).option(`-t, --tree`,`Include project file tree structure in the research context`).option(`-s, --save <file>`,`Save the answer to a markdown file`).option(`-d, --detail <level>`,`Output detail level: low, medium, high`,`medium`).option(`--save-to <id>`,`Add the answer to a task or subtask's details (e.g., "15" or "15.2")`).option(`--save-file`,`Save the answer to .taskgraph/docs/research/`).option(`--tag <tag>`,`Specify tag context for task operations`).action(async(e,t)=>{let n=Y({tasksPath:t.file||!0,tag:t.tag}),r=(e,t)=>{T(e,t),process.exit(1)},i=e=>/^\d+(\.\d+)?$/.test(e);(!e||typeof e!=`string`||e.trim().length===0)&&r(`Research needs a question`,`Example: taskgraph research "How should we store sessions?" --id=3`);let a=(t.detail||`medium`).toLowerCase();[`low`,`medium`,`high`].includes(a)||r(`--detail must be low, medium or high, not "${t.detail}"`);let o=t.id?t.id.split(`,`).map(e=>e.trim()).filter(Boolean):[],s=o.find(e=>!i(e));s&&r(`"${s}" isn't a task ID`,`Use --id=15 or --id=15,16.2`);let c=t.files?t.files.split(`,`).map(e=>e.trim()).filter(Boolean):[],l=t.saveTo?t.saveTo.trim():null;t.saveTo!==void 0&&!i(l||``)&&r(`"${t.saveTo}" isn't a task ID`,`Use --save-to=15 for a task or --save-to=15.2 for a subtask`);let u=t.save?t.save.trim():null;t.save!==void 0&&(!u||u.includes(`..`)||z.isAbsolute(u))&&r(`--save needs a relative file path without ".."`);let d=n.getCurrentTag(),f=n.getProjectRoot(),p=n.getTasksPath();await M(d,{tasksPath:n.getTasksPath()});let m=[...o,...l?[l]:[]];if(m.length>0){let e=_(p,f,d)?.tasks||[],t=t=>{let[n,r]=t.split(`.`).map(e=>Number.parseInt(e,10)),i=e.find(e=>Number(e.id)===n);return!i||r===void 0?!!i:(i.subtasks||[]).some(e=>Number(e.id)===r)},n=m.find(e=>!t(e));n&&r(`${n.includes(`.`)?`Subtask`:`Task`} ${n} doesn't exist in tag '${d}'`,"Run `taskgraph list` to see task IDs")}let h=c.find(e=>!B.existsSync(z.isAbsolute(e)?e:z.join(f,e)));h&&r(`File not found: ${h}`);let g=e.trim(),v;try{let{performResearch:e}=await import(`./research-8cDDG5MH.js`);v=await e(g,{taskIds:o,filePaths:c,customContext:t.context?t.context.trim():``,includeProjectTree:!!t.tree,detailLevel:a,projectRoot:f,saveToFile:!!t.saveFile,tag:d},{commandName:`research`,outputType:`cli`,tag:d},`text`,!0)}catch(e){r(`Research failed: ${e.message}`)}if(l&&!v.interactiveSaveOccurred){let e={kind:`task`,id:l};try{let{appendResearchToTask:t}=await import(`./research-8cDDG5MH.js`);t(p,l,`## Research: ${g}\n\n${v.result}`,{projectRoot:f,tag:d}),console.log(D(e))}catch(t){console.log(O(e,t.message)),process.exitCode=1}}if(u){let e={kind:`file`,path:u};try{B.writeFileSync(u,`# Research: ${g}\n\n${v.result}\n`,`utf-8`),console.log(D(e))}catch(t){console.log(O(e,t.message)),process.exitCode=1}}}),e.command(`clear-subtasks`).description(`Clear subtasks from specified tasks`).option(`-f, --file <file>`,`Path to the tasks file`,v).option(`-i, --id <ids>`,`Task IDs (comma-separated) to clear subtasks from`).option(`--all`,`Clear subtasks from all tasks`).option(`--tag <tag>`,`Specify tag context for task operations`).action(async e=>{!e.id&&!e.all&&(T(`Choose which tasks to clear`,"Use `--id=<ids>`, such as `--id=3,5`, or `--all`"),process.exit(1));let t=Y({tasksPath:e.file||!0,tag:e.tag}),n=t.getCurrentTag(),r=t.getTasksPath(),i=t.getProjectRoot();await M(n,{tasksPath:t.getTasksPath()});let a=e.id;if(e.all&&(a=(_(r,i,n)?.tasks??[]).map(e=>e.id).join(`,`),!a))console.log(`No subtasks to clear`);else try{let e=ae(r,a,{projectRoot:i,tag:n});console.log(we(e))}catch(e){if(e?.name!==`ClearSubtasksError`)throw e;let t={SUBTASK_ID:`Use \`taskgraph remove-subtask --id=${e.taskId}\` for one subtask, or \`--id=${String(e.taskId).split(`.`)[0]}\` for all`,INVALID_TASK_ID:"Use task numbers, such as `--id=3,5`",TASK_NOT_FOUND:"Run `taskgraph list` to see task IDs",NO_TASKS:`Run \`taskgraph list\` to check the "${n}" tag`};T(`${e.message}; nothing was cleared`,t[e.code]),process.exit(1)}}),e.command(`add-task`).description(`Add a new task using AI, optionally providing manual details`).option(`-f, --file <file>`,`Path to the tasks file`,v).option(`-p, --prompt <prompt>`,`Description of the task to add (required if not using manual fields)`).option(`-t, --title <title>`,`Task title (for manual task creation)`).option(`-d, --description <description>`,`Task description (for manual task creation)`).option(`--details <details>`,`Implementation details (for manual task creation)`).option(`--dependencies <dependencies>`,`Comma-separated list of task IDs this task depends on`).option(`--priority <priority>`,`Task priority (high, medium, low)`,`medium`).option(`-r, --research`,`Whether to use research capabilities for task creation`).option(`--ac <criterion>`,`Acceptance criterion; repeat for more (set-status --check ticks them)`,(e,t=[])=>[...t,e]).option(`--tag <tag>`,`Specify tag context for task operations`).action(async e=>{let t=e.title&&e.description;!e.prompt&&!t&&(console.error(L.red(`Error: Either --prompt or both --title and --description must be provided`)),process.exit(1));let n=Y({tasksPath:e.file||!0,tag:e.tag}),r=n.getProjectRoot(),i=n.getCurrentTag();await M(i,{tasksPath:n.getTasksPath()});let a=null;t&&(a={title:e.title,description:e.description,details:e.details||``,testStrategy:e.testStrategy||``});let o=e.dependencies?e.dependencies.split(`,`).map(e=>e.trim()):[],s={projectRoot:r,tag:i,commandName:`add-task`,outputType:`cli`};try{let{newTaskId:t,telemetryData:r}=await Se(n.getTasksPath(),e.prompt,o,e.priority,s,`text`,a,e.research,{acceptanceCriteria:e.ac})}catch(e){A(e,{hint:X(e)})}}),e.command(`add-dependency`).description(`Add a dependency to a task`).option(`-i, --id <id>`,`Task ID to add dependency to`).option(`-d, --depends-on <id>`,`Task ID that will become a dependency`).option(`-f, --file <file>`,`Path to the tasks file`,v).option(`--tag <tag>`,`Specify tag context for task operations`).action(async e=>{let t=Y({tasksPath:e.file||!0,tag:e.tag}),n=e.id,r=e.dependsOn,i=t.getCurrentTag();await M(i,{tasksPath:t.getTasksPath()}),(!n||!r)&&(console.error(L.red(`Error: Both --id and --depends-on are required`)),process.exit(1));let a=n.includes(`.`)?n:parseInt(n,10),o=r.includes(`.`)?r:parseInt(r,10);await Z(()=>re(t.getTasksPath(),a,o,{projectRoot:t.getProjectRoot(),tag:i}))}),e.command(`remove-dependency`).description(`Remove a dependency from a task`).option(`-i, --id <id>`,`Task ID to remove dependency from`).option(`-d, --depends-on <id>`,`Task ID to remove as a dependency`).option(`-f, --file <file>`,`Path to the tasks file`,v).option(`--tag <tag>`,`Specify tag context for task operations`).action(async e=>{let t=Y({tasksPath:e.file||!0,tag:e.tag}),n=e.id,r=e.dependsOn,i=t.getCurrentTag();await M(i,{tasksPath:t.getTasksPath()}),(!n||!r)&&(console.error(L.red(`Error: Both --id and --depends-on are required`)),process.exit(1));let a=n.includes(`.`)?n:parseInt(n,10),o=r.includes(`.`)?r:parseInt(r,10);await Z(()=>be(t.getTasksPath(),a,o,{projectRoot:t.getProjectRoot(),tag:i}))}),e.command(`validate-dependencies`).description(`Identify invalid dependencies without fixing them${L.reset(``)}`).option(`-f, --file <file>`,`Path to the tasks file`,v).option(`--tag <tag>`,`Specify tag context for task operations`).action(async e=>{let t=Y({tasksPath:e.file||!0,tag:e.tag}),n=t.getCurrentTag();await M(n,{tasksPath:t.getTasksPath()});let r=await Z(()=>ie(t.getTasksPath(),{context:{projectRoot:t.getProjectRoot(),tag:n}}));console.log(De(r)),r.valid||(process.exitCode=1)}),e.command(`fix-dependencies`).description(`Fix invalid dependencies automatically${L.reset(``)}`).option(`-f, --file <file>`,`Path to the tasks file`,v).option(`--tag <tag>`,`Specify tag context for task operations`).action(async e=>{let t=Y({tasksPath:e.file||!0,tag:e.tag}),n=t.getCurrentTag();await M(n,{tasksPath:t.getTasksPath()});let r=await Z(()=>ne(t.getTasksPath(),{context:{projectRoot:t.getProjectRoot(),tag:n}}));console.log(Ce(r)),r.remaining.length>0&&(process.exitCode=1)}),e.command(`complexity-report`).description(`Display the complexity analysis report${L.reset(``)}`).option(`-f, --file <file>`,`Path to the report file`,b).option(`--tag <tag>`,`Specify tag context for task operations`).action(async e=>{let t={tag:e.tag};e.file&&e.file!==`.taskgraph/reports/task-complexity-report.json`&&(t.complexityReportPath=e.file);let n=Y(t);await M(n.getCurrentTag(),{tasksPath:n.getTasksPath()}),await Ze(n.getComplexityReportPath())}),e.command(`add-subtask`).description(`Add a subtask to an existing task`).option(`-f, --file <file>`,`Path to the tasks file`,v).option(`-p, --parent <id>`,`Parent task ID (required)`).option(`-i, --task-id <id>`,`Existing task ID to convert to subtask`).option(`-t, --title <title>`,`Title for the new subtask (when creating a new subtask)`).option(`-d, --description <text>`,`Description for the new subtask`).option(`--details <text>`,`Implementation details for the new subtask`).option(`--dependencies <ids>`,`Comma-separated list of dependency IDs for the new subtask`).option(`-s, --status <status>`,`Status for the new subtask`,`pending`).option(`--generate`,`Regenerate task files after adding subtask`).option(`--tag <tag>`,`Specify tag context for task operations`).action(async e=>{let t=Y({tasksPath:e.file||!0,tag:e.tag}),r=e.parent,i=e.taskId,a=e.generate||!1,o=t.getCurrentTag();await M(o,{tasksPath:t.getTasksPath()}),r||(console.error(L.red(`Error: --parent parameter is required. Please provide a parent task ID.`)),n(),process.exit(1));let s=[];e.dependencies&&(s=e.dependencies.split(`,`).map(e=>e.includes(`.`)?e.trim():parseInt(e.trim(),10)));try{if(i)console.log(m.brand(`Converting task ${i} to a subtask of ${r}...`)),await S(t.getTasksPath(),r,i,null,a,{projectRoot:t.getProjectRoot(),tag:o}),console.log(L.green(`✓ Task ${i} successfully converted to a subtask of task ${r}`));else if(e.title){let n={title:e.title,description:e.description||``,details:e.details||``,status:e.status||`pending`,dependencies:s},i=await S(t.getTasksPath(),r,null,n,a,{projectRoot:t.getProjectRoot(),tag:o});console.log(H(m.text.bold(`Subtask ${r}.${i.id} Added Successfully`)+`
15
+
16
+ `+m.text(`Title: ${i.title}`)+`
17
+ `+m.text(`Status: ${P(i.status)}`)+`
18
+ `+(s.length>0?m.text(`Dependencies: ${s.join(`, `)}`)+`
19
+ `:``)+`
20
+ `+m.text.bold(`Next Steps:`)+`
21
+ `+L.cyan(`1. Run ${L.yellow(`taskgraph show ${r}`)} to see the parent task with all subtasks`)+`
22
+ `+L.cyan(`2. Run ${L.yellow(`taskgraph set-status --id=${r}.${i.id} --status=in-progress`)} to start working on it`),{padding:1,borderColor:`green`,borderStyle:`round`,margin:{top:1}}))}else console.error(L.red(`Error: Either --task-id or --title must be provided.`)),console.log(H(m.text.bold(`Usage Examples:`)+`
23
+
24
+ `+m.text(`Convert existing task to subtask:`)+`
25
+ `+L.yellow(` taskgraph add-subtask --parent=5 --task-id=8`)+`
26
+
27
+ `+m.text(`Create new subtask:`)+`
28
+ `+L.yellow(` taskgraph add-subtask --parent=5 --title="Implement login UI" --description="Create the login form"`)+`
29
+
30
+ `,{padding:1,borderColor:y,borderStyle:`round`})),process.exit(1)}catch(e){A(e)}}).on(`error`,function(e){console.error(L.red(`Error: ${e.message}`)),n(),process.exit(1)});function n(){console.log(H(`${m.text.bold(`Add Subtask Command Help`)}\n\n${L.cyan(`Usage:`)}\n taskgraph add-subtask --parent=<id> [options]\n\n${L.cyan(`Options:`)}\n -p, --parent <id> Parent task ID (required)\n -i, --task-id <id> Existing task ID to convert to subtask\n -t, --title <title> Title for the new subtask\n -d, --description <text> Description for the new subtask\n --details <text> Implementation details for the new subtask\n --dependencies <ids> Comma-separated list of dependency IDs\n -s, --status <status> Status for the new subtask (default: "pending")\n -f, --file <file> Path to the tasks file (default: "${v}")\n --generate Regenerate task files after adding subtask\n\n${L.cyan(`Examples:`)}\n taskgraph add-subtask --parent=5 --task-id=8\n taskgraph add-subtask -p 5 -t "Implement login UI" -d "Create the login form" --generate`,{padding:1,borderColor:y,borderStyle:`round`}))}e.command(`remove-subtask`).description(`Remove a subtask from its parent task`).option(`-f, --file <file>`,`Path to the tasks file`,v).option(`-i, --id <id>`,`Subtask ID(s) to remove in format "parentId.subtaskId" (can be comma-separated for multiple subtasks)`).option(`-c, --convert`,`Convert the subtask to a standalone task instead of deleting it`).option(`--generate`,`Regenerate task files after removing subtask`).option(`--tag <tag>`,`Specify tag context for task operations`).action(async e=>{let t=Y({tasksPath:e.file||!0,tag:e.tag}),n=e.id,r=e.convert||!1,i=e.generate||!1,a=t.getCurrentTag();n||(console.error(L.red(`Error: --id parameter is required. Please provide subtask ID(s) in format "parentId.subtaskId".`)),o(),process.exit(1));try{let e=n.split(`,`).map(e=>e.trim());for(let n of e){n.includes(`.`)||(console.error(L.red(`Error: Subtask ID "${n}" must be in format "parentId.subtaskId"`)),o(),process.exit(1)),r&&console.log(m.brand(`The subtask will be converted to a standalone task`));let e=await fe(t.getTasksPath(),n,r,i,{projectRoot:t.getProjectRoot(),tag:a});console.log(H(r&&e?m.text.bold(`Subtask ${n} Converted to Task #${e.id}`)+`
31
+
32
+ `+m.text(`Title: ${e.title}`)+`
33
+ `+m.text(`Status: ${P(e.status)}`)+`
34
+ `+m.text(`Dependencies: ${e.dependencies.join(`, `)}`)+`
35
+
36
+ `+m.text.bold(`Next Steps:`)+`
37
+ `+L.cyan(`1. Run ${L.yellow(`taskgraph show ${e.id}`)} to see details of the new task`)+`
38
+ `+L.cyan(`2. Run ${L.yellow(`taskgraph set-status --id=${e.id} --status=in-progress`)} to start working on it`):m.text.bold(`Subtask ${n} Removed`)+`
39
+
40
+ `+m.text(`The subtask has been successfully deleted.`),{padding:1,borderColor:`green`,borderStyle:`round`,margin:{top:1}}))}}catch(e){A(e)}}).on(`error`,function(e){console.error(L.red(`Error: ${e.message}`)),o(),process.exit(1)});function o(){console.log(H(m.text.bold(`Remove Subtask Command Help`)+`
41
+
42
+ `+L.cyan(`Usage:`)+`
43
+ taskgraph remove-subtask --id=<parentId.subtaskId> [options]
44
+
45
+ `+L.cyan(`Options:`)+`
46
+ -i, --id <id> Subtask ID(s) to remove in format "parentId.subtaskId" (can be comma-separated, required)
47
+ -c, --convert Convert the subtask to a standalone task instead of deleting it
48
+ -f, --file <file> Path to the tasks file (default: "`+v+`")
49
+ --skip-generate Skip regenerating task files
50
+
51
+ `+L.cyan(`Examples:`)+`
52
+ taskgraph remove-subtask --id=5.2
53
+ taskgraph remove-subtask --id=5.2,6.3,7.1
54
+ taskgraph remove-subtask --id=5.2 --convert`,{padding:1,borderColor:y,borderStyle:`round`}))}e.command(`remove-task`).description(`Remove one or more tasks or subtasks permanently`).option(`-i, --id <ids>`,`ID(s) of the task(s) or subtask(s) to remove (e.g., "5", "5.2", or "5,6.1,7")`).option(`-f, --file <file>`,`Path to the tasks file`,v).option(`-y, --yes`,`Skip confirmation prompt`,!1).option(`--tag <tag>`,`Specify tag context for task operations`).action(async e=>{let t=Y({tasksPath:e.file||!0,tag:e.tag}),n=e.id,r=t.getCurrentTag();await M(r,{tasksPath:t.getTasksPath()}),n||(console.error(L.red(`Error: Task ID(s) are required`)),console.error(L.yellow(`Usage: taskgraph remove-task --id=<taskId1,taskId2...>`)),process.exit(1));let i=n.split(`,`).map(e=>e.trim()).filter(Boolean);i.length===0&&(console.error(L.red(`Error: No valid task IDs provided.`)),process.exit(1));try{let n=t.getTasksPath(),a=_(n,t.getProjectRoot(),r);(!a||!a.tasks)&&(console.error(L.red(`Error: No valid tasks found in ${n}`)),process.exit(1));let o=[],s=[],c=0,l=[];for(let e of i)if(!se(a.tasks,e))s.push(e);else{let t=u(a.tasks,e).task;if(t){if(o.push({id:e,task:t}),!t.isSubtask){t.subtasks&&t.subtasks.length>0&&(c+=t.subtasks.length);let n=a.tasks.filter(t=>t.dependencies&&t.dependencies.includes(parseInt(e,10)));n.length>0&&l.push(` - Task ${e}: ${n.length} dependent tasks (${n.map(e=>e.id).join(`, `)})`)}}else s.push(`${e} (error finding details)`)}let d=`${s.length===1?`Task`:`Tasks`} ${s.join(`, `)} not found`;if(o.length===0&&(T(d,"Run `taskgraph list` to see task IDs"),process.exit(1)),s.length>0&&console.warn(L.yellow(`${d}, skipping`)),!e.yes){console.log(),console.log(L.red.bold(`⚠️ WARNING: This will permanently delete the following ${o.length} item(s):`)),console.log(),o.forEach(({id:e,task:t})=>{t&&(t.isSubtask?(console.log(m.text(` Subtask ${e}: ${t.title||`(no title)`}`)),t.parentTask&&console.log(m.muted(` (Parent: ${t.parentTask.id} - ${t.parentTask.title||`(no title)`})`))):console.log(m.text.bold(` Task ${e}: ${t.title||`(no title)`}`)))}),c>0&&console.log(L.yellow(`⚠️ This will also delete ${c} subtasks associated with the selected main tasks!`)),l.length>0&&(console.log(L.yellow(`⚠️ Warning: Dependencies on the following tasks will be removed:`)),l.forEach(e=>console.log(L.yellow(e)))),console.log();let{confirm:e}=await W.prompt([{type:`confirm`,name:`confirm`,message:L.red.bold(`Are you sure you want to permanently delete these ${o.length} item(s)?`),default:!1}]);e||(console.log(m.brand(`Task deletion cancelled.`)),process.exit(0))}let f=Ke(`Removing ${o.length} task(s)/subtask(s)...`),p=o.map(({id:e})=>e).join(`,`),h=await ge(t.getTasksPath(),p,{projectRoot:t.getProjectRoot(),tag:r});Ge(f),h.success?console.log(H(L.green(`Successfully removed ${h.removedTasks.length} task(s)/subtask(s).`)+(h.message?`\n\nDetails:\n${h.message}`:``)+(h.error?`\n\nWarnings:\n${L.yellow(h.error)}`:``),{padding:1,borderColor:`green`,borderStyle:`round`})):(console.error(H(L.red(`Operation completed with errors. Removed ${h.removedTasks.length} task(s)/subtask(s).`)+(h.message?`\n\nDetails:\n${h.message}`:``)+(h.error?`\n\nErrors:\n${L.red(h.error)}`:``),{padding:1,borderColor:`red`,borderStyle:`round`})),process.exit(1)),s.length>0&&(console.warn(L.yellow(`Note: The following IDs were not found initially and were skipped: ${s.join(`, `)}`)),h.removedTasks.length===0&&process.exit(1))}catch(e){A(e)}}),e.command(`init`).description(`Initialize a new project with TaskGraph structure`).option(`-y, --yes`,`Skip prompts and use default values`).option(`-n, --name <name>`,`Project name`).option(`-d, --description <description>`,`Project description`).option(`-v, --version <version>`,`Project version`,`0.1.0`).option(`-a, --author <author>`,`Author name`).option(`-r, --rules <rules...>`,`Rule profiles to install (claude). Accepts comma or space separated values.`).option(`--skip-install`,`Skip installing dependencies`).option(`--dry-run`,`Show what would be done without making changes`).option(`--aliases`,`Add shell aliases (tm, taskgraph)`).option(`--no-aliases`,`Skip shell aliases (tm, taskgraph)`).option(`--git`,`Initialize Git repository`).option(`--no-git`,`Skip Git repository initialization`).option(`--git-tasks`,`Store tasks in Git`).option(`--no-git-tasks`,`No Git storage of tasks`).option(t,`Import a ${i} project (${r}/)`).action(async e=>{let t=I,n=!1;if(e.rules&&Array.isArray(e.rules)){let r=e.rules.flatMap(e=>e.split(`,`)).map(e=>e.trim()).filter(Boolean),i=et(r);i.length>0&&(T(`"${i.join(`, `)}" isn't a rule profile`,`TaskGraph supports Claude Code only; use \`--rules ${I.join(`,`)}\``),process.exit(1)),r.length>0&&(t=r,n=!0)}e.rules=t,e.rulesExplicitlyProvided=n;try{await tt(e)}catch(e){A(e)}}),e.command(`models`).description(`Manage AI model configurations (Claude Code models)`).option(`--set-main <model_id>`,`Set the primary model for task generation/updates`).option(`--set-research <model_id>`,`Set the model for research-backed operations`).option(`--set-fallback <model_id>`,`Set the model to use if the primary fails`).option(`--setup`,`Run interactive setup to configure models`).addOption(new V(`--claude-code`).hideHelp()).addOption(new V(`--openrouter`).hideHelp()).addOption(new V(`--ollama`).hideHelp()).addOption(new V(`--bedrock`).hideHelp()).addOption(new V(`--azure`).hideHelp()).addOption(new V(`--vertex`).hideHelp()).addOption(new V(`--gemini-cli`).hideHelp()).addOption(new V(`--codex-cli`).hideHelp()).addOption(new V(`--lmstudio`).hideHelp()).addOption(new V(`--openai-compatible`).hideHelp()).addOption(new V(`--baseURL <url>`).hideHelp()).addHelpText(`after`,`
55
+ TaskGraph uses Claude Code. Available models: opus, sonnet, haiku.
56
+
57
+ Examples:
58
+ $ taskgraph models # View current configuration
59
+ $ taskgraph models --set-main sonnet # Set main model
60
+ $ taskgraph models --set-research opus # Set research model
61
+ $ taskgraph models --set-fallback haiku # Set fallback
62
+ $ taskgraph models --setup # Run interactive setup`).action(async e=>{let t=Y({tasksPath:e.file||!1}).getProjectRoot(),n=[`openrouter`,`ollama`,`bedrock`,`azure`,`vertex`,`geminiCli`,`codexCli`,`lmstudio`,`openaiCompatible`,`baseURL`].filter(t=>e[t]);if(n.length>0){let e=`--${n[0]===`baseURL`?`baseURL`:n[0].replace(/[A-Z]/g,e=>`-${e.toLowerCase()}`)}`;T(`${e} isn't supported any more; TaskGraph runs on Claude Code`,"Choose a model with `taskgraph models --set-main <opus|sonnet|haiku>`"),process.exit(1)}if(f(t)||(T(`No .taskgraph/config.json in this project`,"Run `taskgraph init` to recreate it"),process.exit(1)),e.setup){try{!await Be(t)&&!process.exitCode&&(process.exitCode=1)}catch(e){A(e)}return}let r=await Re({projectRoot:t});r.success||(T(`Couldn't read the model settings: ${r.error.message}`,"Run `taskgraph init` to recreate .taskgraph/config.json"),process.exit(1));let i=r.data.activeModels,a=await Ie({projectRoot:t}),o=a.success?a.data.models.map(e=>e.modelId):[],s=[[`main`,e.setMain],[`research`,e.setResearch],[`fallback`,e.setFallback]].filter(([,e])=>e);if(s.length>0){let e=s.find(([,e])=>!o.includes(e));e&&(T(`"${e[1]}" isn't a Claude Code model`,`Choose ${Te(o)}`),process.exit(1));let n=[];for(let[e,r]of s){let a=await Me(e,r,{projectRoot:t});a.success||(n.length>0&&console.log(E(n)),T(`Couldn't set the ${e} model: ${a.error.message}`),process.exit(1)),n.push({role:e,from:i[e]?.modelId??null,to:r})}console.log(E(n))}else console.log(Ne({main:i.main?.modelId??null,research:i.research?.modelId??null,fallback:i.fallback?.modelId??null},o))}),e.command(`lang`).description(`Show or set the language AI responses are written in`).option(`--response <response_language>`,`Set the response language`).option(`--setup`,`Choose the response language interactively`).addHelpText(`after`,`
63
+ Examples:
64
+ $ taskgraph lang # Show the response language
65
+ $ taskgraph lang --response French # Set it
66
+ $ taskgraph lang --setup # Choose it interactively`).action(async e=>{let t=Y({}).getProjectRoot();f(t)||(T(`No .taskgraph/config.json in this project`,"Run `taskgraph init` to recreate it"),process.exit(1));let n=h(t)||`English`,r=e.response;if(e.setup)try{r=(await W.prompt([{type:`input`,name:`language`,message:`Language for AI responses?`,default:n}])).language}catch(e){if(e?.name!==`ExitPromptError`)throw e;console.log(m.muted(`
67
+ Cancelled; response language unchanged`)),process.exitCode=130;return}if(r===void 0){console.log(`Response language: ${m.brand(n)}`),console.log(m.muted(`Change it with `)+m.brand(`taskgraph lang --response <language>`));return}r=r.trim();let i=$e(r,{projectRoot:t});i.success||(T(`Couldn't set the response language: ${i.error.message}`),process.exit(1));let a=r===n?`${m.brand(r)} ${m.muted(`(unchanged)`)}`:`${n} → ${m.brand(r)}`;console.log(`${L.green(`✓`)} Response language ${a}`)}),e.command(`move`).description(`Move tasks between tags or reorder within tags. Supports cross-tag moves with dependency resolution options.`).option(`-f, --file <file>`,`Path to the tasks file`,v).option(`--from <id>`,`ID of the task/subtask to move (e.g., "5" or "5.2"). Can be comma-separated to move multiple tasks (e.g., "5,6,7")`).option(`--to <id>`,`ID of the destination (e.g., "7" or "7.3"). Must match the number of source IDs if comma-separated`).option(`--tag <tag>`,`Specify tag context for task operations`).option(`--from-tag <tag>`,`Source tag for cross-tag moves`).option(`--to-tag <tag>`,`Target tag for cross-tag moves`).option(`--with-dependencies`,`Move dependent tasks along with main task`).option(`--ignore-dependencies`,`Break cross-tag dependencies during move`).action(async e=>{function t(){console.log(m.text.bold(`Move Command Help`)+`
68
+
69
+ `+L.cyan(`Move tasks between tags or reorder within tags.`)+`
70
+
71
+ `+L.yellow.bold(`Within-Tag Moves:`)+`
72
+ `+m.text(` taskgraph move --from=5 --to=7`)+`
73
+ `+m.text(` taskgraph move --from=5.2 --to=7.3`)+`
74
+ `+m.text(` taskgraph move --from=5,6,7 --to=10,11,12`)+`
75
+
76
+ `+L.yellow.bold(`Cross-Tag Moves:`)+`
77
+ `+m.text(` taskgraph move --from=5 --from-tag=backlog --to-tag=in-progress`)+`
78
+ `+m.text(` taskgraph move --from=5,6 --from-tag=backlog --to-tag=done`)+`
79
+
80
+ `+L.yellow.bold(`Dependency Resolution:`)+`
81
+ `+m.text(` # Move with dependencies`)+`
82
+ `+m.text(` taskgraph move --from=5 --from-tag=backlog --to-tag=in-progress --with-dependencies`)+`
83
+
84
+ `+m.text(` # Break dependencies`)+`
85
+ `+m.text(` taskgraph move --from=5 --from-tag=backlog --to-tag=in-progress --ignore-dependencies`)+`
86
+
87
+
88
+ `+L.yellow.bold(`Best Practices:`)+`
89
+ `+m.text(` • Use --with-dependencies to move dependent tasks together`)+`
90
+ `+m.text(` • Use --ignore-dependencies to break cross-tag dependencies`)+`
91
+ `+m.text(` • Check dependencies first: taskgraph validate-dependencies`)+`
92
+ `+m.text(` • Fix dependency issues: taskgraph fix-dependencies`)+`
93
+
94
+ `+L.yellow.bold(`Error Resolution:`)+`
95
+ `+m.text(` • Cross-tag dependency conflicts: Use --with-dependencies or --ignore-dependencies`)+`
96
+ `+m.text(` • Subtask movement: Promote subtask first with remove-subtask --convert`)+`
97
+ `+m.text(` • Invalid tags: Check available tags with taskgraph tags`)+`
98
+
99
+ `+m.muted(`For more help, run: taskgraph move --help`))}async function n(e,n){let{sourceId:r,sourceTag:i,toTag:a,taskGraph:o}=e;r||(console.error(L.red(`Error: --from parameter is required for cross-tag moves`)),t(),process.exit(1));let s=r.split(`,`).map(e=>e.trim()),c={withDependencies:n.withDependencies||!1,ignoreDependencies:n.ignoreDependencies||!1};console.log(m.brand(`Moving tasks ${s.join(`, `)} from "${i}" to "${a}"...`));let l=await ce(o.getTasksPath(),s,i,a,c,{projectRoot:o.getProjectRoot()});console.log(L.green(`✓ ${l.message}`)),Array.isArray(l.tips)&&l.tips.length>0&&(console.log(`
100
+ `+L.yellow.bold(`Next Steps:`)),l.tips.forEach(e=>console.log(m.text(` • ${e}`))))}async function r(e){let{sourceId:t,destinationId:n,tag:r,taskGraph:i}=e;(!t||!n)&&(console.error(L.red(`Error: Both --from and --to parameters are required for within-tag moves`)),console.log(L.yellow(`Usage: taskgraph move --from=<sourceId> --to=<destinationId>`)),process.exit(1));let a=t.split(`,`).map(e=>e.trim()),o=n.split(`,`).map(e=>e.trim());if(a.length!==o.length&&(console.error(L.red(`Error: The number of source and destination IDs must match`)),console.log(L.yellow(`Example: taskgraph move --from=5,6,7 --to=10,11,12`)),process.exit(1)),a.length>1){console.log(m.brand(`Moving multiple tasks: ${a.join(`, `)} to ${o.join(`, `)}...`));let e=_(i.getTasksPath(),i.getProjectRoot(),r);(!e||!e.tasks)&&(console.error(L.red(`Error: Invalid or missing tasks file at ${i.getTasksPath()}`)),process.exit(1));let t=[],n=[];for(let e=0;e<a.length;e++){let s=a[e],c=o[e];if(s===c)console.log(L.yellow(`Skipping ${s} -> ${c} (same ID)`));else try{await C(i.getTasksPath(),s,c,e===a.length-1,{projectRoot:i.getProjectRoot(),tag:r}),console.log(L.green(`✓ Successfully moved task/subtask ${s} to ${c}`)),n.push({fromId:s,toId:c})}catch(e){let n={fromId:s,toId:c,error:e.message};t.push(n),console.error(L.red(`Error moving ${s} to ${c}: ${e.message}`))}}t.length>0?(console.log(L.yellow(`
101
+ --- Move Operation Summary ---`)),console.log(L.green(`✓ Successfully moved: ${n.length} tasks`)),console.log(L.red(`✗ Failed to move: ${t.length} tasks`)),n.length>0&&(console.log(L.cyan(`
102
+ Successful moves:`)),n.forEach(({fromId:e,toId:t})=>{console.log(L.cyan(` ${e} → ${t}`))})),console.log(L.red(`
103
+ Failed moves:`)),t.forEach(({fromId:e,toId:t,error:n})=>{console.log(L.red(` ${e} → ${t}: ${n}`))}),console.log(L.yellow(`
104
+ Note: Some tasks were moved successfully. Check the errors above for failed moves.`))):console.log(L.green(`
105
+ ✓ All tasks moved successfully!`))}else await C(i.getTasksPath(),t,n,!0,{projectRoot:i.getProjectRoot(),tag:r}),console.log(L.green(`✓ Successfully moved task/subtask ${t} to ${n}`))}function i(e,t){if([`CROSS_TAG_DEPENDENCY_CONFLICTS`,`CANNOT_MOVE_SUBTASK`,`SOURCE_TARGET_TAGS_SAME`,`SAME_SOURCE_TARGET_TAG`].includes(e.code)||A(e,{hint:/already exists/i.test(e.message)?"Run `taskgraph list` to see which IDs are taken":void 0}),console.error(L.red(`Error: ${e.message}`)),e.code===`CROSS_TAG_DEPENDENCY_CONFLICTS`){let n=e.data.conflicts||[],r=e.data.taskIds||[];Xe(n,t.sourceTag,t.toTag,r.join(`, `))}else if(e.code===`CANNOT_MOVE_SUBTASK`){let n=e.data.taskId||t.sourceId?.split(`,`)[0];Ye(n,t.sourceTag,t.toTag)}else e.code===`SOURCE_TARGET_TAGS_SAME`||e.code===`SAME_SOURCE_TARGET_TAG`?qe(t.sourceTag,t.toTag,`Source and target tags are identical`):Qe(`after-error`);process.exit(1)}let a=Y({tasksPath:e.file||!0,tag:e.tag}),o=e.from,s=e.to,c=e.fromTag,l=e.toTag,u=a.getCurrentTag(),d=c||a.getCurrentTag(),f=d&&l&&d!==l,p={sourceId:o,destinationId:s,sourceTag:d,toTag:l,tag:u,taskGraph:a};try{f?await n(p,e):await r(p)}catch(e){let t=String(e&&(e.message||e));t.includes(`already exists in target tag`)&&(console.error(L.red(`Error: ${t}`)),console.log(`
106
+ `+L.yellow.bold(`Conflict: ID already exists in target tag`)+`
107
+ `+m.text(` • Choose a different target tag without conflicting IDs`)+`
108
+ `+m.text(` • Move a different set of IDs (avoid existing ones)`)+`
109
+ `+m.text(` • If needed, move within-tag to a new ID first, then cross-tag move`)),process.exit(1)),i(e,p)}}),e.command(`sync-readme`).description(`Sync the current task list to README.md in the project root`).option(`-f, --file <file>`,`Path to the tasks file`,v).option(`--with-subtasks`,`Include subtasks in the README output`).option(`-s, --status <status>`,`Show only tasks matching this status (e.g., pending, done)`).option(`-t, --tag <tag>`,`Tag to use for the task list (default: master)`).action(async e=>{let t=Y({tasksPath:e.file||!0,tag:e.tag}),n=e.withSubtasks||!1,r=e.status||null,i=t.getCurrentTag();console.log(m.brand(`📝 Syncing tasks to README.md${n?` (with subtasks)`:``}${r?` (status: ${r})`:``}...`)),await _t(t.getProjectRoot(),{withSubtasks:n,status:r,tasksPath:t.getTasksPath(),tag:i})||(console.error(L.red(`❌ Failed to sync tasks to README.md`)),process.exit(1))});function s(e,t){console.error(`${L.yellow(`⚠`)} ${e} is deprecated; use ${m.brand(`taskgraph ${t}`)}`)}return e.command(`add-tag`).description(`[DEPRECATED] Create a new tag context for organizing tasks (use "taskgraph tags add" instead)`).argument(`[tagName]`,`Name of the new tag to create (optional when using --from-branch)`).option(`-f, --file <file>`,`Path to the tasks file`,v).option(`--copy-from-current`,`Copy tasks from the current tag to the new tag`).option(`--copy-from <tag>`,`Copy tasks from the specified tag to the new tag`).option(`--from-branch`,`Create tag name from current git branch (ignores tagName argument)`).option(`-d, --description <text>`,`Optional description for the tag`).action(async(e,t)=>{s(`add-tag`,`tags add`);try{let n=Y({tasksPath:t.file||!0}),r=n.getTasksPath();B.existsSync(r)||(T(`No tasks yet`,$),process.exit(1)),!e&&!t.fromBranch&&(T(`add-tag needs a tag name`,"Example: `taskgraph tags add feature-auth`, or `--from-branch`"),process.exit(1));let i={projectRoot:n.getProjectRoot(),commandName:`add-tag`,outputType:`cli`};if(t.fromBranch){let{createTagFromBranch:e}=await import(`./tag-management-bTibzuNg.js`),r=await import(`./git-utils-CRR3iPaC.js`);await r.isGitRepository(i.projectRoot)||(T(`--from-branch needs a git repository, and this isn't one`,"Name the tag instead: `taskgraph tags add <name>`"),process.exit(1));let a=await r.getCurrentBranch(i.projectRoot);a||(T(`Couldn't tell which git branch is checked out`,"Name the tag instead: `taskgraph tags add <name>`"),process.exit(1));let o={copyFromCurrent:t.copyFromCurrent||!1,copyFromTag:t.copyFrom,description:t.description};await e(n.getTasksPath(),a,o,i,`text`)}else{let r={copyFromCurrent:t.copyFromCurrent||!1,copyFromTag:t.copyFrom,description:t.description};await ze(n.getTasksPath(),e,r,i,`text`)}if(t.autoSwitch){let{useTag:r}=await import(`./tag-management-bTibzuNg.js`),a=t.fromBranch?(await import(`./git-utils-CRR3iPaC.js`)).sanitizeBranchNameForTag(await(await import(`./git-utils-CRR3iPaC.js`)).getCurrentBranch(projectRoot)):e;await r(n.getTasksPath(),a,{},i,`text`)}}catch(e){A(e)}}).on(`error`,function(e){A(e)}),e.command(`delete-tag`).description(`[DEPRECATED] Delete an existing tag and all its tasks (use "taskgraph tags remove" instead)`).argument(`<tagName>`,`Name of the tag to delete`).option(`-f, --file <file>`,`Path to the tasks file`,v).option(`-y, --yes`,`Skip confirmation prompts`).action(async(e,t)=>{s(`delete-tag`,`tags remove`);try{let n=Y({tasksPath:t.file||!0}),r=n.getTasksPath();B.existsSync(r)||(T(`No tasks yet`,$),process.exit(1));let i={yes:t.yes||!1},a={projectRoot:n.getProjectRoot(),commandName:`delete-tag`,outputType:`cli`};await Pe(n.getTasksPath(),e,i,a,`text`)}catch(e){A(e)}}).on(`error`,function(e){A(e)}),e.command(`use-tag`).description(`[DEPRECATED] Switch to a different tag context (use "taskgraph tags use" instead)`).argument(`<tagName>`,`Name of the tag to switch to`).option(`-f, --file <file>`,`Path to the tasks file`,v).action(async(e,t)=>{s(`use-tag`,`tags use`);try{let n=Y({tasksPath:t.file||!0}),r=n.getTasksPath();B.existsSync(r)||(T(`No tasks yet`,$),process.exit(1));let i={projectRoot:n.getProjectRoot(),commandName:`use-tag`,outputType:`cli`};await Fe(n.getTasksPath(),e,{},i,`text`)}catch(e){A(e)}}).on(`error`,function(e){A(e)}),e.command(`rename-tag`).description(`[DEPRECATED] Rename an existing tag (use "taskgraph tags rename" instead)`).argument(`<oldName>`,`Current name of the tag`).argument(`<newName>`,`New name for the tag`).option(`-f, --file <file>`,`Path to the tasks file`,v).action(async(e,t,n)=>{s(`rename-tag`,`tags rename`);try{let r=Y({tasksPath:n.file||!0}),i=r.getTasksPath();B.existsSync(i)||(T(`No tasks yet`,$),process.exit(1));let a={projectRoot:r.getProjectRoot(),commandName:`rename-tag`,outputType:`cli`};await Ve(r.getTasksPath(),e,t,{},a,`text`)}catch(e){A(e)}}).on(`error`,function(e){A(e)}),e.command(`copy-tag`).description(`[DEPRECATED] Copy an existing tag to create a new tag with the same tasks (use "taskgraph tags copy" instead)`).argument(`<sourceName>`,`Name of the source tag to copy from`).argument(`<targetName>`,`Name of the new tag to create`).option(`-f, --file <file>`,`Path to the tasks file`,v).option(`-d, --description <text>`,`Optional description for the new tag`).action(async(e,t,n)=>{s(`copy-tag`,`tags copy`);try{let r=Y({tasksPath:n.file||!0}),i=r.getTasksPath();B.existsSync(i)||(T(`No tasks yet`,$),process.exit(1));let a={description:n.description},o={projectRoot:r.getProjectRoot(),commandName:`copy-tag`,outputType:`cli`};await Le(i,e,t,a,o,`text`)}catch(e){A(e)}}).on(`error`,function(e){A(e)}),e.command(`tui`).alias(`repl`).description(`Launch the interactive TUI/REPL mode`).action(async()=>{await Q()}),e}async function yt(){return null}async function Q(){let e=await yt();if(!e){console.log(L.yellow(`TUI mode coming soon!`)),console.log(L.dim(`Showing help instead...
110
+ `)),N();return}let t=await import(`react`),{render:n,Shell:r}=e,i=`master`,a=process.cwd();try{let e=Y({});i=e.getCurrentTag(),a=e.getProjectRoot()||process.cwd()}catch{}let o=process.stdin.isTTY&&typeof process.stdin.setRawMode==`function`;console.clear();let s={showBanner:!0,showSplash:o,initialTag:i,isInteractive:o,projectRoot:a,onExit:()=>{console.log(L.dim(`
111
+ Goodbye! 👋`)),process.exit(0)}},c=n(t.createElement(r,s));o||setTimeout(()=>{c.unmount(),console.log(L.dim(`
112
+ 💡 Run in an interactive terminal for full REPL mode.`)),process.exit(0)},200)}const $="Create some with `taskgraph parse-prd <file>`",bt=/* @__PURE__ */ new Set([`init`,`help`,`completion`,`tui`,`repl`]);function xt(t,r){let i=r;for(;i.parent?.parent;)i=i.parent;if([i.name(),...i.aliases()].some(e=>bt.has(e))||r.getOptionValueSource(`file`)===`cli`)return;let a=r.options.some(e=>e.attributeName()===`project`)?r.opts().project:null,o=typeof a==`string`?z.resolve(a):null;e(o||n())||(o?T(`No TaskGraph project at ${o}`,"Run `taskgraph init` in that folder to set one up"):T(`No TaskGraph project in this folder`,"Run `taskgraph init` to set one up, or cd into your project"),process.exit(1))}function St(){let e=new it().name(`taskgraph`).description(`AI-driven development task management`).version(`0.54.22`).helpOption(`-h, --help`,`Display help`).addHelpCommand(!1),t=e.helpInformation.bind(e);e.helpInformation=function(){return this.parent&&this.parent!==e?t():(N(),``)},vt(e);let n=(e,t)=>{e.configureOutput({outputError:(e,n)=>n(`\n${Ee(e,t||void 0)}\n`)});for(let r of e.commands)n(r,t?`${t} ${r.name()}`:r.name())};return n(e,``),e.hook(`preAction`,xt),e}async function Ct(e=process.argv){try{if(e.length<=2){k(e.slice(2),!!process.stdout.isTTY)&&F(),await Q();return}[`init`,`models`,`lang`].includes(e[2])&&d(!0),k(e.slice(2),!!process.stdout.isTTY)&&F();let t=e[2]===`completion`,n=process.env.TASKGRAPH_SKIP_AUTO_UPDATE===`1`||process.env.CI||process.env.NODE_ENV===`test`||t,r=Ue(),i=n?{currentVersion:r,latestVersion:r,needsUpdate:!1}:await ft(r);if(i.needsUpdate&&(He(i.currentVersion,i.latestVersion,i.highlights),await Oe(i.latestVersion))){je(e);return}let a=St(),o=e.filter(e=>e!==`--no-banner`);await a.parseAsync(o);try{if(t)return;let e=Y({}).getStatePath();if(e&&B.existsSync(e)){let t=JSON.parse(B.readFileSync(e,`utf8`));t?.migrationNoticePending===!0&&(We({_migrationHappened:!0}),t.migrationNoticePending=!1,t.migrationNoticeShown=!0,B.writeFileSync(e,JSON.stringify(t,null,2)))}}catch{}}catch(e){e instanceof te?console.error(H(L.red.bold(`Configuration Update Required!`)+`
113
+
114
+ `+m.text(`TaskGraph now uses a `)+L.yellow.bold(`configuration file`)+m.text(` in your project for AI model choices and settings.
115
+
116
+ This file appears to be `)+L.red.bold(`missing`)+m.text(`. No worries though.
117
+
118
+ `)+L.cyan.bold(`To create this file, run the interactive setup:`)+`
119
+ `+L.green(` taskgraph models --setup`)+`
120
+
121
+ `+m.text.bold(`Key Points:`)+`
122
+ `+m.text(`* `)+L.yellow.bold(`Configuration file`)+m.text(`: Stores your AI model settings (do not manually edit)
123
+ `)+m.text(`* `)+L.yellow.bold(`.env & .mcp.json`)+m.text(`: Still used `)+L.red.bold(`only`)+m.text(` for your AI provider API keys.
124
+
125
+ `)+L.cyan("`taskgraph models` to check your config & available models\n")+L.cyan("`taskgraph models --setup` to adjust the AI models used by TaskGraph"),{padding:1,margin:{top:1},borderColor:`red`,borderStyle:`round`})):A(e),process.exit(1)}}export{Ct as runCLI};
@@ -0,0 +1 @@
1
+ import"./src-BQZsjzA5.js";export{S as getUserId}from"./config-manager-DTkRerDn.js";
@@ -0,0 +1 @@
1
+ import{B as e,E as t,T as n,g as r,k as i,v as a,z as o}from"./src-BQZsjzA5.js";import{t as s}from"./git-utils-NnZtE3nY.js";import c from"chalk";import{isDeepStrictEqual as l}from"node:util";import u from"path";import{z as d}from"zod";import f from"dotenv";import p from"fs";import{fileURLToPath as m}from"url";import{AsyncLocalStorage as h}from"async_hooks";const g=e=>typeof e==`object`&&!!e&&!Array.isArray(e),_=e=>Array.isArray(e)&&e.every(e=>g(e)&&e.id!==void 0&&e.id!==null),v=e=>String(e.id),y=(e,t)=>l(e,t),b=(e,t)=>Object.hasOwn(e,t)?e[t]:void 0,x=(e,t,n)=>{Object.defineProperty(e,t,{value:n,enumerable:!0,writable:!0,configurable:!0})};function ee(e,t,n){let r=[];return{merged:S(e,t,n,``,r),renumbered:r}}function S(e,t,n,r,i){return y(e,t)?n:y(e,n)||y(t,n)?t:g(e)&&g(t)&&g(n)?te(e,t,n,r,i):_(e)&&_(t)&&_(n)?re(e,t,n,r,i):t}function te(e,t,n,r,i){let a=b(t,`id`),o=a==null?r:`${r}${a}.`,s=/* @__PURE__ */ new Set([...Object.keys(n),...Object.keys(t),...Object.keys(e)]),c={};for(let r of s){let a=S(b(e,r),b(t,r),b(n,r),o,i);a!==void 0&&x(c,r,a)}return c}function ne(e,t){let n=new Set(t.map(v)),r=new Set(e.map(v)),i=e.map(v).filter(e=>n.has(e)),a=t.map(v).filter(e=>r.has(e));return!y(i,a)}function re(e,t,n,r,i){let a=new Map(e.map(e=>[v(e),e])),o=new Map(t.map(e=>[v(e),e])),s=new Map(n.map(e=>[v(e),e])),c=[],l=/* @__PURE__ */ new Map;for(let e of n){let t=v(e),n=a.get(t);if(n===void 0){c.push(e);continue}let s=o.get(t);if(s===void 0)continue;let u=S(n,s,e,r,i);c.push(u),l.set(t,u)}let u=new Set(c.map(v)),d=/* @__PURE__ */ new Map,f=/* @__PURE__ */ new Map,p=ae([...c,...t.filter(e=>!a.has(v(e)))]);for(let e of t){let t=v(e);if(a.has(t))continue;if(!u.has(t)){f.set(t,e),u.add(t);continue}if(y(e,s.get(t)))continue;let n=typeof e.id==`number`?p:String(p);p++,d.set(t,n),i.push({from:`${r}${t}`,to:`${r}${n}`}),f.set(t,{...e,id:n}),u.add(String(n))}if(d.size>0)for(let[e,t]of f)f.set(e,ie(t,r,d));if(!ne(e,t))return[...c,...f.values()];let m=/* @__PURE__ */ new Map,h=null;for(let e of c){let t=v(e);l.has(t)?h=t:m.set(h,[...m.get(h)??[],e])}let g=[...m.get(null)??[]];for(let e of t){let t=v(e),n=l.get(t)??f.get(t);n!==void 0&&(g.push(n),l.has(t)&&g.push(...m.get(t)??[]))}return g}function ie(e,t,n){let r=e=>{if(!e.startsWith(t))return e;let[r,...i]=e.slice(t.length).split(`.`);return n.has(r)?[`${t}${String(n.get(r))}`,...i].join(`.`):e},i=C(e,t===``?void 0:t.slice(0,-1),r);if(t===``&&_(i.subtasks)){let t=v(e);i.subtasks=i.subtasks.map(e=>C(e,t,r))}return i}function C(e,t,n){let r={...e},a=b(e,`dependencies`);Array.isArray(a)&&(r.dependencies=a.map(e=>{if(typeof e!=`number`&&typeof e!=`string`)return e;let r=t===void 0?String(e):o(t,e),i=n(r);return i===r?e:typeof e==`string`?i:Number(i.split(`.`).pop())}));let s=b(e,`metadata`);if(g(s)){let e=b(s,i);if(g(e)){let t={};for(let[r,i]of Object.entries(e))x(t,n(r),i);let a={...s};x(a,i,t),r.metadata=a}}return r}function ae(e){let t=0;for(let n of e){let e=Number(n.id);Number.isInteger(e)&&e>t&&(t=e)}return t+1}const oe=[`add-task`,`analyze-complexity`,`expand-task`,`parse-prd`,`research`,`research-save`,`update-subtask`,`update-task`,`update-tasks`],se=`.taskgraph`,ce=`.taskgraph/tasks`,le=`.taskgraph/docs`,ue=`.taskgraph/reports`,de=`.taskgraph/templates`,fe=`.taskgraph/config.json`,pe=`.taskgraph/state.json`,me=`.taskgraph/reports/task-complexity-report.json`,he=`.taskgraph/docs/prd.txt`,ge=`.taskgraph/templates/example_prd.txt`,_e=`.taskgraph/tasks/tasks.json`,ve=`.env.example`,ye=`.gitignore`,w={primary:`#0088CC`,accent:`#0096C7`,deep:`#0080C0`},be=[w.accent,w.primary,w.deep],xe=w.accent,Se=[`dim`],Ce={dimBorder:!0},we={brand:c.cyan,heading:c.cyan.bold,accent:c.magenta,active:c.cyan.bold,muted:c.dim,text:c};let T=!1;const Te={maxRetries:5,retryDelay:100,staleLockAge:1e4};function Ee(e){if(typeof SharedArrayBuffer<`u`&&typeof Atomics<`u`&&typeof Atomics.wait==`function`)try{let t=new SharedArrayBuffer(4),n=new Int32Array(t);Atomics.wait(n,0,0,e);return}catch{}let t=Date.now()+e;for(;Date.now()<t;);}function De(e,t,n={}){let{createIfMissing:r=!1}=n,i=u.dirname(e);if(p.existsSync(i)||p.mkdirSync(i,{recursive:!0}),r)try{p.writeFileSync(e,`{}`,{flag:`wx`})}catch(e){if(e.code!==`EEXIST`)throw e}let a=`${e}.lock`,{maxRetries:o,retryDelay:s,staleLockAge:c}=Te,l=!1;for(let e=0;e<o;e++)try{let e=JSON.stringify({pid:process.pid,timestamp:Date.now()});p.writeFileSync(a,e,{flag:`wx`}),l=!0;break}catch(t){if(t.code===`EEXIST`){try{let e=p.statSync(a);if(Date.now()-e.mtimeMs>c){let e=`${a}.stale.${process.pid}.${Date.now()}`;try{p.renameSync(a,e);try{p.rmSync(e,{recursive:!0,force:!0})}catch{}continue}catch{}}}catch(e){if(e.code===`ENOENT`)continue;throw e}e<o-1&&Ee(s*2**e)}else throw t}if(!l)throw Error(`Failed to acquire lock on ${e} after ${o} attempts`);try{return t()}finally{try{p.unlinkSync(a)}catch(t){j(`warn`,`Failed to release lock for ${e}: ${t.message}`)}}}function E(e,t=null,n=null){if(t?.env?.[e])return t.env[e];if(n){let t=u.join(n,`.env`);if(p.existsSync(t))try{let n=p.readFileSync(t,`utf-8`),r=f.parse(n);if(r&&r[e])return r[e]}catch(e){j(`warn`,`Could not read or parse ${t}: ${e.message}`)}}if(process.env[e])return process.env[e]}function D(e=process.cwd(),t=[`package.json`,`pyproject.toml`,`.git`]){let n=u.resolve(e),r=u.parse(n).root;for(;n!==r;){if(t.some(e=>{let t=u.join(n,e);return p.existsSync(t)}))return n;n=u.dirname(n)}return t.some(e=>{let t=u.join(r,e);return p.existsSync(t)})?r:null}const O={debug:0,info:1,warn:2,error:3,success:1},k=new h;function Oe(e){return k.run({silent:A()},e)}function ke(){let e=k.getStore();e?e.silent=!0:T=!0}function Ae(){let e=k.getStore();e?e.silent=!1:T=!1}function A(){let e=k.getStore();return e?e.silent:T}function j(e,...t){if(A())return;let n=`info`;try{n=xt()||`info`}catch{n=`info`}let r={debug:we.muted(`[debug]`),info:``,warn:c.yellow(`⚠`),error:c.red(`✗`),success:c.green(`✓`)},i=O.hasOwnProperty(e)?e:`info`;if(O[i]>=(O[n]??O.info)){let e=r[i]||``,n=t.map(e=>typeof e==`object`?JSON.stringify(e):e).join(` `);console.log(e?`${e} ${n}`:n)}}function M(e){if(!e||typeof e!=`object`)return!1;for(let t in e)if(e.hasOwnProperty(t)&&typeof e[t]==`object`&&Array.isArray(e[t].tasks))return!0;return!1}function N(e){Array.isArray(e)&&e.forEach(e=>{if(e.id!==void 0){let t=parseInt(e.id,10);!isNaN(t)&&t>0&&(e.id=t)}Array.isArray(e.subtasks)&&e.subtasks.forEach(e=>{if(e.id!==void 0){if(typeof e.id==`string`&&e.id.includes(`.`)){let t=e.id.split(`.`);e.id=parseInt(t[t.length-1],10)}else{let t=parseInt(e.id,10);!isNaN(t)&&t>0&&(e.id=t)}}})})}function je(e,t){let n=u.relative(process.cwd(),e),r=n&&!n.startsWith(`..`)&&!u.isAbsolute(n)?n:e,i=/\(line (\d+) column (\d+)\)/.exec(t.message),a=i?` (line ${i[1]}, column ${i[2]})`:``,o=Error(`${r} isn't valid JSON${a}`,{cause:t});return o.code=`JSON_PARSE_ERROR`,o}function P(e,t=null,n=null){let r=!1;try{r=Z()}catch{}if(r&&console.log(`readJSON called with: ${e}, projectRoot: ${t}, tag: ${n}`),!e)return null;let i;try{i=JSON.parse(p.readFileSync(e,`utf8`)),r&&console.log(`Successfully read JSON from ${e}`)}catch(t){if(r&&console.log(`Failed to read JSON from ${e}: ${t.message}`),t instanceof SyntaxError&&u.basename(e)===`tasks.json`)throw je(e,t);return null}if(!e.includes(`tasks.json`)||!i)return r&&console.log(`File is not tasks.json or data is null, returning as-is`),i;if(Array.isArray(i.tasks)&&!i._rawTaggedData&&!M(i)){r&&console.log(`File is in legacy format, performing migration...`),N(i.tasks);let n={master:{tasks:i.tasks,metadata:i.metadata||{created:(/* @__PURE__ */ new Date()).toISOString(),updated:(/* @__PURE__ */ new Date()).toISOString(),description:`Tasks for master context`}}};try{if(ze(e,n),r&&console.log(`Successfully migrated legacy format to tagged format`),Me(e),t)try{s(t,e)}catch{}Fe(e)}catch(e){r&&console.log(`Error writing migrated data: ${e.message}`)}i=n}if(typeof i==`object`&&!i.tasks){r&&console.log(`File is in tagged format, resolving tag...`);for(let e in i)if(i.hasOwnProperty(e)&&typeof i[e]==`object`&&i[e].tasks)try{R(i[e],{description:`Tasks for ${e} context`,skipUpdate:!0})}catch(t){r&&console.log(`Failed to ensure metadata for tag ${e}: ${t.message}`)}let a=JSON.parse(JSON.stringify(i));for(let e in a)a[e]&&Array.isArray(a[e].tasks)&&N(a[e].tasks);if(t)try{s(t,e)}catch{}try{let o=`master`;try{if(n)o=n;else if(t)o=L({projectRoot:t});else{let t=D(u.dirname(e));t&&(o=L({projectRoot:t}))}}catch(e){r&&console.log(`Tag resolution failed, using master: ${e.message}`)}r&&console.log(`Resolved tag: ${o}`);let s=i[o];if(s&&s.tasks){N(s.tasks);let e={...s,tag:o,_rawTaggedData:a};return r&&console.log(`Returning data for tag '${o}' with ${s.tasks.length} tasks`),e}{let e=i.master;return e&&e.tasks?(N(e.tasks),r&&console.log(`Tag '${o}' not found, falling back to master with ${e.tasks.length} tasks`),{...e,tag:`master`,_rawTaggedData:a}):(r&&console.log(`No valid tag data found, returning empty structure`),{tasks:[],tag:`master`,_rawTaggedData:a})}}catch(e){r&&console.log(`Error during tag resolution: ${e.message}`);let t=i.master;return t&&t.tasks?(N(t.tasks),{...t,_rawTaggedData:a}):{tasks:[],_rawTaggedData:a}}}return r&&console.log(`File format not recognized, returning as-is`),i}function Me(e){try{let t=D(u.dirname(e))||u.dirname(e),n=u.join(t,`.taskgraph`,`config.json`);p.existsSync(n)&&Ne(n);let r=u.join(t,`.taskgraph`,`state.json`);p.existsSync(r)||Pe(r),Z()&&j(`debug`,`Complete tag migration performed for project: ${t}`)}catch(e){Z()&&j(`warn`,`Error during complete tag migration: ${e.message}`)}}function Ne(e){try{let t=p.readFileSync(e,`utf8`),n=JSON.parse(t);if(!n)return;let r=!1;n.global||={},n.global.defaultTag||(n.global.defaultTag=`master`,r=!0),r&&(p.writeFileSync(e,JSON.stringify(n,null,2),`utf8`),process.env.TASKGRAPH_DEBUG===`true`&&console.log(`[DEBUG] Updated config.json with tagged task system settings`))}catch(e){process.env.TASKGRAPH_DEBUG===`true`&&console.warn(`[WARN] Error migrating config.json: ${e.message}`)}}function Pe(e){try{let t={currentTag:`master`,lastSwitched:(/* @__PURE__ */ new Date()).toISOString(),branchTagMapping:{},migrationNoticeShown:!1};p.writeFileSync(e,JSON.stringify(t,null,2),`utf8`),process.env.TASKGRAPH_DEBUG===`true`&&console.log(`[DEBUG] Created initial state.json for tagged task system`)}catch(e){process.env.TASKGRAPH_DEBUG===`true`&&console.warn(`[WARN] Error creating state.json: ${e.message}`)}}function Fe(e){try{let t=u.join(u.dirname(u.dirname(e)),`state.json`);p.existsSync(t)||Pe(t);try{let e=p.readFileSync(t,`utf8`),n=JSON.parse(e)||{};n.migrationNoticePending=!0,n.migrationNoticeShown=!1,p.writeFileSync(t,JSON.stringify(n,null,2),`utf8`)}catch(e){process.env.TASKGRAPH_DEBUG===`true`&&console.warn(`[WARN] Error updating state for migration notice: ${e.message}`)}}catch(e){process.env.TASKGRAPH_DEBUG===`true`&&console.warn(`[WARN] Error marking migration for notice: ${e.message}`)}}let Ie=null;function Le(){return Ie||=new e,Ie}async function Re(e,t){await Le().modifyJson(e,t)}function ze(e,t,n=null,r=null){let i=process.env.TASKGRAPH_DEBUG===`true`;try{De(e,()=>{let a=t;if(t&&!t._rawTaggedData&&n&&Array.isArray(t.tasks)&&!M(t)){let o=r||I(n);i&&console.log(`writeJSON: Detected resolved tag data missing _rawTaggedData. Re-reading raw data to prevent data loss for tag '${o}'.`);let s={};try{s=JSON.parse(p.readFileSync(e,`utf8`))}catch(e){i&&console.log(`writeJSON: Could not read existing file, starting fresh: ${e.message}`)}a={...s,[o]:{metadata:{...s[o]?.metadata||{},...t.metadata||{}},tasks:t.tasks}}}else if(t&&t._rawTaggedData&&n){let o=r||I(n),s;try{s=JSON.parse(p.readFileSync(e,`utf8`))}catch(e){s=t._rawTaggedData,i&&console.log(`writeJSON: Using _rawTaggedData as fallback: ${e.message}`)}if(!s[o]&&t.tag!==o)throw Error(`Tag "${o}" not found`);let{_rawTaggedData:c,tag:l,...u}=t,d=c[o],f=s[o],m=u;if(d&&f&&Array.isArray(f.tasks)){let e=JSON.parse(JSON.stringify(f));N(e.tasks),R(e,{description:`Tasks for ${o} context`,skipUpdate:!0});let{merged:t,renumbered:n}=ee(d,u,e);m=t;for(let{from:e,to:t}of n)j(`warn`,`ID ${e} was taken by a change saved while this command ran; saved as ${t}`)}a={...s,[o]:m},i&&console.log(`writeJSON: Merging resolved data back into tag '${o}'`)}let o=a;if(o&&typeof o==`object`){let{_rawTaggedData:e,tag:t,...n}=o;if(o=n,typeof o==`object`&&!Array.isArray(o)){let e={};for(let[t,n]of Object.entries(o))if(n&&typeof n==`object`&&Array.isArray(n.tasks)){let{created:r,description:i,...a}=n;a.metadata||={},r&&!a.metadata.created&&(a.metadata.created=r),i&&!a.metadata.description&&(a.metadata.description=i),e[t]=a}else e[t]=n;o=e}}let s=`${e}.tmp.${process.pid}`;try{p.writeFileSync(s,JSON.stringify(o,null,2),`utf8`),p.renameSync(s,e)}catch(e){try{p.existsSync(s)&&p.unlinkSync(s)}catch{}throw e}i&&console.log(`writeJSON: Successfully wrote to ${e}`)},{createIfMissing:!0})}catch(t){throw j(`error`,`Error writing JSON file ${e}:`,t.message),i&&j(`error`,`Full error details:`,t),t}}function Be(e=null){let t=!1;try{t=Z()}catch{t=!1}try{let n;if(n=e||u.join(process.cwd(),me),!p.existsSync(n))return t&&j(`debug`,`Complexity report not found at ${n}`),null;let r=P(n);return t&&j(`debug`,`Successfully read complexity report from ${n}`),r}catch(e){return t&&j(`error`,`Error reading complexity report: ${e.message}`),null}}function Ve(e,t){return!e||!e.complexityAnalysis||!Array.isArray(e.complexityAnalysis)?null:e.complexityAnalysis.find(e=>e.taskId===t)}function F(e,t){let n;n=e.isSubtask?e.parentTask.id:e.parentId?e.parentId:e.id;let r=Ve(t,n);r&&(e.complexityScore=r.complexityScore)}function He(e,t){if(!t||!e||!Array.isArray(e))return!1;if(typeof t==`string`&&t.includes(`.`)){let[n,r]=t.split(`.`).map(e=>parseInt(e,10)),i=e.find(e=>e.id===n);return!i||!i.subtasks?!1:i.subtasks.some(e=>e.id===r)}let n=parseInt(t,10);return e.some(e=>e.id===n)}function Ue(e){return typeof e==`string`&&e.includes(`.`)?e:typeof e==`number`?e.toString():e}function We(e,t,n=null,r=null){if(!t||!e||!Array.isArray(e))return{task:null,originalSubtaskCount:null};if(typeof t==`string`&&t.includes(`.`)){let[r,i]=t.split(`.`).map(e=>parseInt(e,10)),a=e.find(e=>e.id===r);if(!a||!a.subtasks)return{task:null,originalSubtaskCount:null,originalSubtasks:null};let o=a.subtasks.find(e=>e.id===i);return o&&(o.parentTask={id:a.id,title:a.title,status:a.status},o.isSubtask=!0),o&&n&&F(o,n),{task:o||null,originalSubtaskCount:null,originalSubtasks:null}}let i=null,a=null,o=null,s=parseInt(t,10),c=e.find(e=>e.id===s)||null;if(!c)return{task:null,originalSubtaskCount:null,originalSubtasks:null};if(i=c,r&&c.subtasks&&Array.isArray(c.subtasks)){o=[...c.subtasks],a=c.subtasks.length;let e={...c};e.subtasks=c.subtasks.filter(e=>e.status&&e.status.toLowerCase()===r.toLowerCase()),i=e}return i&&n&&F(i,n),{task:i,originalSubtaskCount:a,originalSubtasks:o}}function Ge(e,t){return!e||e.length<=t?e:`${e.slice(0,t-3)}...`}function Ke(e){return Array.isArray(e)?e.length===0:typeof e==`object`&&e?Object.keys(e).length===0:!1}function qe(e,t,n={}){let{maxDepth:r=50,includeSelf:i=!1,direction:a=`forward`,logger:o=null}=n,s=/* @__PURE__ */ new Set,c=/* @__PURE__ */ new Set;function l(e){if(typeof e==`string`){if(e.includes(`.`))return e;let t=parseInt(e,10);return isNaN(t)?e:t}return e}function u(e,n=0){if(n>=r){let t=`Maximum recursion depth (${r}) reached for task ${e}`;o&&typeof o.warn==`function`?o.warn(t):j!==void 0&&j.warn?j.warn(t):console.warn(t);return}if(c.has(e))return;c.add(e);let a=t.find(t=>t.id===e);a&&Array.isArray(a.dependencies)&&a.dependencies.forEach(t=>{let r=l(t);r==null||!i&&r===e||(s.add(r),u(r,n+1))})}function d(e,n=0){if(n>=r){let t=`Maximum recursion depth (${r}) reached for task ${e}`;o&&typeof o.warn==`function`?o.warn(t):j!==void 0&&j.warn?j.warn(t):console.warn(t)}else c.has(e)||(c.add(e),t.forEach(t=>{if(t.dependencies&&Array.isArray(t.dependencies)&&t.dependencies.some(t=>l(t)===e)){if(t.id==null||!i&&t.id===e)return;s.add(t.id),d(t.id,n+1)}}))}let f=a===`reverse`?d:u;return e.forEach(e=>{e&&e.id&&f(e.id)}),Array.from(s)}function Je(e,t){if(!e||e.length===0)return null;let n={timestamp:(/* @__PURE__ */ new Date()).toISOString(),userId:e[0].userId,commandName:t,modelUsed:`Multiple`,providerName:`Multiple`,inputTokens:0,outputTokens:0,cachedInputTokens:0,totalTokens:0,totalCost:0,currency:e[0].currency||`USD`},r=/* @__PURE__ */ new Set,i=/* @__PURE__ */ new Set,a=/* @__PURE__ */ new Set;return e.forEach(e=>{n.inputTokens+=e.inputTokens||0,n.outputTokens+=e.outputTokens||0,n.cachedInputTokens+=e.cachedInputTokens||0,n.totalCost+=e.totalCost||0,r.add(e.modelUsed),i.add(e.providerName),a.add(e.currency||`USD`)}),n.totalTokens=n.inputTokens+n.outputTokens,n.totalCost=parseFloat(n.totalCost.toFixed(6)),r.size===1&&(n.modelUsed=[...r][0]),i.size===1&&(n.providerName=[...i][0]),a.size>1?n.currency=`Multiple`:a.size===1&&(n.currency=[...a][0]),n}function I(e){if(!e)throw Error(`projectRoot is required for getCurrentTag`);try{let t=u.join(e,`.taskgraph`,`state.json`);if(p.existsSync(t)){let e=p.readFileSync(t,`utf8`),n=JSON.parse(e);if(n&&n.currentTag)return n.currentTag}}catch{}try{let t=u.join(e,`.taskgraph`,`config.json`);if(p.existsSync(t)){let e=p.readFileSync(t,`utf8`),n=JSON.parse(e);if(n&&n.global&&n.global.defaultTag)return n.global.defaultTag}}catch{}return`master`}function L(e={}){let{projectRoot:t,tag:n}=e;if(!t)throw Error(`projectRoot is required for resolveTag`);return n||I(t)}function Ye(e,t){return!e||!t?[]:e[t]&&e[t].tasks&&Array.isArray(e[t].tasks)?e[t].tasks:[]}function Xe(e){let t=[];for(let n of e)if(t.push({...n,searchableId:n.id.toString(),isSubtask:!1}),n.subtasks&&n.subtasks.length>0)for(let e of n.subtasks)t.push({...e,searchableId:`${n.id}.${e.id}`,isSubtask:!0,parentId:n.id,parentTitle:n.title,title:`${e.title} (subtask of: ${n.title})`,description:`${e.description} [Parent: ${n.description}]`});return t}function R(e,t={}){if(!e||typeof e!=`object`)throw Error(`tagObj must be a valid object`);let n=(/* @__PURE__ */ new Date()).toISOString();return e.metadata?(e.metadata.created||(e.metadata.created=n),t.skipUpdate||(e.metadata.updated=n),t.description&&!e.metadata.description&&(e.metadata.description=t.description)):e.metadata={created:n,updated:n,...t.description?{description:t.description}:{}},e}function Ze(){return{info:(e,...t)=>j(`info`,e,...t),warn:(e,...t)=>j(`warn`,e,...t),error:(e,...t)=>j(`error`,e,...t),debug:(e,...t)=>j(`debug`,e,...t),success:(e,...t)=>j(`success`,e,...t)}}function z(e=null){return e||Ze()}function B(e){return a(e)}function V(e=process.cwd()){return r(e)}function Qe(e=null,t=null,n=null){let r=z(n),i=t?.projectRoot||V();if(!i)return r.warn?.(`Could not determine project root directory`),null;let a=B(i);if(e){let t=u.isAbsolute(e)?e:u.resolve(a,e);if(p.existsSync(t))return r.info?.(`Using explicit tasks path: ${t}`),t;r.warn?.(`Explicit tasks path not found: ${t}, trying fallbacks`)}let o=u.join(a,_e);return p.existsSync(o)?(r.info?.(`Found tasks file at: ${o}`),o):(r.warn?.(`No tasks.json found in project: ${a}`),null)}function $e(e=null,t=null,n=null){let r=z(n);if(e){let t=process.env.TASKGRAPH_ORIGINAL_CWD||process.cwd(),n=u.isAbsolute(e)?e:u.resolve(t,e);if(p.existsSync(n))return r.info?.(`Using explicit PRD path: ${n}`),n;r.warn?.(`Explicit PRD path not found: ${n}, trying fallbacks`)}let i=t?.projectRoot||V();if(!i)return r.warn?.(`Could not determine project root directory`),null;let a=B(i);for(let e of[`PRD.md`,`prd.md`,`PRD.txt`,`prd.txt`]){let t=u.join(a,le,e);if(p.existsSync(t))return r.info?.(`Found PRD document at: ${t}`),t}return r.warn?.(`No PRD document found in project: ${a}`),null}function et(e=null,t=null,n=null){let r=z(n);if(e){let t=process.env.TASKGRAPH_ORIGINAL_CWD||process.cwd(),n=u.isAbsolute(e)?e:u.resolve(t,e);if(p.existsSync(n))return r.info?.(`Using explicit complexity report path: ${n}`),n;r.warn?.(`Explicit complexity report path not found: ${n}, trying fallbacks`)}let i=t?.projectRoot||V();if(!i)return r.warn?.(`Could not determine project root directory`),null;let a=B(i),o=[`task-complexity-report`,`task-complexity`,`complexity-report`].map(e=>t?.tag&&t?.tag!==`master`?`${e}_${t.tag}.json`:`${e}.json`);for(let e of o){let t=u.join(a,ue,e);if(p.existsSync(t))return r.info?.(`Found complexity report at: ${t}`),t}return r.warn?.(`No complexity report found in project: ${a}`),null}function tt(e=null,t=null,n=null){let r=z(n),i=t?.tag;if(e){let t=process.env.TASKGRAPH_ORIGINAL_CWD||process.cwd(),n=u.isAbsolute(e)?e:u.resolve(t,e);return r.info?.(`Using explicit complexity report output path: ${n}`),n}let a=B(t?.projectRoot||V()||process.cwd()),o=`task-complexity-report.json`;i&&i!==`master`&&(o=`task-complexity-report_${i}.json`);let s=u.join(a,`.taskgraph/reports`,o);r.info?.(`Using tag-aware complexity report output path: ${s}`);let c=u.dirname(s);return p.existsSync(c)||(r.info?.(`Creating reports directory: ${c}`),p.mkdirSync(c,{recursive:!0})),s}function H(e=null,t=null,n=null){let r=z(n);if(e){let t=process.env.TASKGRAPH_ORIGINAL_CWD||process.cwd(),n=u.isAbsolute(e)?e:u.resolve(t,e);if(p.existsSync(n))return r.info?.(`Using explicit config path: ${n}`),n;r.warn?.(`Explicit config path not found: ${n}, trying fallbacks`)}let i=t?.projectRoot||V();if(!i)return r.warn?.(`Could not determine project root directory`),null;let a=B(i),o=u.join(a,fe);if(p.existsSync(o))return o;if(!K()){let e=`config_warning_${a}`;global._tmConfigWarningsThisRun||(global._tmConfigWarningsThisRun=/* @__PURE__ */ new Set),global._tmConfigWarningsThisRun.has(e)||(global._tmConfigWarningsThisRun.add(e),r.debug?.(`No configuration file found in project: ${a}`))}return null}var U={"claude-code":[{id:`opus`,swe_score:.725,cost_per_1m_tokens:{input:0,output:0},allowed_roles:[`main`,`fallback`,`research`],max_tokens:32e3,supported:!0},{id:`sonnet`,swe_score:.727,cost_per_1m_tokens:{input:0,output:0},allowed_roles:[`main`,`fallback`,`research`],max_tokens:64e3,supported:!0},{id:`haiku`,swe_score:.45,cost_per_1m_tokens:{input:0,output:0},allowed_roles:[`main`,`fallback`,`research`],max_tokens:2e5,supported:!0}]};const nt=m(import.meta.url);u.dirname(nt);const W={models:{main:{provider:`claude-code`,modelId:`sonnet`,maxTokens:64e3,temperature:.2},research:{provider:`claude-code`,modelId:`sonnet`,maxTokens:8700,temperature:.1},fallback:{provider:`claude-code`,modelId:`sonnet`,maxTokens:64e3,temperature:.2}},global:{logLevel:`info`,debug:!1,defaultNumTasks:10,defaultSubtasks:5,defaultPriority:`medium`,projectName:`TaskGraph`,responseLanguage:`English`,enableCodebaseAnalysis:!0,enableProxy:!1},claudeCode:{}};let G=null,rt=null;function it(e){global._tmSuppressConfigWarnings=e}function K(){return global._tmSuppressConfigWarnings===!0}var at=class extends Error{constructor(e){super(e),this.name=`ConfigurationError`}};function ot(e=null){let t=W,n=e;e&&`${e}`,n||(n=D(),n||=process.cwd(),`${n}`);let r=null,i={...t};if(p.existsSync(u.join(n,`.taskgraph`))&&(r=H(null,{projectRoot:n})),r)try{let e=p.readFileSync(r,`utf-8`),n=JSON.parse(e);i={models:{main:{...t.models.main,...n?.models?.main},research:{...t.models.research,...n?.models?.research},fallback:n?.models?.fallback?.provider&&n?.models?.fallback?.modelId?{...t.models.fallback,...n.models.fallback}:{...t.models.fallback}},global:{...t.global,...n?.global},claudeCode:{...t.claudeCode,...n?.claudeCode}},`${r}`,J(i.models.main.provider)||(console.warn(c.yellow(`Warning: Invalid main provider "${i.models.main.provider}" in ${r}. Falling back to default. Run 'taskgraph models --setup' to choose a Claude Code model.`)),i.models.main={...t.models.main}),J(i.models.research.provider)||(console.warn(c.yellow(`Warning: Invalid research provider "${i.models.research.provider}" in ${r}. Falling back to default. Run 'taskgraph models --setup' to choose a Claude Code model.`)),i.models.research={...t.models.research}),i.models.fallback?.provider&&!J(i.models.fallback.provider)&&(console.warn(c.yellow(`Warning: Invalid fallback provider "${i.models.fallback.provider}" in ${r}. Fallback model configuration will be ignored. Run 'taskgraph models --setup' to choose a Claude Code model.`)),i.models.fallback.provider=void 0,i.models.fallback.modelId=void 0),i.claudeCode&&!Ke(i.claudeCode)&&(i.claudeCode=ut(i.claudeCode))}catch(e){console.error(c.red(`Error reading or parsing ${r}: ${e.message}. Using default configuration.`)),i={...t},`${r}`}else(e||p.existsSync(u.join(n,`.taskgraph/tasks/tasks.json`)))&&!K()&&ct(e||n),i={...t},`${n}`;return i}const st=/* @__PURE__ */ new Set;function ct(e){st.has(e)||(st.add(e),console.warn(`${c.yellow(`⚠`)} No .taskgraph/config.json in ${e}; using default settings\n`+c.dim(` Run taskgraph init to recreate it`)))}function q(e=null,t=!1){if(!G||t||e&&e!==rt){let n=ot(e);return(t||e)&&(G=n,rt=e),n}return G}function J(e){return!!t.includes(e)}function lt(e){return U[e]?U[e].filter(e=>e.supported!==!1).map(e=>e.id):[]}function ut(e){let t=d.object({pathToClaudeCodeExecutable:d.string().optional(),maxTurns:d.number().int().positive().optional(),customSystemPrompt:d.string().optional(),appendSystemPrompt:d.string().optional(),permissionMode:d.enum([`default`,`acceptEdits`,`plan`,`bypassPermissions`]).optional(),allowedTools:d.array(d.string()).optional(),disallowedTools:d.array(d.string()).optional(),mcpServers:d.record(d.string(),d.object({type:d.enum([`stdio`,`sse`]).optional(),command:d.string(),args:d.array(d.string()).optional(),env:d.record(d.string(),d.string()).optional(),url:d.url().optional(),headers:d.record(d.string(),d.string()).optional()})).optional()}),n=d.record(d.string(),t).refine(e=>Object.keys(e||{}).every(e=>oe.includes(e)),{message:`Invalid command name in commandSpecific`}),r=t.extend({commandSpecific:n.optional()}),i={};try{i=r.parse(e)}catch(e){console.warn(c.yellow(`Warning: Invalid Claude Code settings in config: ${e.message}. Falling back to default.`)),i={}}return i}function dt(e=null,t=!1){let n=q(e,t);return{...W.claudeCode,...n?.claudeCode||{}}}function ft(e,t=null,n=!1){let r=dt(t,n),i=r?.commandSpecific||{};return{...r,...i[e]}}function Y(e,t=null){return q(t)?.models?.[e]||(j(`warn`,`No model configuration found for role: ${e}. Returning default.`),W.models[e]||{})}function pt(e=null){return Y(`main`,e).provider}function mt(e=null){return Y(`main`,e).modelId}function ht(e=null){return Y(`research`,e).provider}function gt(e=null,t=null){let n=E(`TASKGRAPH_ENABLE_CODEBASE_ANALYSIS`,e,t);if(n!=null&&n!==``)return n.toLowerCase()===`true`||n===`1`;if(e?.env?.TASKGRAPH_ENABLE_CODEBASE_ANALYSIS){let t=e.env.TASKGRAPH_ENABLE_CODEBASE_ANALYSIS;return t.toLowerCase()===`true`||t===`1`}return X(t).enableCodebaseAnalysis!==!1}function _t(e=!1,t=null,r=null){return!gt(r,t)||e?!1:(e?ht(t):pt(t))===n.CLAUDE_CODE}function vt(e=null){return Y(`research`,e).modelId}function yt(e=null){return Y(`fallback`,e).provider}function bt(e=null){return Y(`fallback`,e).modelId}function X(e=null){let t=q(e);return{...W.global,...t?.global||{}}}function xt(e=null){return X(e).logLevel.toLowerCase()}function Z(e=null){return X(e).debug===!0}function St(e=null){let t=X(e).defaultSubtasks,n=parseInt(t,10);return Number.isNaN(n)?W.global.defaultSubtasks:n}function Ct(e=null){let t=X(e).defaultNumTasks,n=parseInt(t,10);return Number.isNaN(n)?W.global.defaultNumTasks:n}function wt(e=null){return X(e).defaultPriority}function Tt(e=null){return X(e).projectName}function Et(e=null){return X(e).responseLanguage}function Q(e=null){return X(e).enableProxy===!0}function Dt(e=null,t=null){let n=E(`TASKGRAPH_ENABLE_PROXY`,e,t);if(n!=null&&n!==``)return n.toLowerCase()===`true`||n===`1`;if(e?.env?.TASKGRAPH_ENABLE_PROXY){let t=e.env.TASKGRAPH_ENABLE_PROXY;return t.toLowerCase()===`true`||t===`1`}return Q(t)}function Ot(e,t=null){let n=Y(e,t),r=n.maxTokens,i=n.temperature,a=n.modelId,o=n.provider,s=r,c=i;try{let e=U[o];if(e&&Array.isArray(e)){let t=e.find(e=>e.id===a);if(t&&typeof t.max_tokens==`number`&&t.max_tokens>0){let e=t.max_tokens;s=Math.min(r,e),j(`debug`,`Applying model-specific max_tokens (${e}) for ${a}. Effective limit: ${s}`)}else j(`debug`,`No valid model-specific max_tokens override found for ${a}. Using role default: ${r}`);t&&typeof t.temperature==`number`&&t.temperature>=0&&t.temperature<=1&&(c=t.temperature,j(`debug`,`Applying model-specific temperature (${t.temperature}) for ${a}`))}else j(`debug`,`No model definitions found for provider ${o} in MODEL_MAP. Using role default maxTokens: ${r}`)}catch(e){j(`warn`,`Error looking up model-specific parameters for ${a}: ${e.message}. Using role defaults.`),s=r,c=i}return{maxTokens:s,temperature:c}}function kt(){let e=[];for(let[t,n]of Object.entries(U))n.length>0&&n.filter(e=>!!e.supported).forEach(n=>{let r=n.id,i=n.swe_score,a=n.cost_per_1m_tokens,o=n.allowed_roles||[`main`,`fallback`],s=n.name;s||=r.split(`-`).map(e=>e.charAt(0).toUpperCase()+e.slice(1)).join(` `),e.push({id:r,name:s,provider:t,swe_score:i,cost_per_1m_tokens:a,allowed_roles:o,max_tokens:n.max_tokens})});return e}function $(e,t=null){let n=t;if(t==null){let e=D();if(!e)return console.error(c.red(`Error: Could not determine project root. Configuration not saved.`)),!1;n=e}let r=u.join(n,`.taskgraph`),i=u.join(r,`config.json`);try{return p.existsSync(r)||p.mkdirSync(r,{recursive:!0}),p.writeFileSync(i,JSON.stringify(e,null,2)),G=e,!0}catch(e){return console.error(c.red(`Error writing configuration to ${i}: ${e.message}`)),!1}}function At(e=null){return H(null,{projectRoot:e})!==null}function jt(e=null){let t=q(e);return t.global||={},t.global.userId||(t.global.userId=`1234567890`,$(t,e)||j(`warning`,`Failed to write updated configuration with new userId. Please let the developers know.`)),t.global.userId}export{j as $,J as A,de as At,F as B,_t as C,fe as Ct,Dt as D,pe as Dt,K as E,ue as Et,$e as F,D as G,Ae as H,V as I,Xe as J,We as K,Qe as L,U as M,et as N,it as O,ce as Ot,H as P,A as Q,B as R,jt as S,he as St,At as T,le as Tt,ke as U,Je as V,R as W,I as X,Ue as Y,Ye as Z,Q as _,we as _t,q as a,E as at,Et as b,ge as bt,wt as c,qe as ct,yt as d,ze as dt,Fe as et,xt as f,be as ft,Tt as g,Se as gt,Ot as h,Ce as ht,ft as i,P as it,$ as j,ut as k,_e as kt,St as l,Ge as lt,pt as m,w as mt,kt as n,Me as nt,Z as o,L as ot,mt as p,xe as pt,Ve as q,dt as r,Be as rt,Ct as s,He as st,at as t,Re as tt,bt as u,Oe as ut,vt as v,me as vt,gt as w,se as wt,lt as x,ye as xt,ht as y,ve as yt,tt as z};
@@ -0,0 +1,24 @@
1
+ import{t as e}from"./rolldown-runtime-BxhE39jg.js";import{d as t,f as n,l as r,p as i,s as a}from"./src-BQZsjzA5.js";import{$ as o,At as s,Ct as c,Dt as l,Et as u,M as d,Ot as ee,Q as f,Tt as te,_t as p,bt as ne,kt as m,wt as h,xt as g,yt as _}from"./config-manager-DTkRerDn.js";import{r as v}from"./git-utils-NnZtE3nY.js";import{A as y,C as b,W as re,et as ie}from"./src-CpPJ2WS1.js";import x from"chalk";import{join as ae}from"node:path";import{existsSync as oe,readdirSync as S,rmSync as se,rmdirSync as C,statSync as ce}from"node:fs";import w from"path";import{execSync as T}from"child_process";import E from"fs";import{fileURLToPath as le}from"url";import D from"readline";import ue from"os";import{randomUUID as de}from"crypto";const O=[`claude`];function fe(e){return e.filter(e=>!pe(e))}function pe(e){return O.includes(e)}const k=`tasks.json`,A=`tasks/`;function j(e){return e.trim().replace(/^#/,``).trim()}function M(e){let t=j(e);return t===`tasks.json`||t===`tasks/`}function me(e,t){return e.map(e=>{if(M(e)){let n=j(e),r=e.match(/\s*$/)[0];return t?`# ${n}${r}`:`${n}${r}`}return e})}function he(e){let t=[],n=!1;for(let r of e)r.trim()===`# Task files`?n=!0:M(r)||(!n||r.trim())&&(n&&r.trim()&&!M(r)&&(n=!1),n||t.push(r));return t}function ge(e,t){return e.filter(e=>{let n=e.trim();return!n||M(e)||n===`# Task files`?!1:!t.has(n)})}function N(e){let t=[`# Task files`];return e?t.push(`# ${k}`,`# ${A} `):t.push(k,`${A} `),t}function _e(e,t){if(e.some(M))return e;let n=[...e];for(;n.length>0&&!n[n.length-1].trim();)n.pop();return P(n),n.push(...N(t)),n}function P(e){if(e.some(e=>e.trim())){let t=e[e.length-1];t&&t.trim()&&e.push(``)}}function ve(e,t,n){if(!e||typeof e!=`string`)throw Error(`targetPath must be a non-empty string`);if(!e.endsWith(`.gitignore`))throw Error(`targetPath must end with .gitignore`);if(!t||typeof t!=`string`)throw Error(`content must be a non-empty string`);if(typeof n!=`boolean`)throw Error(`storeTasksInGit must be a boolean`)}function ye(e,t,n){try{E.writeFileSync(e,t.join(`
2
+ `)+`
3
+ `),typeof n==`function`&&n(`success`,`Created ${e} with full template`)}catch(t){throw typeof n==`function`&&n(`error`,`Failed to create ${e}: ${t.message}`),t}}function be(e,t,n,r){try{let i=he(E.readFileSync(e,`utf8`).split(`
4
+ `)),a=ge(t,new Set(i.map(e=>e.trim()).filter(e=>e))),o=[...i];a.length>0&&(P(o),o.push(...a)),P(o),o.push(...N(n)),E.writeFileSync(e,o.join(`
5
+ `)+`
6
+ `),typeof r==`function`&&r(`debug`,`Updated ${e} according to user preference${a.length>0?` and merged new content`:``}`)}catch(t){throw typeof r==`function`&&r(`error`,`Failed to merge content with ${e}: ${t.message}`),t}}function xe(e){try{if(!E.existsSync(e))return;let t=E.readFileSync(e,`utf8`).split(`
7
+ `).find(e=>j(e)===k);return t===void 0?void 0:t.trim().startsWith(`#`)}catch{return}}function Se(e,t,n=!0,r=null){ve(e,t,n);let i=me(t.split(`
8
+ `),n);E.existsSync(e)?be(e,i,n,r):ye(e,_e(i,n),r)}const Ce=le(import.meta.url),F=w.dirname(Ce);function I(){let e=[w.join(F,`assets`),w.join(F,`..`,`assets`),w.join(F,`..`,`..`,`public`,`assets`),w.join(process.cwd(),`assets`),w.join(process.cwd(),`node_modules`,`taskgraph-ai`,`dist`,`assets`),w.join(process.cwd(),`node_modules`,`taskgraph-ai`,`assets`)];for(let t of e)if(E.existsSync(t)){let e=w.join(t,`AGENTS.md`);if(E.existsSync(e))return t}throw Error(`Assets directory not found. This is likely a packaging issue.`)}function L(e){let t=I();return w.join(t,e)}function we(e){try{let t=L(e);return E.existsSync(t)}catch{return!1}}function R(e,t=`utf8`){let n=L(e);return E.readFileSync(n,t)}const z=`taskgraph-ai`;function Te(e){return Array.isArray(e?.args)&&e.args.some(e=>typeof e==`string`&&e.includes(`taskgraph-ai`))}function B(e){let t=JSON.stringify(e,null,` `);return t=t.replace(/(\[\n\t+)([^[\]]+?)(\n\t+\])/g,(e,t,n,r)=>!n.includes(`{`)&&!n.includes(`[`)?`[${n.replace(/\n\t+/g,` `).replace(/\s+/g,` `).trim()}]`:e),t}function Ee(e,t){if(!t){o(`debug`,`[MCP Config] No mcpConfigPath provided, skipping MCP configuration setup`);return}let n=w.join(e,t),r=w.dirname(n);o(`debug`,`Setting up MCP configuration at ${n}...`);let i={[z]:{command:`npx`,args:[`-y`,z],env:{TASKGRAPH_TOOLS:`core`}}};if(E.existsSync(r)||E.mkdirSync(r,{recursive:!0}),E.existsSync(n)){o(`debug`,`MCP configuration file already exists, checking for existing taskgraph-ai...`);try{let e=JSON.parse(E.readFileSync(n,`utf8`));if(e.mcpServers||={},Object.values(e.mcpServers).some(Te)){o(`debug`,`Found existing taskgraph-ai MCP configuration in mcp.json, leaving untouched`);return}e.mcpServers[`taskgraph-ai`]?o(`debug`,`taskgraph-ai server already configured in mcp.json`):(e.mcpServers[z]=i[z],o(`debug`,`Added taskgraph-ai server to existing MCP configuration`)),E.writeFileSync(n,B(e)+`
9
+ `),o(`debug`,`Updated MCP configuration file`)}catch(e){o(`error`,`Failed to update MCP configuration: ${e.message}`);let t=`${n}.backup-${Date.now()}`;E.existsSync(n)&&(E.copyFileSync(n,t),o(`warn`,`Saved the old file as ${t}`));let r={mcpServers:i};E.writeFileSync(n,B(r)+`
10
+ `),o(`warn`,`Created new MCP configuration file (backup of original file was created if it existed)`)}}else{let e={mcpServers:i};E.writeFileSync(n,B(e)+`
11
+ `),o(`debug`,`Created MCP configuration file at ${n}`)}o(`debug`,`MCP server will use the installed taskgraph-ai package`)}function De(e){let{name:t,displayName:n=t,profileDir:r=`.${t.toLowerCase()}`,rulesDir:i=`${r}/rules`,mcpConfig:a=!0,mcpConfigName:o=a?`mcp.json`:null,fileMap:s={},onAdd:c,onPostConvert:l}=e;return{profileName:t,displayName:n,profileDir:r,rulesDir:i,mcpConfig:a,mcpConfigName:o,mcpConfigPath:o?w.join(r,o):null,fileMap:s,...c&&{onAddRulesProfile:c},...l&&{onPostConvertRulesProfile:l}}}function Oe(){let e=ue.homedir(),t=process.env.SHELL||``;if(t.includes(`zsh`))return w.join(e,`.zshrc`);if(t.includes(`bash`)){let t=w.join(e,`.bash_profile`);return process.platform===`darwin`?t:w.join(e,`.bashrc`)}if(t.includes(`fish`))return w.join(e,`.config`,`fish`,`config.fish`);if(process.platform===`win32`){if(process.env.PSModulePath){let t=process.env.PROFILE||w.join(e,`Documents`,`WindowsPowerShell`,`Microsoft.PowerShell_profile.ps1`),n=w.join(e,`Documents`,`PowerShell`,`Microsoft.PowerShell_profile.ps1`);return E.existsSync(n)?n:E.existsSync(t)?t:n}let t=w.join(e,`.bashrc`);if(E.existsSync(t))return t}let n=w.join(e,`.zshrc`);if(E.existsSync(n))return n;let r=w.join(e,`.bashrc`);return E.existsSync(r)?r:null}function V(e){return e.endsWith(`.ps1`)}function H(e){return e.includes(`config.fish`)}function ke(e,t,n){if(!/^[A-Z_][A-Z0-9_]*$/i.test(e))return{success:!1,message:`Invalid environment variable name: ${e}. Must start with a letter or underscore and contain only alphanumeric characters and underscores.`};if(typeof t!=`string`||t.includes(`
12
+ `)||t.includes(`\r`))return{success:!1,message:`Invalid value: must be a single-line string without newlines`};let r=Oe();if(!r)return{success:!1,message:`Could not determine shell type (zsh, bash, fish, or PowerShell)`};try{let i=w.dirname(r);if(E.existsSync(i)||E.mkdirSync(i,{recursive:!0}),!E.existsSync(r)){let e=process.platform===`darwin`&&r.endsWith(`.bash_profile`);if(V(r)||e)E.writeFileSync(r,``);else return{success:!1,shellConfigFile:r,message:`Shell config file ${r} not found`}}let a=E.readFileSync(r,`utf8`),o;if(o=V(r)?RegExp(`^\\s*\\$env:${e}\\s*=`,`m`).test(a):H(r)?RegExp(`^\\s*set\\s+-[gux]*x[gux]*\\s+${e}\\s+`,`m`).test(a):RegExp(`^\\s*export\\s+${e}\\s*=`,`m`).test(a),o)return{success:!0,shellConfigFile:r,message:`${e} already configured`,alreadyExists:!0};let s,c;V(r)?(s=`$env:${e} = "${t.replace(/["`$]/g,"`$&")}"`,c=`#`):H(r)?(s=`set -gx ${e} '${t.replace(/'/g,`'\\''`)}'`,c=`#`):(s=`export ${e}='${t.replace(/'/g,`'\\''`)}'`,c=`#`);let l=`\n${n?`${c} ${n}\n`:``}${s}\n`;return E.appendFileSync(r,l),{success:!0,shellConfigFile:r,message:`Added ${e} to ${r}`}}catch(e){return{success:!1,shellConfigFile:r,message:`Failed to modify shell config: ${e.message}`}}}function Ae(){return ke(`ENABLE_EXPERIMENTAL_MCP_CLI`,`true`,`Claude Code deferred MCP loading (added by TaskGraph)`)}const U=[`task`,`master`].join(``),je=[`parse-prd`,`parse-prd-with-research`,`analyze-complexity`,`complexity-report`,`expand-task`,`expand-all-tasks`,`add-task`,`add-subtask`,`remove-task`,`remove-subtask`,`remove-subtasks`,`remove-all-subtasks`,`convert-task-to-subtask`,`add-dependency`,`remove-dependency`,`fix-dependencies`,`validate-dependencies`,`setup-models`,`view-models`,`install-taskgraph`,`quick-install-taskgraph`,`to-review`,`to-deferred`,`to-cancelled`,`init-project`,`init-project-quick`,`show-task`,`graph`,`list-tasks`,`list-tasks-with-subtasks`,`list-tasks-by-status`,`project-status`,`next-task`,`help`,`to-done`,`to-pending`,`to-in-progress`,`update-task`,`update-single-task`,`update-tasks-from-id`,`tm-main`,`smart-workflow`,`learn`,`command-pipeline`,`auto-implement-tasks`,`analyze-project`,`sync-readme`,`index`,`clear-subtasks`,`clear-all-subtasks`,`generate-tasks`,`install-${U}`,`quick-install-${U}`],Me=new Set(je.map(e=>`${e}.md`));function W(e,t,n){for(let r of S(e,{withFileTypes:!0})){let i=ae(e,r.name),a=t?`${t}/${r.name}`:r.name;r.isDirectory()?(W(i,a,n),S(i).length===0&&C(i)):Me.has(r.name)&&(se(i),n.push(a))}}function Ne(e){let t=ae(e,`.claude`,`commands`,`tm`),n=[];return!oe(t)||!ce(t).isDirectory()||(W(t,``,n),S(t).length===0&&C(t)),{removed:n}}function Pe(e,t){try{let{removed:t}=Ne(e);t.length>0&&o(`debug`,`[Claude] Removed ${t.length} old slash command files from .claude/commands/tm`)}catch(e){o(`error`,`[Claude] Failed to remove old slash command files: ${e.message}`)}let n=w.join(t,`AGENTS.md`),r=w.join(e,`CLAUDE.md`),i=w.join(e,`.taskgraph`,`CLAUDE.md`),a=`@./.taskgraph/CLAUDE.md`,s=`\n## TaskGraph Instructions\n**Import TaskGraph's development workflow commands and guidelines, treat as if import is in the main CLAUDE.md file.**\n${a}`;if(E.existsSync(n))try{let t=w.join(e,`.taskgraph`);if(E.existsSync(t)||E.mkdirSync(t,{recursive:!0}),E.copyFileSync(n,i),o(`debug`,`[Claude] Created TaskGraph instructions at ${i}`),E.existsSync(r)){let e=E.readFileSync(r,`utf8`);if(e.includes(a))o(`debug`,`[Claude] TaskGraph import already present in ${r}`);else{let t=e.trim()+`
13
+ `+s+`
14
+ `;E.writeFileSync(r,t),o(`debug`,`[Claude] Added TaskGraph import to existing ${r}`)}}else{let e=`# Claude Code Instructions\n${s}\n`;E.writeFileSync(r,e),o(`debug`,`[Claude] Created ${r} with TaskGraph import`)}}catch(e){o(`error`,`[Claude] Failed to set up Claude instructions: ${e.message}`)}let c=Ae();c.success?c.alreadyExists?o(`debug`,`[Claude] Deferred MCP loading already configured`):o(`debug`,`[Claude] Enabled deferred MCP loading in ${c.shellConfigFile}`):o(`debug`,`[Claude] Could not configure deferred loading: ${c.message}`)}function Fe(e){let t={};if(e.mcpServers){t.mcpServers={};for(let[n,r]of Object.entries(e.mcpServers)){let e={};e.type=`stdio`,r.command&&(e.command=r.command),r.args&&(e.args=r.args),r.env&&(e.env=r.env),Object.keys(r).forEach(t=>{[`command`,`args`,`env`,`type`].includes(t)||(e[t]=r[t])}),t.mcpServers[n]=e}}return t}function Ie(e,t){let n=w.join(e,`.mcp.json`);if(E.existsSync(n))try{let e=Fe(JSON.parse(E.readFileSync(n,`utf8`)));E.writeFileSync(n,JSON.stringify(e,null,` `)+`
15
+ `),o(`debug`,`[Claude] Transformed MCP configuration to Claude format at ${n}`)}catch(e){o(`error`,`[Claude] Failed to transform MCP configuration: ${e.message}`)}}const Le=De({name:`claude`,displayName:`Claude Code`,profileDir:`.`,rulesDir:`.`,mcpConfigName:`.mcp.json`,fileMap:{"AGENTS.md":`.taskgraph/CLAUDE.md`},onAdd:Pe,onPostConvert:Ie});var Re=/* @__PURE__ */ e({claudeProfile:()=>Le});function ze(e){return O.includes(e)}function Be(e){if(!ze(e))return null;let t=Re[`${e}Profile`];if(!t)throw Error(`Profile not found: static import missing for '${e}'. Valid profiles: ${O.join(`, `)}`);return t}function Ve(e,t){let n=w.join(e,t.rulesDir),r=0;if(typeof t.onAddRulesProfile==`function`)try{t.onAddRulesProfile(n,I()),o(`debug`,`[Rule Transformer] Called onAddRulesProfile for ${t.profileName}`)}catch(e){o(`error`,`[Rule Transformer] onAddRulesProfile failed for ${t.profileName}: ${e.message}`),r++}if(t.mcpConfig!==!1)try{Ee(e,t.mcpConfigPath),o(`debug`,`[Rule Transformer] Setup MCP configuration for ${t.profileName}`)}catch(e){o(`error`,`[Rule Transformer] MCP setup failed for ${t.profileName}: ${e.message}`)}if(typeof t.onPostConvertRulesProfile==`function`)try{t.onPostConvertRulesProfile(n,I()),o(`debug`,`[Rule Transformer] Called onPostConvertRulesProfile for ${t.profileName}`)}catch(e){o(`error`,`[Rule Transformer] onPostConvertRulesProfile failed for ${t.profileName}: ${e.message}`)}return{success:1,failed:r}}function He(e){try{let t=JSON.parse(E.readFileSync(e,`utf-8`));for(let e of[`main`,`research`,`fallback`])if(t.models&&t.models[e]){let n=t.models[e].provider,r=t.models[e].modelId;if(d[n]){let i=d[n].find(e=>e.id===r);i&&i.max_tokens&&(t.models[e].maxTokens=i.max_tokens)}}return E.writeFileSync(e,JSON.stringify(t,null,2)),!0}catch(e){return console.error(`Error updating config maxTokens:`,e.message),!1}}const G=(e={})=>!!e[r];function Ue(e,r){if(G(e))try{n(r)}catch(e){if(!(e instanceof t)||f())throw e;b(e.message,e.hint),process.exit(1)}}const We=e=>G(e)?[` import tasks, docs, reports and settings from ${a}/`]:[],Ge=(e,t,n)=>G(t)&&!n?i(e):void 0;function Ke(e,t,n){console.log(`${y({result:e,changes:t.filter(e=>e.path!==`${n}/`)})}\n`)}const K=`alias tm='taskgraph'`,q=`ENABLE_EXPERIMENTAL_MCP_CLI`,J={debug:0,info:1,warn:2,error:3,success:4},qe=process.env.TASKGRAPH_LOG_LEVEL?J[process.env.TASKGRAPH_LOG_LEVEL.toLowerCase()]:J.info;function Je(){f()||ie()}function Y(e,...t){let n={debug:p.muted(`•`),info:p.brand(`→`),warn:x.yellow(`!`),error:x.red(`✗`),success:x.green(`✓`)};if(J[e]>=qe){let r=n[e]||``;f()||(e===`error`?console.error(r,x.red(...t)):e===`warn`?console.warn(r,x.yellow(...t)):e===`success`?console.log(r,x.green(...t)):e===`info`?console.log(r,p.brand(...t)):console.log(r,...t))}if(process.env.DEBUG===`true`){let n=`[${e.toUpperCase()}] ${t.join(` `)}\n`;E.appendFileSync(`init-debug.log`,n)}}function Ye(e,...t){Y(e===`warn`||e===`error`?e:`debug`,...t)}function X(e){E.existsSync(e)||(E.mkdirSync(e,{recursive:!0}),Y(`debug`,`Created directory: ${e}`))}function Xe(){let e=process.env.HOME||process.env.USERPROFILE;return e?[`.zshrc`,`.bashrc`,`.bash_profile`,`.profile`].map(t=>w.join(e,t)):[]}function Ze(e){return[w.join(e,h),w.join(e,c),w.join(e,m),w.join(e,`.git`),w.join(e,g),w.join(e,_),w.join(e,`CLAUDE.md`),w.join(e,`.mcp.json`),...Xe()]}function Qe(e){let t=/* @__PURE__ */ new Map;for(let n of e){let e=null;try{E.existsSync(n)&&(e=E.statSync(n).isDirectory()?``:E.readFileSync(n,`utf8`))}catch{e=null}t.set(n,e)}return t}function $e(e,t,n){let r=t=>w.join(e,t),i=e=>t.get(e)==null&&n.get(e)!=null,a=e=>t.get(e)!=null&&n.get(e)!=null&&t.get(e)!==n.get(e),o=t.get(r(`.taskgraph/config.json`))!=null||t.get(r(`.taskgraph/tasks/tasks.json`))!=null,s=[];!o&&n.get(r(`.taskgraph/config.json`))!=null?s.push({path:`${h}/`,note:`tasks, settings and PRD templates`}):o&&i(r(`.taskgraph/config.json`))&&s.push({path:c,note:`restored`}),i(r(`.git`))&&s.push({path:`.git/`,note:`new Git repository`});let l=[[g,`created`,`added TaskGraph entries`],[_,`optional settings`,`updated`],[`CLAUDE.md`,`loads TaskGraph's instructions in Claude Code`,`now imports TaskGraph's instructions`],[`.mcp.json`,`TaskGraph MCP server for Claude Code`,`added the TaskGraph MCP server`]];for(let[e,t,n]of l){let o=r(e);i(o)?s.push({path:e,note:t}):a(o)&&s.push({path:e,note:n})}let u=process.env.HOME||process.env.USERPROFILE;for(let e of Xe()){let r=t.get(e)||``,i=n.get(e)||``;if(i===r)continue;let a=[];i.includes(K)&&!r.includes(K)&&a.push("the `tm` alias"),i.includes(q)&&!r.includes(q)&&a.push(`deferred MCP loading`),a.length!==0&&s.push({path:u?e.replace(u,`~`):e,note:`added ${a.join(` and `)}; open a new terminal`})}return{alreadySetUp:o,changes:s}}function et(){let e=process.env.HOME||process.env.USERPROFILE,t;if(process.env.SHELL?.includes(`zsh`))t=w.join(e,`.zshrc`);else if(process.env.SHELL?.includes(`bash`))t=w.join(e,`.bashrc`);else return Y(`debug`,`Could not determine shell type. Aliases not added.`),!1;try{if(!E.existsSync(t))return Y(`debug`,`Shell config file ${t} not found.`),!1;let e=E.readFileSync(t,`utf8`),n=[{name:`tm`,line:K}].filter(t=>!e.includes(t.line));if(n.length===0)return Y(`debug`,`All TaskGraph aliases already exist.`),!0;let r=n.map(e=>e.line).join(`
16
+ `),i=`
17
+ # TaskGraph aliases added on ${(/* @__PURE__ */ new Date()).toLocaleDateString()}
18
+ ${r}
19
+ `;return E.appendFileSync(t,i),Y(`debug`,`Added ${n.length} alias(es): ${n.map(e=>e.name).join(`, `)}`),!0}catch(e){return Y(`debug`,`Failed to add aliases: ${e.message}`),!1}}function tt(e){let t=w.join(e,l);if(E.existsSync(t)){Y(`debug`,`State file already exists, preserving current configuration`);return}let n={currentTag:`master`,lastSwitched:(/* @__PURE__ */ new Date()).toISOString(),branchTagMapping:{},migrationNoticeShown:!0};try{E.writeFileSync(t,JSON.stringify(n,null,2)),Y(`debug`,`Created initial state file: ${t}`)}catch(e){Y(`error`,`Failed to create state file: ${e.message}`)}}function nt(e){let t=w.join(e,m);if(E.existsSync(t))return;let n={master:{tasks:[],metadata:{created:(/* @__PURE__ */ new Date()).toISOString(),description:`Tasks for master context`}}};try{E.writeFileSync(t,`${JSON.stringify(n,null,2)}\n`),Y(`debug`,`Created empty tasks file: ${t}`)}catch(e){Y(`error`,`Failed to create tasks file: ${e.message}`)}}function Z(e,t,n={}){if(!we(e)){Y(`error`,`Source file not found: ${e}`);return}let r=R(e,`utf8`);if(Object.entries(n).forEach(([e,t])=>{let n=RegExp(`\\{\\{${e}\\}\\}`,`g`);r=r.replace(n,t)}),E.existsSync(t)){let e=w.basename(t);if(e===`.gitignore`){Y(`debug`,`${t} already exists, merging content...`);let e=E.readFileSync(t,`utf8`),n=new Set(e.split(`
20
+ `).map(e=>e.trim())),i=r.split(`
21
+ `).filter(e=>!n.has(e.trim()));if(i.length>0){let n=`${e.trim()}\n\n# Added by TaskGraph\n${i.join(`
22
+ `)}`;E.writeFileSync(t,n),Y(`debug`,`Updated ${t} with additional entries`)}else Y(`debug`,`No new content to add to ${t}`);return}if(e===`README-taskgraph.md`){Y(`debug`,`${t} already exists`);let e=w.join(w.dirname(t),`README-taskgraph.md`);E.writeFileSync(e,r),Y(`debug`,`Created ${e} (preserved original README-taskgraph.md)`);return}Y(`debug`,`${t} already exists, skipping.`)}else E.writeFileSync(t,r),Y(`debug`,`Created file: ${t}`)}async function rt(e={}){Ue(e,process.cwd()),f()||Je(),e.git===!0?e.initGit=!0:e.git===!1&&(e.initGit=!1),e.gitTasks===!0?e.storeTasksInGit=!0:e.gitTasks===!1&&(e.storeTasksInGit=!1);let t=e.yes||e.name&&e.description,n;if(n=e.rulesExplicitlyProvided?e.rules:[],t){e.name,e.description,e.version,e.author;let t=e.dryRun||!1,r=e.initGit===void 0||e.initGit,i=e.storeTasksInGit??xe(w.join(process.cwd(),`.gitignore`))??!0;if(t)return $(r,i,e),{dryRun:!0};await ot(e.aliases!==!1,r,i,t,{...e,preferredLanguage:`English`},n)}else{Y(`debug`,`Required options not provided, proceeding with prompts.`);let t;try{Y(`debug`,`Init started - taskgraph_id: ${it()}`),t=D.createInterface({input:process.stdin,output:process.stdout});let r=!0,i=!0;r=e.initGit===void 0?v()?!0:(await Q(t,x.cyan(`Initialize a Git repository in project root? (Y/n): `),e=>{let t=e.trim().toLowerCase()!==`n`,n=t?x.green(`✓`):x.dim(`–`);return x.cyan(`Initialize a Git repository in project root?`)+` `+n+` `+x.dim(t?`Yes`:`No`)})).trim().toLowerCase()!==`n`:e.initGit,i=e.storeTasksInGit===void 0?(await Q(t,x.cyan(`Store tasks in Git (tasks.json and tasks/ directory)? (Y/n): `),e=>{let t=e.trim().toLowerCase()!==`n`,n=t?x.green(`✓`):x.dim(`–`);return x.cyan(`Store tasks in Git (tasks.json and tasks/ directory)?`)+` `+n+` `+x.dim(t?`Yes`:`No`)})).trim().toLowerCase()!==`n`:e.storeTasksInGit;let a=!1;e.rulesExplicitlyProvided?Y(`debug`,`Using rule profiles provided via command line: ${n.join(`, `)}`):a=(await Q(t,x.cyan(`Set up Claude Code integration (CLAUDE.md import)? (y/N): `),e=>{let t=e.trim().toLowerCase()===`y`,n=t?x.green(`✓`):x.dim(`–`);return x.cyan(`Set up Claude Code integration?`)+` `+n+` `+x.dim(t?`Yes`:`No`)})).trim().toLowerCase()===`y`;let o=(await Q(t,x.cyan(`Language for AI responses (English): `),e=>`${x.cyan(`Language for AI responses?`)} ${x.dim(e.trim()||`English`)}`)).trim()||`English`,s=e.dryRun||!1;if(s)return t.close(),$(r,i,e),{dryRun:!0};await ot(e.aliases!==!1,r,i,s,{...e,shouldSetupRules:a,preferredLanguage:o},a?O:n),t.close()}catch(e){t&&t.close(),Y(`error`,`Error during initialization process: ${e.message}`),process.exit(1)}}}function Q(e,t,n){return new Promise(r=>{e.question(t,e=>{D.moveCursor(process.stdout,0,-1),D.cursorTo(process.stdout,0),D.clearLine(process.stdout,0),n&&process.stdout.write(n(e)+`
23
+ `),r(e)})})}function it(){return de()}function at(e){try{if(!E.existsSync(e)){Y(`warn`,`Config file does not exist, skipping storage configuration`);return}let t=E.readFileSync(e,`utf8`),n=JSON.parse(t);n.storage||={},n.storage.type=`file`,n.storage.operatingMode=`solo`,Y(`debug`,`Configured storage for local file storage`),E.writeFileSync(e,JSON.stringify(n,null,2)),Y(`debug`,`Storage configuration updated in config.json`)}catch(e){Y(`error`,`Failed to update storage configuration: ${e.message}`)}}async function ot(e,t,n,r,i,a=O){let o=process.cwd();Y(`debug`,`Initializing project in ${o}`);let l=f()?[]:Ze(o),d=Qe(l);X(w.join(o,h)),X(w.join(o,ee)),X(w.join(o,te)),X(w.join(o,u)),X(w.join(o,s)),tt(o),nt(o);let p={year:(/* @__PURE__ */ new Date()).getFullYear()};function m(e){let t=Be(e);t?Ve(o,t):Y(`warn`,`Unknown rule profile: ${e}`)}Z(`env.example`,w.join(o,_),p),Z(`config.json`,w.join(o,c),{...p});let y=w.join(o,c);He(y)?Y(`debug`,`Updated config with correct maxTokens values`):Y(`debug`,`Could not update maxTokens in config`),at(y);try{let e=R(`gitignore`,`utf8`);Se(w.join(o,g),e,n,Ye)}catch(e){Y(`error`,`Failed to create .gitignore: ${e.message}`)}Z(`example_prd.txt`,w.join(o,ne)),Z(`example_prd_rpg.txt`,w.join(o,s,`example_prd_rpg.txt`));try{t===!1?Y(`debug`,`Git initialization skipped due to --no-git flag.`):v()?Y(`debug`,`Existing Git repository detected; skipping git init.`):(T(`git init`,{cwd:o,stdio:`ignore`}),Y(`debug`,`Git repository initialized`))}catch{Y(`warn`,`Git not available, skipping repository initialization`)}if(a.length>0){Y(`debug`,`Setting up Claude Code integration...`);for(let e of a)m(e)}if(i.preferredLanguage&&!r)try{let e=(await import(`./response-language-cUVFE-lr.js`)).default;e(i.preferredLanguage,{projectRoot:o,silent:!0}),Y(`debug`,`Response language set to: ${i.preferredLanguage}`)}catch(e){Y(`warn`,`Failed to set response language: ${e.message}`)}let b=Ge(o,i,r);if(!f()&&!r&&!i?.yes&&!b){console.log(``);try{T(`"${process.execPath}" "${process.argv[1]}" models --setup --no-banner`,{stdio:`inherit`,cwd:o}),console.log(``)}catch{Y(`warn`,"Model setup did not finish; run `taskgraph models --setup` to retry")}}else f()&&!r&&Y(`debug`,`Skipping interactive model setup in silent (MCP) mode.`);if(e&&!r&&et(),!f()){let{alreadySetUp:e,changes:t}=$e(o,d,Qe(l));if(b){Ke(b,t,h);return}console.log(`${re({folder:w.basename(o),changes:t,alreadySetUp:e,claudeCode:a.includes(`claude`),defaultModels:!!i?.yes})}\n`)}}function $(e,t,n){if(f())return;let r=[`Dry run; nothing was changed. Init would:`,` create ${h}/ with tasks, settings and PRD templates`,...We(n),` create or update ${g} and ${_}`];e!==!1&&!v()&&r.push(` start a Git repository`),r.push(t?` keep tasks in Git`:` keep tasks out of Git`),console.log(r.join(`
24
+ `))}export{O as n,fe as r,rt as t};