taskgraph-ai 0.50.1 → 0.52.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1 @@
1
+ import"./ai-services-unified-D8KwE3rg.js";import"./src-D5YOCTZ3.js";import"./config-manager-BUm0w7j9.js";import"./git-utils-CrYiSKu0.js";import{k as e}from"./dependency-manager-LVhwG4fY.js";import"./response-language-lNB7-WgQ.js";export{e as performResearch};
@@ -0,0 +1 @@
1
+ import"./src-D5YOCTZ3.js";import"./config-manager-BUm0w7j9.js";import"./git-utils-CrYiSKu0.js";import{t as e}from"./response-language-lNB7-WgQ.js";export{e as default};
@@ -1 +1 @@
1
- import{A as e,N as t,T as n,a as r,nt as i}from"./config-manager-Da0wEujO.js";function a(a,o={}){let{mcpLog:s,projectRoot:c}=o,l=(e,...t)=>{s&&typeof s[e]==`function`&&s[e](...t)},u=t(null,{projectRoot:c}),d=n(c);if(i(`debug`,`Checking for config file using findConfigPath, found: ${u}`),i(`debug`,`Checking config file using isConfigFilePresent(), exists: ${d}`),!d)return{success:!1,error:{code:`CONFIG_MISSING`,message:`The configuration file is missing. Run "taskgraph init" to create it.`}};if(typeof a!=`string`||a.trim()===``)return{success:!1,error:{code:`INVALID_RESPONSE_LANGUAGE`,message:`Invalid response language: ${a}. Must be a non-empty string.`}};try{let t=r(c);return t.global.responseLanguage=a,e(t,c)?{success:!0,data:{responseLanguage:a,message:successMessage}}:{success:!1,error:{code:`WRITE_ERROR`,message:`Error writing updated configuration to configuration file`}}}catch(e){return l(`error`,`Error setting response language: ${e.message}`),{success:!1,error:{code:`SET_RESPONSE_LANGUAGE_ERROR`,message:e.message}}}}var o=a;export{o as t};
1
+ import{A as e,N as t,T as n,a as r,nt as i}from"./config-manager-BUm0w7j9.js";function a(a,o={}){let{mcpLog:s,projectRoot:c}=o,l=(e,...t)=>{s&&typeof s[e]==`function`&&s[e](...t)},u=t(null,{projectRoot:c}),d=n(c);if(i(`debug`,`Checking for config file using findConfigPath, found: ${u}`),i(`debug`,`Checking config file using isConfigFilePresent(), exists: ${d}`),!d)return{success:!1,error:{code:`CONFIG_MISSING`,message:`The configuration file is missing. Run "taskgraph init" to create it.`}};if(typeof a!=`string`||a.trim()===``)return{success:!1,error:{code:`INVALID_RESPONSE_LANGUAGE`,message:`Invalid response language: ${a}. Must be a non-empty string.`}};try{let t=r(c);return t.global.responseLanguage=a,e(t,c)?{success:!0,data:{responseLanguage:a,message:successMessage}}:{success:!1,error:{code:`WRITE_ERROR`,message:`Error writing updated configuration to configuration file`}}}catch(e){return l(`error`,`Error setting response language: ${e.message}`),{success:!1,error:{code:`SET_RESPONSE_LANGUAGE_ERROR`,message:e.message}}}}var o=a;export{o as t};
@@ -175,18 +175,18 @@ Find code smells and clean them up. ONE cleanup per session.
175
175
  `,`utf-8`)}isPreset(e){return F(e)}async resolvePrompt(e){if(this.isPreset(e))return N[e];let t=await s(e,`utf-8`);if(!t.trim())throw Error(`Custom prompt file '${e}' is empty`);return t}buildContextHeader(e,t){let n=e.tag?` (tag: ${e.tag})`:``;return`@${e.progressFile} @CLAUDE.md
176
176
 
177
177
  Loop iteration ${t} of ${e.iterations}${n}`}async buildPrompt(e,t){let n=await this.resolvePrompt(e.prompt);return`${this.buildContextHeader(e,t)}\n\n${n}`}parseCompletion(e,t){let n=e.match(/<loop-complete>([^<]*)<\/loop-complete>/i);if(n)return{status:`complete`,message:n[1].trim()};let r=e.match(/<loop-blocked>([^<]*)<\/loop-blocked>/i);return r?{status:`blocked`,message:r[1].trim()}:t===0?{status:`success`}:{status:`error`,message:`Exit code ${t}`}}async executeIteration(e,t,n,r=!1,i=!1,a){let o=Date.now(),s=n?`docker`:`claude`;if(i)return this.executeVerboseIteration(e,t,s,n,r,o,a);let c=p(s,this.buildCommandArgs(e,n,!1),{cwd:this.projectRoot,encoding:`utf-8`,maxBuffer:50*1024*1024,stdio:[`inherit`,`pipe`,`pipe`]});if(c.error){let e=this.formatCommandError(c.error,s,n);return this.reportError(a,e),this.createErrorIteration(t,o,e)}let l=(c.stdout||``)+(c.stderr||``);if(l&&a?.onOutput?.(l),c.status===null){let e=`Command terminated abnormally (no exit code)`;return this.reportError(a,e),this.createErrorIteration(t,o,e)}let{status:u,message:d}=this.parseCompletion(l,c.status);return{iteration:t,status:u,duration:Date.now()-o,message:d,...r&&{output:l}}}executeVerboseIteration(e,t,n,r,i,a,o){let s=this.buildCommandArgs(e,r,!0);return new Promise(e=>{let c=!1,l=t=>{c||(c=!0,e(t))},u=f(n,s,{cwd:this.projectRoot,stdio:[`inherit`,`pipe`,`pipe`]}),d=!1,p=``,m=``,h=e=>{if(e.startsWith(`{`))try{let t=JSON.parse(e);if(!this.isValidStreamEvent(t))return;this.handleStreamEvent(t,o),t.type===`result`&&(p=typeof t.result==`string`?t.result:``)}catch(t){if(e.trim().startsWith(`{`)){let n=`Failed to parse JSON event: ${t instanceof Error?t.message:`Unknown error`}. Line: ${e.substring(0,100)}...`;this.reportError(o,n,`warning`)}}};if(!u.stdout){l(this.createErrorIteration(t,a,`Failed to capture stdout from child process`));return}u.stdout.on(`data`,e=>{try{let t=this.processBufferedLines(m,e.toString(`utf-8`));m=t.remaining;for(let e of t.complete)h(e)}catch(e){this.reportError(o,`Failed to process stdout data: ${e instanceof Error?e.message:`Unknown error`}`,`warning`)}}),u.stdout.on(`end`,()=>{d=!0,m&&=(h(m),``)}),u.stderr?.on(`data`,e=>{let n=e.toString(`utf-8`);o?.onStderr?.(t,n)}),u.on(`error`,e=>{let i=this.formatCommandError(e,n,r);if(this.reportError(o,i),u.stdout?.removeAllListeners(),u.stderr?.removeAllListeners(),!u.killed)try{u.kill(`SIGTERM`)}catch{}l(this.createErrorIteration(t,a,i))}),u.on(`close`,e=>{if(!d&&m&&h(m),e===null){let e=`Command terminated abnormally (no exit code)`;this.reportError(o,e),l(this.createErrorIteration(t,a,e));return}let{status:n,message:r}=this.parseCompletion(p,e);l({iteration:t,status:n,duration:Date.now()-a,message:r,...i&&{output:p}})})})}isValidStreamEvent(e){if(!e||typeof e!=`object`)return!1;let t=e;if(!(`type`in t)||typeof t.type!=`string`)return!1;if(`message`in t&&t.message!==void 0){if(typeof t.message!=`object`||t.message===null)return!1;let e=t.message;if(`content`in e&&!Array.isArray(e.content))return!1}return!0}buildCommandArgs(e,t,n){if(t)return[`sandbox`,`run`,`claude`,`-p`,e];let r=[`-p`,e,`--dangerously-skip-permissions`];return n&&r.push(`--output-format`,`stream-json`,`--verbose`),r}formatCommandError(e,t,n){return e.code===`ENOENT`?n?`Docker is not installed. Install Docker Desktop to use --sandbox mode.`:`Claude CLI is not installed. Install with: npm install -g @anthropic-ai/claude-code`:e.code===`EACCES`?`Permission denied executing '${t}'`:`Failed to execute '${t}': ${e.message}`}createErrorIteration(e,t,n){return{iteration:e,status:`error`,duration:Date.now()-t,message:n}}handleStreamEvent(e,t){if(!(e.type!==`assistant`||!e.message?.content))for(let n of e.message.content)n.type===`text`&&n.text?t?.onText?.(n.text):n.type===`tool_use`&&n.name&&t?.onToolUse?.(n.name)}processBufferedLines(e,t){let n=(e+t).split(`
178
- `);return{complete:n.slice(0,-1),remaining:n[n.length-1]}}},xe=class{logger=E(`LoopDomain`);loopService=null;projectRoot;constructor(e){this.projectRoot=e.getProjectRoot()}checkSandboxAuth(){return new I({projectRoot:this.projectRoot}).checkSandboxAuth()}runInteractiveAuth(){return new I({projectRoot:this.projectRoot}).runInteractiveAuth()}async run(e){if(this.loopService?.isRunning)try{this.loopService.stop()}catch(e){this.logger.warn(`Failed to stop previous loop service:`,e)}let t=this.buildConfig(e);return this.loopService=new I({projectRoot:this.projectRoot}),this.loopService.run(t)}stop(){this.loopService&&=(this.loopService.stop(),null)}getIsRunning(){return this.loopService?.isRunning??!1}isPreset(e){return F(e)}async resolvePrompt(e,t){if(F(e))return be(e);if(!t)throw Error(`Custom prompt file requires readFile callback: ${e}`);return t(e)}getAvailablePresets(){return[...P]}resolveIterations(e){let{userIterations:t,preset:n,pendingTaskCount:r}=e;return t===void 0?n===`default`&&r!==void 0&&r>0?r:10:t}buildConfig(e){return{iterations:e.iterations??10,prompt:e.prompt??`default`,progressFile:e.progressFile??t.join(this.projectRoot,`.taskgraph`,`progress.txt`),sleepSeconds:e.sleepSeconds??5,tag:e.tag,sandbox:e.sandbox??!1,includeOutput:e.includeOutput??!1,verbose:e.verbose??!1,callbacks:e.callbacks}}},Se=class{detectFormat(e){return!e||typeof e!=`object`?`standard`:Object.keys(e).some(e=>e!==`tasks`&&e!==`metadata`)?`legacy`:`standard`}extractTasks(e,t){return e?this.detectFormat(e)===`legacy`?this.extractTasksFromLegacy(e,t):this.extractTasksFromStandard(e):[]}extractTasksFromLegacy(e,t){if(t in e)return e[t]?.tasks||[];let n=Object.keys(e).filter(e=>e!==`tasks`&&e!==`metadata`);return t===`master`&&n.length>0&&e[n[0]]?.tasks||[]}extractTasksFromStandard(e){return e?.tasks||[]}extractMetadata(e,t){return e?this.detectFormat(e)===`legacy`?this.extractMetadataFromLegacy(e,t):this.extractMetadataFromStandard(e):null}extractMetadataFromLegacy(e,t){if(t in e){let n=e[t];return!n?.metadata&&n?.tasks?this.generateMetadataFromTasks(n.tasks,t):n?.metadata||null}let n=Object.keys(e).filter(e=>e!==`tasks`&&e!==`metadata`);if(t===`master`&&n.length>0){let t=n[0],r=e[t];return!r?.metadata&&r?.tasks?this.generateMetadataFromTasks(r.tasks,t):r?.metadata||null}return null}extractMetadataFromStandard(e){return e?.metadata||null}extractTags(e){return e?this.detectFormat(e)===`legacy`?Object.keys(e).filter(e=>e!==`tasks`&&e!==`metadata`):[`master`]:[]}convertToSaveFormat(e,t,n,r){let i=r||`master`,a=this.normalizeTasks(e);return n&&this.detectFormat(n)===`legacy`?this.convertToLegacyFormat(a,t,i):this.convertToStandardFormat(a,t,r)}convertToLegacyFormat(e,t,n){return{[n]:{tasks:e,metadata:{...t,tags:[n]}}}}convertToStandardFormat(e,t,n){return{tasks:e,metadata:{...t,tags:n?[n]:[]}}}normalizeTasks(e){return e.map(e=>({...e,id:String(e.id),dependencies:e.dependencies?.map(e=>String(e))||[],subtasks:e.subtasks?.map(e=>({...e,id:Number(e.id),parentId:String(e.parentId)}))||[]}))}generateMetadataFromTasks(e,t){return{version:`1.0.0`,lastModified:new Date().toISOString(),taskCount:e.length,completedCount:e.filter(e=>e.status===`done`).length,tags:[t]}}};const L={stale:1e4,retries:{retries:5,factor:2,minTimeout:100,maxTimeout:1e3},realpath:!1};var Ce=class{writers=new Map;getWriter(e){let t=this.writers.get(e);return t||(t=new v(e),this.writers.set(e,t)),t}async readJson(e){try{let t=await i.readFile(e,`utf-8`);return JSON.parse(t)}catch(t){throw t.code===`ENOENT`?t:t instanceof SyntaxError?Error(`Invalid JSON in file ${e}: ${t.message}`):Error(`Failed to read file ${e}: ${t.message}`)}}async writeJson(e,t){await this.ensureFileExists(e);let n=null;try{n=await _.lock(e,L);let r=JSON.stringify(t,null,2);await this.getWriter(e).write(r)}finally{if(n)try{await n()}catch(t){(process.env.DEBUG||process.env.TASKGRAPH_DEBUG===`true`)&&console.warn(`[WARN] Lock release warning for ${e}: ${t.message}`)}}}async modifyJson(e,t){await this.ensureFileExists(e);let n=null;try{n=await _.lock(e,L);let r;try{let t=await i.readFile(e,`utf-8`);r=JSON.parse(t)}catch(t){if(t.code===`ENOENT`)r={};else if(t instanceof SyntaxError){let n=await i.readFile(e,`utf-8`).catch(()=>``);if(n.trim()===``||n.trim()===`{}`)r={};else throw Error(`Corrupted JSON in ${e}: ${t.message}. File contains: ${n.substring(0,100)}...`)}else throw Error(`Failed to read ${e} for modification: ${t.message}`)}let a=await t(r),o=JSON.stringify(a,null,2);await this.getWriter(e).write(o)}finally{if(n)try{await n()}catch(t){(process.env.DEBUG||process.env.TASKGRAPH_DEBUG===`true`)&&console.warn(`[WARN] Lock release warning for ${e}: ${t.message}`)}}}async ensureFileExists(e){let n=t.dirname(e);await i.mkdir(n,{recursive:!0});try{await i.writeFile(e,`{}`,{flag:`wx`})}catch(e){if(e.code!==`EEXIST`)throw e}}async exists(e){try{return await i.access(e,h.F_OK),!0}catch{return!1}}async getStats(e){return i.stat(e)}async readDir(e){return i.readdir(e)}async ensureDir(e){try{await i.mkdir(e,{recursive:!0})}catch(t){throw Error(`Failed to create directory ${e}: ${t.message}`)}}async deleteFile(e){try{await i.unlink(e)}catch(t){if(t.code!==`ENOENT`)throw Error(`Failed to delete file ${e}: ${t.message}`)}}async moveFile(e,t){try{await i.rename(e,t)}catch(n){throw Error(`Failed to move file from ${e} to ${t}: ${n.message}`)}}async copyFile(e,t){try{await i.copyFile(e,t)}catch(n){throw Error(`Failed to copy file from ${e} to ${t}: ${n.message}`)}}async cleanup(){this.writers.clear()}},we=class{basePath;tasksDir;tasksFilePath;constructor(e){this.basePath=t.join(e,`.taskgraph`),this.tasksDir=t.join(this.basePath,`tasks`),this.tasksFilePath=t.join(this.tasksDir,`tasks.json`)}getBasePath(){return this.basePath}getTasksDir(){return this.tasksDir}getTasksPath(){return this.tasksFilePath}};const R=E(`ComplexityReportManager`);var Te=class{projectRoot;reportCache=new Map;constructor(e){this.projectRoot=e}getReportPath(e){let t=c.join(this.projectRoot,`.taskgraph`,`reports`),n=e&&e!==`master`?`_${e}`:``;return c.join(t,`task-complexity-report${n}.json`)}async loadReport(e){let t=e||`master`,n=t;if(this.reportCache.has(n))return this.reportCache.get(n);let r=this.getReportPath(e);try{await i.access(r);let e=await i.readFile(r,`utf-8`),a=JSON.parse(e);return!a.meta||!Array.isArray(a.complexityAnalysis)?(R.warn(`Invalid complexity report structure at ${r}, ignoring`),null):(this.reportCache.set(n,a),R.debug(`Loaded complexity report for tag '${t}' with ${a.complexityAnalysis.length} analyses`),a)}catch(e){return e.code===`ENOENT`?(R.debug(`No complexity report found for tag '${t}'`),null):(R.warn(`Failed to load complexity report for tag '${t}': ${e.message}`),null)}}async getComplexityForTask(e,t){let n=await this.loadReport(t);if(!n)return null;let r=n.complexityAnalysis.find(t=>String(t.taskId)===String(e));return r?{complexityScore:r.complexityScore,recommendedSubtasks:r.recommendedSubtasks,expansionPrompt:r.expansionPrompt,complexityReasoning:r.complexityReasoning}:null}async getComplexityForTasks(e,t){let n=new Map,r=await this.loadReport(t);if(!r)return n;let i=new Map;return r.complexityAnalysis.forEach(e=>{i.set(String(e.taskId),e)}),e.forEach(e=>{let t=i.get(String(e));t&&n.set(String(e),{complexityScore:t.complexityScore,recommendedSubtasks:t.recommendedSubtasks,expansionPrompt:t.expansionPrompt,complexityReasoning:t.complexityReasoning})}),n}clearCache(e){e?this.reportCache.delete(e):this.reportCache.clear()}async hasReport(e){let t=this.getReportPath(e);try{return await i.access(t),!0}catch{return!1}}},Ee=class{formatHandler;fileOps;pathResolver;complexityManager;constructor(e){this.formatHandler=new Se,this.fileOps=new Ce,this.pathResolver=new we(e),this.complexityManager=new Te(e)}async initialize(){await this.fileOps.ensureDir(this.pathResolver.getTasksDir())}async close(){await this.fileOps.cleanup()}async getStats(){let e=this.pathResolver.getTasksPath();try{let t=await this.fileOps.getStats(e),n=await this.fileOps.readJson(e),r=this.formatHandler.extractTags(n),i=0,a=r.map(e=>{let r=this.formatHandler.extractTasks(n,e).length;return i+=r,{tag:e,taskCount:r,lastModified:t.mtime.toISOString()}});return{totalTasks:i,totalTags:r.length,lastModified:t.mtime.toISOString(),storageSize:0,tagStats:a}}catch(e){if(e.code===`ENOENT`)return{totalTasks:0,totalTags:0,lastModified:new Date().toISOString(),storageSize:0,tagStats:[]};throw Error(`Failed to get storage stats: ${e.message}`)}}async loadTasks(e,t){let n=this.pathResolver.getTasksPath(),r=e||`master`;try{let e=await this.fileOps.readJson(n),i=this.formatHandler.extractTasks(e,r);return t&&(t.status&&(i=i.filter(e=>e.status===t.status)),t.excludeSubtasks&&(i=i.map(e=>({...e,subtasks:[]})))),await this.enrichTasksWithComplexity(i,r)}catch(e){if(e.code===`ENOENT`)return[];throw Error(`Failed to load tasks: ${e.message}`)}}async loadTask(e,t){let n=await this.loadTasks(t);if(e.includes(`.`)){let[t,r]=e.split(`.`),i=n.find(e=>String(e.id)===t);if(!i||!i.subtasks)return null;let a=i.subtasks.find(e=>String(e.id)===r);if(!a)return null;let o=e=>{let t=String(e);return t.includes(`.`)?t:`${i.id}.${t}`},s=a.dependencies?.map(e=>o(e))??[];return{...a,id:e,title:a.title||`Subtask ${r}`,description:a.description||``,status:a.status||`pending`,priority:a.priority||i.priority||`medium`,dependencies:s,details:a.details||``,testStrategy:a.testStrategy||``,subtasks:[],tags:i.tags||[],assignee:a.assignee||i.assignee,complexity:a.complexity||i.complexity,createdAt:a.createdAt||i.createdAt,updatedAt:a.updatedAt||i.updatedAt,parentTask:{id:i.id,title:i.title,status:i.status},isSubtask:!0}}return n.find(t=>String(t.id)===String(e))||null}async saveTasks(e,t){let n=this.pathResolver.getTasksPath(),r=t||`master`;await this.fileOps.ensureDir(this.pathResolver.getTasksDir());let i={version:`1.0.0`,lastModified:new Date().toISOString(),taskCount:e.length,completedCount:e.filter(e=>e.status===`done`).length,tags:[r]},a=this.normalizeTaskIds(e);await this.fileOps.modifyJson(n,e=>this.formatHandler.detectFormat(e)===`legacy`||Object.keys(e).some(e=>e!==`tasks`&&e!==`metadata`)?(e[r]={tasks:a,metadata:i},e):r===`master`?{tasks:a,metadata:i}:{master:{tasks:e.tasks||[],metadata:e.metadata||i},[r]:{tasks:a,metadata:i}})}normalizeTaskIds(e){return e.map(e=>({...e,id:String(e.id),dependencies:e.dependencies?.map(e=>String(e))||[],subtasks:e.subtasks?.map(e=>({...e,id:Number(e.id),parentId:String(e.parentId)}))||[]}))}async exists(e){let t=this.pathResolver.getTasksPath();return this.fileOps.exists(t)}async getAllTags(){try{let e=this.pathResolver.getTasksPath(),t=await this.fileOps.readJson(e);return this.formatHandler.extractTags(t)}catch(e){if(e.code===`ENOENT`)return[];throw Error(`Failed to get tags: ${e.message}`)}}async loadMetadata(e){let t=this.pathResolver.getTasksPath(),n=e||`master`;try{let e=await this.fileOps.readJson(t);return this.formatHandler.extractMetadata(e,n)}catch(e){if(e.code===`ENOENT`)return null;throw Error(`Failed to load metadata: ${e.message}`)}}async saveMetadata(e,t){let n=await this.loadTasks(t);await this.saveTasks(n,t)}async appendTasks(e,t){let n=[...await this.loadTasks(t),...e];await this.saveTasks(n,t)}async updateTask(e,t,n){let r=await this.loadTasks(n),i=r.findIndex(t=>String(t.id)===String(e));if(i===-1)throw Error(`Task ${e} not found`);let a=r[i],o=t.subtasks;t.subtasks&&a.subtasks&&(o=t.subtasks.map(e=>{let t=a.subtasks?.find(t=>String(t.id)===String(e.id)||e.title&&t.title===e.title);return t?.metadata||e.metadata?{...e,metadata:{...t?.metadata||{},...e.metadata||{}}}:e})),r[i]={...a,...t,...o&&{subtasks:o},id:String(e)},await this.saveTasks(r,n)}async updateTaskStatus(e,t,n){let r=await this.loadTasks(n);if(e.includes(`.`))return this.updateSubtaskStatusInFile(r,e,t,n);let i=r.findIndex(t=>String(t.id)===String(e));if(i===-1)throw Error(`Task ${e} not found`);let a=r[i].status;return a===t?{success:!0,oldStatus:a,newStatus:t,taskId:String(e)}:(r[i]={...r[i],status:t,updatedAt:new Date().toISOString()},await this.saveTasks(r,n),{success:!0,oldStatus:a,newStatus:t,taskId:String(e)})}async updateSubtaskStatusInFile(e,t,n,r){let i=t.split(`.`);if(i.length!==2)throw Error(`Invalid subtask ID format: ${t}. Expected format: parentId.subtaskId`);let[a,o]=i,s=o.trim();if(!/^\d+$/.test(s))throw Error(`Invalid subtask ID: ${s}. Subtask ID must be a positive integer.`);let c=Number(s),l=e.findIndex(e=>String(e.id)===String(a));if(l===-1)throw Error(`Parent task ${a} not found`);let u=e[l],d=u.subtasks.findIndex(e=>e.id===c||String(e.id)===s);if(d===-1)throw Error(`Subtask ${t} not found in parent task ${a}`);let f=u.subtasks[d].status||`pending`;if(f===n)return{success:!0,oldStatus:f,newStatus:n,taskId:t};let p=new Date().toISOString();u.subtasks[d]={...u.subtasks[d],status:n,updatedAt:p};let m=u.subtasks,h=u.status;if(m.length>0){let e=e=>e.status||`pending`,t=t=>{let n=e(t);return n===`done`||n===`completed`},n=m.every(t),r=m.some(t=>e(t)===`in-progress`),i=m.some(t),a=m.every(t=>e(t)===`pending`);n?h=`done`:r||i?h=`in-progress`:a&&(h=`pending`)}return e[l]={...u,...h===u.status?{}:{status:h},updatedAt:p},await this.saveTasks(e,r),{success:!0,oldStatus:f,newStatus:n,taskId:t}}async deleteTask(e,t){let n=await this.loadTasks(t),r=n.filter(t=>String(t.id)!==String(e));if(r.length===n.length)throw Error(`Task ${e} not found`);await this.saveTasks(r,t)}async createTag(e,t){let n=this.pathResolver.getTasksPath();try{await this.fileOps.modifyJson(n,n=>{if(this.formatHandler.detectFormat(n)===`legacy`){if(e in n)throw new O(`Tag ${e} already exists`,D.VALIDATION_ERROR);let r=[];return t?.copyFrom&&t.copyFrom in n&&n[t.copyFrom].tasks&&(r=JSON.parse(JSON.stringify(n[t.copyFrom].tasks))),n[e]={tasks:r,metadata:{created:new Date().toISOString(),updatedAt:new Date().toISOString(),description:t?.description||`Tag created on ${new Date().toLocaleDateString()}`,tags:[e]}},n}else{let r=n.tasks||[],i=n.metadata||{},a=[];return(t?.copyFrom===`master`||!t?.copyFrom)&&(a=JSON.parse(JSON.stringify(r))),{master:{tasks:r,metadata:{...i,tags:[`master`]}},[e]:{tasks:a,metadata:{created:new Date().toISOString(),updatedAt:new Date().toISOString(),description:t?.description||`Tag created on ${new Date().toLocaleDateString()}`,tags:[e]}}}}})}catch(e){throw e.code===`ENOENT`?Error(`Tasks file not found - initialize project first`):e}}async deleteTag(e){let t=this.pathResolver.getTasksPath();try{let n=!1;await this.fileOps.modifyJson(t,t=>{if(this.formatHandler.detectFormat(t)!==`legacy`&&e===`master`)return n=!0,t;if(this.formatHandler.detectFormat(t)===`legacy`){if(e in t)return delete t[e],t;throw Error(`Tag ${e} not found`)}else throw Error(`Tag ${e} not found in standard format`)}),n&&await this.fileOps.deleteFile(t)}catch(t){throw t.code===`ENOENT`?Error(`Tag ${e} not found - file doesn't exist`):t}}async renameTag(e,t){let n=this.pathResolver.getTasksPath();try{await this.fileOps.modifyJson(n,n=>{if(this.formatHandler.detectFormat(n)===`legacy`){if(e in n)return n[t]=n[e],delete n[e],n[t].metadata&&(n[t].metadata.tags=[t]),n;throw Error(`Tag ${e} not found`)}else if(e===`master`){let e=n.tasks||[],r=n.metadata||{};return{[t]:{tasks:e,metadata:{...r,tags:[t]}}}}else throw Error(`Tag ${e} not found in standard format`)})}catch(t){throw t.code===`ENOENT`?Error(`Tag ${e} not found - file doesn't exist`):t}}async copyTag(e,t){let n=await this.loadTasks(e);if(n.length===0)throw Error(`Source tag ${e} not found or has no tasks`);await this.saveTasks(n,t)}async getTagsWithStats(){let e=await this.getAllTags(),t=await this.getActiveTagFromState(),n=await Promise.all(e.map(async e=>{try{let n=await this.loadTasks(e),r={},i=0,a={totalSubtasks:0,subtasksByStatus:{}};n.forEach(e=>{let t=e.status||`pending`;r[t]=(r[t]||0)+1,t===`done`&&i++,e.subtasks&&e.subtasks.length>0&&(a.totalSubtasks+=e.subtasks.length,e.subtasks.forEach(e=>{let t=e.status||`pending`;a.subtasksByStatus[t]=(a.subtasksByStatus[t]||0)+1}))});let o=await this.loadMetadata(e);return{name:e,isCurrent:e===t,taskCount:n.length,completedTasks:i,statusBreakdown:r,subtaskCounts:a.totalSubtasks>0?a:void 0,created:o?.created,description:o?.description}}catch{return{name:e,isCurrent:e===t,taskCount:0,completedTasks:0,statusBreakdown:{}}}}));return{tags:n,currentTag:t,totalTags:n.length}}async getActiveTagFromState(){try{let e=t.join(this.pathResolver.getBasePath(),`state.json`);return(await this.fileOps.readJson(e))?.currentTag||`master`}catch{return`master`}}async watch(e,t){let n=this.pathResolver.getTasksPath(),r=t?.debounceMs??100;if(!await this.fileOps.exists(n))throw new O(`Tasks file not found. Initialize the project first.`,D.NOT_FOUND,{path:n});let i,a=!1,o=m.watch(n,(t,n)=>{a||n&&t===`change`&&(i&&clearTimeout(i),i=setTimeout(()=>{a||e({type:`change`,timestamp:new Date})},r))});return o.on(`error`,t=>{a||e({type:`error`,timestamp:new Date,error:t})}),{unsubscribe:()=>{a=!0,i&&clearTimeout(i),o.close()}}}async enrichTasksWithComplexity(e,t){let n=e.map(e=>e.id),r=await this.complexityManager.getComplexityForTasks(n,t);return r.size===0?e:e.map(e=>{let t=r.get(String(e.id));return t?{...e,complexity:t.complexityScore,recommendedSubtasks:t.recommendedSubtasks,expansionPrompt:t.expansionPrompt,complexityReasoning:t.complexityReasoning}:e})}},De=class{static async createFromStorageConfig(e,t){return new Ee(e.basePath||t)}},Oe=class e{id;title;description;status;priority;dependencies;details;testStrategy;subtasks;createdAt;updatedAt;effort;actualEffort;tags;assignee;complexity;recommendedSubtasks;expansionPrompt;complexityReasoning;metadata;constructor(e){this.validate(e),this.id=String(e.id),this.title=e.title,this.description=e.description,this.status=e.status,this.priority=e.priority,this.dependencies=(e.dependencies||[]).map(e=>String(e)),this.details=e.details,this.testStrategy=e.testStrategy,this.subtasks=(e.subtasks||[]).map(e=>({...e,id:String(e.id),parentId:String(e.parentId)})),this.createdAt=e.createdAt,this.updatedAt=e.updatedAt,this.effort=e.effort,this.actualEffort=e.actualEffort,this.tags=e.tags,this.assignee=e.assignee,this.complexity=e.complexity,this.recommendedSubtasks=e.recommendedSubtasks,this.expansionPrompt=e.expansionPrompt,this.complexityReasoning=e.complexityReasoning,this.metadata=e.metadata}validate(e){if(e.id===void 0||e.id===null||typeof e.id!=`string`&&typeof e.id!=`number`)throw new O(`Task ID is required and must be a string or number`,D.VALIDATION_ERROR);if(!e.title||e.title.trim().length===0)throw new O(`Task title is required`,D.VALIDATION_ERROR);if(!e.description||e.description.trim().length===0)throw new O(`Task description is required`,D.VALIDATION_ERROR);if(!this.isValidStatus(e.status))throw new O(`Invalid task status: ${e.status}`,D.VALIDATION_ERROR);if(!this.isValidPriority(e.priority))throw new O(`Invalid task priority: ${e.priority}`,D.VALIDATION_ERROR)}isValidStatus(e){return[`pending`,`in-progress`,`done`,`deferred`,`cancelled`,`blocked`,`review`].includes(e)}isValidPriority(e){return[`low`,`medium`,`high`,`critical`].includes(e)}canComplete(){return this.status===`done`||this.status===`cancelled`||this.status===`blocked`?!1:this.subtasks.every(e=>e.status===`done`||e.status===`cancelled`)}markAsComplete(){if(!this.canComplete())throw new O(`Task cannot be marked as complete`,D.TASK_STATUS_ERROR,{taskId:this.id,currentStatus:this.status,hasIncompleteSubtasks:this.subtasks.some(e=>e.status!==`done`&&e.status!==`cancelled`)});this.status=`done`,this.updatedAt=new Date().toISOString()}hasDependencies(){return this.dependencies.length>0}hasSubtasks(){return this.subtasks.length>0}addSubtask(e){let t=this.subtasks.length+1;this.subtasks.push({...e,id:t,parentId:this.id}),this.updatedAt=new Date().toISOString()}updateStatus(e){if(!this.isValidStatus(e))throw new O(`Invalid status: ${e}`,D.VALIDATION_ERROR);if(this.status===`done`&&e===`pending`)throw new O(`Cannot move completed task back to pending`,D.TASK_STATUS_ERROR);this.status=e,this.updatedAt=new Date().toISOString()}toJSON(){return{id:this.id,title:this.title,description:this.description,status:this.status,priority:this.priority,dependencies:this.dependencies,details:this.details,testStrategy:this.testStrategy,subtasks:this.subtasks,createdAt:this.createdAt,updatedAt:this.updatedAt,effort:this.effort,actualEffort:this.actualEffort,tags:this.tags,assignee:this.assignee,complexity:this.complexity,recommendedSubtasks:this.recommendedSubtasks,expansionPrompt:this.expansionPrompt,complexityReasoning:this.complexityReasoning,metadata:this.metadata}}static fromObject(t){return new e(t)}static fromArray(t){return t.map(t=>new e(t))}},ke=class{configManager;storage;initialized=!1;logger=E(`TaskService`);constructor(e){this.configManager=e,this.storage=null}async initialize(){if(this.initialized)return;let e=this.configManager.getStorageConfig(),t=this.configManager.getProjectRoot();this.storage=await De.createFromStorageConfig(e,t),await this.storage.initialize(),this.initialized=!0}async getTaskList(e={}){let t=this.configManager.getActiveTag(),n=e.tag||t;try{let t=e.filter?.status&&!e.filter.priority&&!e.filter.tags&&!e.filter.assignee&&!e.filter.search&&e.filter.hasSubtasks===void 0,r={};if(t){let t=Array.isArray(e.filter.status)?e.filter.status:[e.filter.status];t.length===1&&(r.status=t[0])}e.includeSubtasks===!1&&(r.excludeSubtasks=!0);let i=await this.storage.loadTasks(n,r),a={};e.includeSubtasks===!1&&(a.excludeSubtasks=!0);let o=r.status===void 0?i:await this.storage.loadTasks(n,a),s=Oe.fromArray(i),c=s;return(e.filter&&!t||e.filter?.status&&Array.isArray(e.filter.status)&&e.filter.status.length>1)&&(c=this.applyFilters(s,e.filter)),{tasks:c.map(e=>e.toJSON()),total:o.length,filtered:c.length,tag:n}}catch(t){throw t instanceof O?t:(this.logger.error(`Failed to get task list`,t),new O(`Failed to get task list`,D.INTERNAL_ERROR,{operation:`getTaskList`,tag:n,hasFilter:!!e.filter},t))}}async getTask(e,t){let n=t||this.getActiveTag();try{return await this.storage.loadTask(String(e),n)}catch(t){throw t instanceof O?t:new O(`Failed to get task ${e}`,D.STORAGE_ERROR,{operation:`getTask`,resource:`task`,taskId:String(e),tag:n},t)}}async getTasksByStatus(e,t){let n=Array.isArray(e)?e:[e];return(await this.getTaskList({tag:t,filter:{status:n}})).tasks}async getTaskStats(e){let t=await this.getTaskList({tag:e,includeSubtasks:!0}),n={total:t.total,byStatus:{},withSubtasks:0,blocked:0};return[`pending`,`in-progress`,`done`,`deferred`,`cancelled`,`blocked`,`review`].forEach(e=>{n.byStatus[e]=0}),t.tasks.forEach(e=>{n.byStatus[e.status]++,e.subtasks&&e.subtasks.length>0&&n.withSubtasks++,e.status===`blocked`&&n.blocked++}),n}async getNextTask(e){let t=(await this.getTaskList({tag:e,filter:{status:[`pending`,`in-progress`,`done`]}})).tasks,n={critical:4,high:3,medium:2,low:1},r=(e,t)=>typeof t==`string`&&t.includes(`.`)?t:`${e}.${t}`,i=new Set;t.forEach(e=>{e.status===`done`&&i.add(String(e.id)),Array.isArray(e.subtasks)&&e.subtasks.forEach(t=>{t.status===`done`&&i.add(`${e.id}.${t.id}`)})});let a=[];if(t.filter(e=>e.status===`in-progress`&&Array.isArray(e.subtasks)).forEach(e=>{e.subtasks.forEach(t=>{let n=(t.status||`pending`).toLowerCase();if(n!==`pending`&&n!==`in-progress`)return;let o=t.dependencies?.map(t=>r(String(e.id),t))??[];(o.length===0||o.every(e=>i.has(String(e))))&&a.push({id:`${e.id}.${t.id}`,title:t.title||`Subtask ${t.id}`,status:t.status||`pending`,priority:t.priority||e.priority||`medium`,dependencies:o,parentId:String(e.id),description:t.description,details:t.details,testStrategy:t.testStrategy,subtasks:[]})})}),a.length>0)return a.sort((e,t)=>{let r=n[e.priority]??2,i=n[t.priority]??2;if(i!==r)return i-r;if(e.dependencies.length!==t.dependencies.length)return e.dependencies.length-t.dependencies.length;let[a,o]=String(e.id).split(`.`).map(Number),[s,c]=String(t.id).split(`.`).map(Number);return a===s?o-c:a-s}),a[0];let o=t.filter(e=>{let t=(e.status||`pending`).toLowerCase();return t!==`pending`&&t!==`in-progress`?!1:(e.dependencies??[]).every(e=>i.has(String(e)))});return o.length===0?null:o.sort((e,t)=>{let r=n[e.priority]??2,i=n[t.priority]??2;if(i!==r)return i-r;let a=(e.dependencies??[]).length,o=(t.dependencies??[]).length;return a===o?Number(e.id)-Number(t.id):a-o})[0]}applyFilters(e,t){return e.filter(e=>{if(t.status&&!(Array.isArray(t.status)?t.status:[t.status]).includes(e.status)||t.priority&&!(Array.isArray(t.priority)?t.priority:[t.priority]).includes(e.priority)||t.tags&&t.tags.length>0&&(!e.tags||!t.tags.some(t=>e.tags?.includes(t)))||t.assignee&&e.assignee!==t.assignee)return!1;if(t.search){let n=t.search.toLowerCase(),r=e.title.toLowerCase().includes(n),i=e.description.toLowerCase().includes(n),a=e.details.toLowerCase().includes(n);if(!r&&!i&&!a)return!1}return!(t.hasSubtasks!==void 0&&e.subtasks.length>0!==t.hasSubtasks)})}getStorage(){return this.storage}getActiveTag(){return this.configManager.getActiveTag()}async setActiveTag(e){await this.configManager.setActiveTag(e)}async updateTask(e,t,n){if(!this.storage)throw new O(`Storage not initialized`,D.STORAGE_ERROR);this.initialized||await this.initialize();let r=n||this.getActiveTag(),i=String(e);try{await this.storage.updateTask(i,t,r)}catch(t){throw t instanceof O?t:new O(`Failed to update task ${e}`,D.STORAGE_ERROR,{operation:`updateTask`,resource:`task`,taskId:i,tag:r},t)}}async updateTaskStatus(e,t,n){if(!this.storage)throw new O(`Storage not initialized`,D.STORAGE_ERROR);let r=n||this.getActiveTag(),i=String(e);try{return await this.storage.updateTaskStatus(i,t,r)}catch(e){throw e instanceof O?e:new O(`Failed to update task status for ${i}`,D.STORAGE_ERROR,{operation:`updateTaskStatus`,resource:`task`,taskId:i,newStatus:t,tag:r},e)}}async getTagsWithStats(){if(!this.storage)throw new O(`Storage not initialized`,D.STORAGE_ERROR);this.initialized||await this.initialize();try{return await this.storage.getTagsWithStats()}catch(e){throw e instanceof O?e:new O(`Failed to get tags with stats`,D.STORAGE_ERROR,{operation:`getTagsWithStats`,resource:`tags`},e)}}async close(){this.storage&&await this.storage.close(),this.initialized=!1}},Ae=class{constructor(e){this.taskService=e}async startTask(e,t={}){try{let{parentId:n,subtaskId:r}=this.parseTaskId(e);if(!t.force){let t=await this.checkInProgressConflicts(e);if(!t.canProceed)return{task:null,found:!1,started:!1,error:`Conflicting tasks in progress: ${t.conflictingTasks.map(e=>`#${e.id}: ${e.title}`).join(`, `)}`}}let i=await this.taskService.getTask(n);if(!i)return{task:null,found:!1,started:!1,error:`Task ${n} not found`};let a;if(r&&i.subtasks&&(a=i.subtasks.find(e=>String(e.id)===r)),t.updateStatus&&!t.dryRun)try{await this.taskService.updateTaskStatus(n,`in-progress`)}catch(e){console.warn(`Could not update task status: ${e instanceof Error?e.message:String(e)}`)}let o=!1,s=`Task ready to execute`,c;return t.dryRun?(o=!0,s=`Dry run - task would be executed`,c=await this.prepareExecutionCommand(i,a)):(c=await this.prepareExecutionCommand(i,a),o=!!c,s=c?`Command prepared: ${c.executable} ${c.args.join(` `)}`:`Failed to prepare execution command`),{task:i,found:!0,started:o,subtaskId:r,subtask:a,executionOutput:s,command:c||void 0}}catch(e){return{task:null,found:!1,started:!1,error:e instanceof Error?e.message:String(e)}}}async checkInProgressConflicts(e){let t=(await this.taskService.getTaskList()).tasks.filter(e=>e.status===`in-progress`);if(t.find(t=>t.id===e))return{canProceed:!0,conflictingTasks:[]};let n=e.includes(`.`);if(n){let n=e.split(`.`)[0];if(t.find(e=>e.id===n))return{canProceed:!0,conflictingTasks:[]}}let r=t.filter(t=>{if(t.id===e)return!1;if(n){let n=e.split(`.`)[0];if(t.id===n)return!1}if(t.id.toString().includes(`.`)){let r=t.id.toString().split(`.`)[0];if(n&&r===e.split(`.`)[0])return!1}return!0});return r.length>0?{canProceed:!1,conflictingTasks:r,reason:`Other tasks are already in progress`}:{canProceed:!0,conflictingTasks:[]}}async getNextAvailableTask(){return(await this.taskService.getNextTask())?.id||null}parseTaskId(e){if(e.includes(`.`)){let[t,n]=e.split(`.`);return{parentId:t,subtaskId:n}}return{parentId:e}}async canStartTask(e,t=!1){return t?!0:(await this.checkInProgressConflicts(e)).canProceed}async prepareExecutionCommand(e,t){try{return{executable:`claude`,args:[this.formatTaskPrompt(e,t)],cwd:process.cwd()}}catch(e){return console.warn(`Failed to prepare execution command: ${e instanceof Error?e.message:String(e)}`),null}}formatTaskPrompt(e,t){let n=t||e,r=t?`Subtask`:`Task`,i=`${r} #${t?`${e.id}.${t.id}`:e.id}: ${n.title}\n\n`;return n.description&&(i+=`Description:\n${n.description}\n\n`),n.details&&(i+=`Implementation Details:\n${n.details}\n\n`),n.testStrategy&&(i+=`Test Strategy:\n${n.testStrategy}\n\n`),e.dependencies&&e.dependencies.length>0&&(i+=`Dependencies: ${e.dependencies.join(`, `)}\n\n`),i+=`Please help me implement this ${r.toLowerCase()}.`,i}async getTaskWithSubtask(e){let{parentId:t,subtaskId:n}=this.parseTaskId(e),r=await this.taskService.getTask(t);return r?n&&r.subtasks?{task:r,subtask:r.subtasks.find(e=>String(e.id)===n),subtaskId:n}:{task:r}:{task:null}}},je=`taskgraph-ai`,Me=`0.50.1`;const z={CLAUDE_CODE:`claude-code`},B=Object.values(z);[...B];const V=`.taskgraph/tasks/tasks.json`,H=[`.taskgraph`,`.taskgraph/config.json`,V],U=`.git,.svn,.hg,.fossil,.github,.gitlab,.circleci,.travis.yml,.jenkins,.buildkite,.vscode,.idea,.project,.devcontainer,package-lock.json,yarn.lock,pnpm-lock.yaml,bun.lockb,bun.lock,deno.lock,deno.json,deno.jsonc,package.json,lerna.json,nx.json,turbo.json,rush.json,pnpm-workspace.yaml,Cargo.toml,Cargo.lock,go.mod,go.sum,go.work,pyproject.toml,setup.py,setup.cfg,poetry.lock,Pipfile,Pipfile.lock,uv.lock,Gemfile,Gemfile.lock,composer.json,composer.lock,build.gradle,build.gradle.kts,settings.gradle,settings.gradle.kts,pom.xml,build.sbt,project.clj,deps.edn,mix.exs,rebar.config,pubspec.yaml,Package.swift,CMakeLists.txt,Makefile,meson.build,BUILD.bazel,WORKSPACE,flake.nix,shell.nix,default.nix,Dockerfile,docker-compose.yml,docker-compose.yaml,Containerfile,kubernetes.yml,kubernetes.yaml,helm/Chart.yaml`.split(`,`),Ne=[`tasks.json`,...U,`requirements.txt`];[...H,...Ne];const W=[`pending`,`in-progress`,`done`,`deferred`,`cancelled`,`blocked`,`review`],Pe=[`done`,`completed`,`cancelled`];function G(e){return Pe.includes(e)}const Fe=[`text`,`json`,`compact`],Ie={done:`✓`,completed:`✓`,"in-progress":`►`,blocked:`⭕`,pending:`○`,deferred:`⏸`,cancelled:`✗`,review:`👁`},K=E(`TaskLoader`);var Le=class{taskService;constructor(e){if(!e)throw Error(`taskService is required for TaskLoaderService`);this.taskService=e}async loadAndValidateTask(e){K.info(`Loading task ${e}...`);let t=await this.loadTask(e);if(!t)return{success:!1,errorType:`task_not_found`,errorMessage:`Task with ID "${e}" not found`,suggestion:`Use "taskgraph list" to see available tasks or verify the task ID is correct.`};let n=this.validateTaskStatus(t);if(!n.success)return n;let r=this.validateSubtasksExist(t);if(!r.success)return r;let i=this.validateSubtaskStructure(t);if(!i.success)return i;let a=this.validateDependencies(t);return a.success?(K.info(`Task ${e} validated successfully`),{success:!0,task:t}):a}async loadTask(e){try{return await this.taskService.getTask(e)}catch(t){return K.error(`Failed to load task ${e}:`,t),null}}validateTaskStatus(e){return G(e.status)?{success:!1,errorType:`task_completed`,errorMessage:`Task "${e.title}" is already ${e.status}`,suggestion:`Autopilot can only execute tasks that are pending or in-progress. Use a different task.`}:{success:!0}}validateSubtasksExist(e){return!e.subtasks||e.subtasks.length===0?{success:!1,errorType:`no_subtasks`,errorMessage:`Task "${e.title}" has no subtasks`,suggestion:this.buildExpansionSuggestion(e)}:{success:!0}}buildExpansionSuggestion(e){let t=[`Autopilot requires tasks to be broken down into subtasks for execution.`];return t.push(`
178
+ `);return{complete:n.slice(0,-1),remaining:n[n.length-1]}}},xe=class{logger=E(`LoopDomain`);loopService=null;projectRoot;constructor(e){this.projectRoot=e.getProjectRoot()}checkSandboxAuth(){return new I({projectRoot:this.projectRoot}).checkSandboxAuth()}runInteractiveAuth(){return new I({projectRoot:this.projectRoot}).runInteractiveAuth()}async run(e){if(this.loopService?.isRunning)try{this.loopService.stop()}catch(e){this.logger.warn(`Failed to stop previous loop service:`,e)}let t=this.buildConfig(e);return this.loopService=new I({projectRoot:this.projectRoot}),this.loopService.run(t)}stop(){this.loopService&&=(this.loopService.stop(),null)}getIsRunning(){return this.loopService?.isRunning??!1}isPreset(e){return F(e)}async resolvePrompt(e,t){if(F(e))return be(e);if(!t)throw Error(`Custom prompt file requires readFile callback: ${e}`);return t(e)}getAvailablePresets(){return[...P]}resolveIterations(e){let{userIterations:t,preset:n,pendingTaskCount:r}=e;return t===void 0?n===`default`&&r!==void 0&&r>0?r:10:t}buildConfig(e){return{iterations:e.iterations??10,prompt:e.prompt??`default`,progressFile:e.progressFile??t.join(this.projectRoot,`.taskgraph`,`progress.txt`),sleepSeconds:e.sleepSeconds??5,tag:e.tag,sandbox:e.sandbox??!1,includeOutput:e.includeOutput??!1,verbose:e.verbose??!1,callbacks:e.callbacks}}},Se=class{detectFormat(e){return!e||typeof e!=`object`?`standard`:Object.keys(e).some(e=>e!==`tasks`&&e!==`metadata`)?`legacy`:`standard`}extractTasks(e,t){return e?this.detectFormat(e)===`legacy`?this.extractTasksFromLegacy(e,t):this.extractTasksFromStandard(e):[]}extractTasksFromLegacy(e,t){if(t in e)return e[t]?.tasks||[];let n=Object.keys(e).filter(e=>e!==`tasks`&&e!==`metadata`);return t===`master`&&n.length>0&&e[n[0]]?.tasks||[]}extractTasksFromStandard(e){return e?.tasks||[]}extractMetadata(e,t){return e?this.detectFormat(e)===`legacy`?this.extractMetadataFromLegacy(e,t):this.extractMetadataFromStandard(e):null}extractMetadataFromLegacy(e,t){if(t in e){let n=e[t];return!n?.metadata&&n?.tasks?this.generateMetadataFromTasks(n.tasks,t):n?.metadata||null}let n=Object.keys(e).filter(e=>e!==`tasks`&&e!==`metadata`);if(t===`master`&&n.length>0){let t=n[0],r=e[t];return!r?.metadata&&r?.tasks?this.generateMetadataFromTasks(r.tasks,t):r?.metadata||null}return null}extractMetadataFromStandard(e){return e?.metadata||null}extractTags(e){return e?this.detectFormat(e)===`legacy`?Object.keys(e).filter(e=>e!==`tasks`&&e!==`metadata`):[`master`]:[]}convertToSaveFormat(e,t,n,r){let i=r||`master`,a=this.normalizeTasks(e);return n&&this.detectFormat(n)===`legacy`?this.convertToLegacyFormat(a,t,i):this.convertToStandardFormat(a,t,r)}convertToLegacyFormat(e,t,n){return{[n]:{tasks:e,metadata:{...t,tags:[n]}}}}convertToStandardFormat(e,t,n){return{tasks:e,metadata:{...t,tags:n?[n]:[]}}}normalizeTasks(e){return e.map(e=>({...e,id:String(e.id),dependencies:e.dependencies?.map(e=>String(e))||[],subtasks:e.subtasks?.map(e=>({...e,id:Number(e.id),parentId:String(e.parentId)}))||[]}))}generateMetadataFromTasks(e,t){return{version:`1.0.0`,lastModified:new Date().toISOString(),taskCount:e.length,completedCount:e.filter(e=>e.status===`done`).length,tags:[t]}}};const L={stale:1e4,retries:{retries:5,factor:2,minTimeout:100,maxTimeout:1e3},realpath:!1};var Ce=class{writers=new Map;getWriter(e){let t=this.writers.get(e);return t||(t=new v(e),this.writers.set(e,t)),t}async readJson(e){try{let t=await i.readFile(e,`utf-8`);return JSON.parse(t)}catch(t){throw t.code===`ENOENT`?t:t instanceof SyntaxError?Error(`Invalid JSON in file ${e}: ${t.message}`):Error(`Failed to read file ${e}: ${t.message}`)}}async writeJson(e,t){await this.ensureFileExists(e);let n=null;try{n=await _.lock(e,L);let r=JSON.stringify(t,null,2);await this.getWriter(e).write(r)}finally{if(n)try{await n()}catch(t){(process.env.DEBUG||process.env.TASKGRAPH_DEBUG===`true`)&&console.warn(`[WARN] Lock release warning for ${e}: ${t.message}`)}}}async modifyJson(e,t){await this.ensureFileExists(e);let n=null;try{n=await _.lock(e,L);let r;try{let t=await i.readFile(e,`utf-8`);r=JSON.parse(t)}catch(t){if(t.code===`ENOENT`)r={};else if(t instanceof SyntaxError){let n=await i.readFile(e,`utf-8`).catch(()=>``);if(n.trim()===``||n.trim()===`{}`)r={};else throw Error(`Corrupted JSON in ${e}: ${t.message}. File contains: ${n.substring(0,100)}...`)}else throw Error(`Failed to read ${e} for modification: ${t.message}`)}let a=await t(r),o=JSON.stringify(a,null,2);await this.getWriter(e).write(o)}finally{if(n)try{await n()}catch(t){(process.env.DEBUG||process.env.TASKGRAPH_DEBUG===`true`)&&console.warn(`[WARN] Lock release warning for ${e}: ${t.message}`)}}}async ensureFileExists(e){let n=t.dirname(e);await i.mkdir(n,{recursive:!0});try{await i.writeFile(e,`{}`,{flag:`wx`})}catch(e){if(e.code!==`EEXIST`)throw e}}async exists(e){try{return await i.access(e,h.F_OK),!0}catch{return!1}}async getStats(e){return i.stat(e)}async readDir(e){return i.readdir(e)}async ensureDir(e){try{await i.mkdir(e,{recursive:!0})}catch(t){throw Error(`Failed to create directory ${e}: ${t.message}`)}}async deleteFile(e){try{await i.unlink(e)}catch(t){if(t.code!==`ENOENT`)throw Error(`Failed to delete file ${e}: ${t.message}`)}}async moveFile(e,t){try{await i.rename(e,t)}catch(n){throw Error(`Failed to move file from ${e} to ${t}: ${n.message}`)}}async copyFile(e,t){try{await i.copyFile(e,t)}catch(n){throw Error(`Failed to copy file from ${e} to ${t}: ${n.message}`)}}async cleanup(){this.writers.clear()}},we=class{basePath;tasksDir;tasksFilePath;constructor(e){this.basePath=t.join(e,`.taskgraph`),this.tasksDir=t.join(this.basePath,`tasks`),this.tasksFilePath=t.join(this.tasksDir,`tasks.json`)}getBasePath(){return this.basePath}getTasksDir(){return this.tasksDir}getTasksPath(){return this.tasksFilePath}};const R=E(`ComplexityReportManager`);var Te=class{projectRoot;reportCache=new Map;constructor(e){this.projectRoot=e}getReportPath(e){let t=c.join(this.projectRoot,`.taskgraph`,`reports`),n=e&&e!==`master`?`_${e}`:``;return c.join(t,`task-complexity-report${n}.json`)}async loadReport(e){let t=e||`master`,n=t;if(this.reportCache.has(n))return this.reportCache.get(n);let r=this.getReportPath(e);try{await i.access(r);let e=await i.readFile(r,`utf-8`),a=JSON.parse(e);return!a.meta||!Array.isArray(a.complexityAnalysis)?(R.warn(`Invalid complexity report structure at ${r}, ignoring`),null):(this.reportCache.set(n,a),R.debug(`Loaded complexity report for tag '${t}' with ${a.complexityAnalysis.length} analyses`),a)}catch(e){return e.code===`ENOENT`?(R.debug(`No complexity report found for tag '${t}'`),null):(R.warn(`Failed to load complexity report for tag '${t}': ${e.message}`),null)}}async getComplexityForTask(e,t){let n=await this.loadReport(t);if(!n)return null;let r=n.complexityAnalysis.find(t=>String(t.taskId)===String(e));return r?{complexityScore:r.complexityScore,recommendedSubtasks:r.recommendedSubtasks,expansionPrompt:r.expansionPrompt,complexityReasoning:r.complexityReasoning}:null}async getComplexityForTasks(e,t){let n=new Map,r=await this.loadReport(t);if(!r)return n;let i=new Map;return r.complexityAnalysis.forEach(e=>{i.set(String(e.taskId),e)}),e.forEach(e=>{let t=i.get(String(e));t&&n.set(String(e),{complexityScore:t.complexityScore,recommendedSubtasks:t.recommendedSubtasks,expansionPrompt:t.expansionPrompt,complexityReasoning:t.complexityReasoning})}),n}clearCache(e){e?this.reportCache.delete(e):this.reportCache.clear()}async hasReport(e){let t=this.getReportPath(e);try{return await i.access(t),!0}catch{return!1}}},Ee=class{formatHandler;fileOps;pathResolver;complexityManager;constructor(e){this.formatHandler=new Se,this.fileOps=new Ce,this.pathResolver=new we(e),this.complexityManager=new Te(e)}async initialize(){await this.fileOps.ensureDir(this.pathResolver.getTasksDir())}async close(){await this.fileOps.cleanup()}async getStats(){let e=this.pathResolver.getTasksPath();try{let t=await this.fileOps.getStats(e),n=await this.fileOps.readJson(e),r=this.formatHandler.extractTags(n),i=0,a=r.map(e=>{let r=this.formatHandler.extractTasks(n,e).length;return i+=r,{tag:e,taskCount:r,lastModified:t.mtime.toISOString()}});return{totalTasks:i,totalTags:r.length,lastModified:t.mtime.toISOString(),storageSize:0,tagStats:a}}catch(e){if(e.code===`ENOENT`)return{totalTasks:0,totalTags:0,lastModified:new Date().toISOString(),storageSize:0,tagStats:[]};throw Error(`Failed to get storage stats: ${e.message}`)}}async loadTasks(e,t){let n=this.pathResolver.getTasksPath(),r=e||`master`;try{let e=await this.fileOps.readJson(n),i=this.formatHandler.extractTasks(e,r);return t&&(t.status&&(i=i.filter(e=>e.status===t.status)),t.excludeSubtasks&&(i=i.map(e=>({...e,subtasks:[]})))),await this.enrichTasksWithComplexity(i,r)}catch(e){if(e.code===`ENOENT`)return[];throw Error(`Failed to load tasks: ${e.message}`)}}async loadTask(e,t){let n=await this.loadTasks(t);if(e.includes(`.`)){let[t,r]=e.split(`.`),i=n.find(e=>String(e.id)===t);if(!i||!i.subtasks)return null;let a=i.subtasks.find(e=>String(e.id)===r);if(!a)return null;let o=e=>{let t=String(e);return t.includes(`.`)?t:`${i.id}.${t}`},s=a.dependencies?.map(e=>o(e))??[];return{...a,id:e,title:a.title||`Subtask ${r}`,description:a.description||``,status:a.status||`pending`,priority:a.priority||i.priority||`medium`,dependencies:s,details:a.details||``,testStrategy:a.testStrategy||``,subtasks:[],tags:i.tags||[],assignee:a.assignee||i.assignee,complexity:a.complexity||i.complexity,createdAt:a.createdAt||i.createdAt,updatedAt:a.updatedAt||i.updatedAt,parentTask:{id:i.id,title:i.title,status:i.status},isSubtask:!0}}return n.find(t=>String(t.id)===String(e))||null}async saveTasks(e,t){let n=this.pathResolver.getTasksPath(),r=t||`master`;await this.fileOps.ensureDir(this.pathResolver.getTasksDir());let i={version:`1.0.0`,lastModified:new Date().toISOString(),taskCount:e.length,completedCount:e.filter(e=>e.status===`done`).length,tags:[r]},a=this.normalizeTaskIds(e);await this.fileOps.modifyJson(n,e=>this.formatHandler.detectFormat(e)===`legacy`||Object.keys(e).some(e=>e!==`tasks`&&e!==`metadata`)?(e[r]={tasks:a,metadata:i},e):r===`master`?{tasks:a,metadata:i}:{master:{tasks:e.tasks||[],metadata:e.metadata||i},[r]:{tasks:a,metadata:i}})}normalizeTaskIds(e){return e.map(e=>({...e,id:String(e.id),dependencies:e.dependencies?.map(e=>String(e))||[],subtasks:e.subtasks?.map(e=>({...e,id:Number(e.id),parentId:String(e.parentId)}))||[]}))}async exists(e){let t=this.pathResolver.getTasksPath();return this.fileOps.exists(t)}async getAllTags(){try{let e=this.pathResolver.getTasksPath(),t=await this.fileOps.readJson(e);return this.formatHandler.extractTags(t)}catch(e){if(e.code===`ENOENT`)return[];throw Error(`Failed to get tags: ${e.message}`)}}async loadMetadata(e){let t=this.pathResolver.getTasksPath(),n=e||`master`;try{let e=await this.fileOps.readJson(t);return this.formatHandler.extractMetadata(e,n)}catch(e){if(e.code===`ENOENT`)return null;throw Error(`Failed to load metadata: ${e.message}`)}}async saveMetadata(e,t){let n=await this.loadTasks(t);await this.saveTasks(n,t)}async appendTasks(e,t){let n=[...await this.loadTasks(t),...e];await this.saveTasks(n,t)}async updateTask(e,t,n){let r=await this.loadTasks(n),i=r.findIndex(t=>String(t.id)===String(e));if(i===-1)throw Error(`Task ${e} not found`);let a=r[i],o=t.subtasks;t.subtasks&&a.subtasks&&(o=t.subtasks.map(e=>{let t=a.subtasks?.find(t=>String(t.id)===String(e.id)||e.title&&t.title===e.title);return t?.metadata||e.metadata?{...e,metadata:{...t?.metadata||{},...e.metadata||{}}}:e})),r[i]={...a,...t,...o&&{subtasks:o},id:String(e)},await this.saveTasks(r,n)}async updateTaskStatus(e,t,n){let r=await this.loadTasks(n);if(e.includes(`.`))return this.updateSubtaskStatusInFile(r,e,t,n);let i=r.findIndex(t=>String(t.id)===String(e));if(i===-1)throw Error(`Task ${e} not found`);let a=r[i].status;return a===t?{success:!0,oldStatus:a,newStatus:t,taskId:String(e)}:(r[i]={...r[i],status:t,updatedAt:new Date().toISOString()},await this.saveTasks(r,n),{success:!0,oldStatus:a,newStatus:t,taskId:String(e)})}async updateSubtaskStatusInFile(e,t,n,r){let i=t.split(`.`);if(i.length!==2)throw Error(`Invalid subtask ID format: ${t}. Expected format: parentId.subtaskId`);let[a,o]=i,s=o.trim();if(!/^\d+$/.test(s))throw Error(`Invalid subtask ID: ${s}. Subtask ID must be a positive integer.`);let c=Number(s),l=e.findIndex(e=>String(e.id)===String(a));if(l===-1)throw Error(`Parent task ${a} not found`);let u=e[l],d=u.subtasks.findIndex(e=>e.id===c||String(e.id)===s);if(d===-1)throw Error(`Subtask ${t} not found in parent task ${a}`);let f=u.subtasks[d].status||`pending`;if(f===n)return{success:!0,oldStatus:f,newStatus:n,taskId:t};let p=new Date().toISOString();u.subtasks[d]={...u.subtasks[d],status:n,updatedAt:p};let m=u.subtasks,h=u.status;if(m.length>0){let e=e=>e.status||`pending`,t=t=>{let n=e(t);return n===`done`||n===`completed`},n=m.every(t),r=m.some(t=>e(t)===`in-progress`),i=m.some(t),a=m.every(t=>e(t)===`pending`);n?h=`done`:r||i?h=`in-progress`:a&&(h=`pending`)}return e[l]={...u,...h===u.status?{}:{status:h},updatedAt:p},await this.saveTasks(e,r),{success:!0,oldStatus:f,newStatus:n,taskId:t}}async deleteTask(e,t){let n=await this.loadTasks(t),r=n.filter(t=>String(t.id)!==String(e));if(r.length===n.length)throw Error(`Task ${e} not found`);await this.saveTasks(r,t)}async createTag(e,t){let n=this.pathResolver.getTasksPath();try{await this.fileOps.modifyJson(n,n=>{if(this.formatHandler.detectFormat(n)===`legacy`){if(e in n)throw new O(`Tag ${e} already exists`,D.VALIDATION_ERROR);let r=[];return t?.copyFrom&&t.copyFrom in n&&n[t.copyFrom].tasks&&(r=JSON.parse(JSON.stringify(n[t.copyFrom].tasks))),n[e]={tasks:r,metadata:{created:new Date().toISOString(),updatedAt:new Date().toISOString(),description:t?.description||`Tag created on ${new Date().toLocaleDateString()}`,tags:[e]}},n}else{let r=n.tasks||[],i=n.metadata||{},a=[];return(t?.copyFrom===`master`||!t?.copyFrom)&&(a=JSON.parse(JSON.stringify(r))),{master:{tasks:r,metadata:{...i,tags:[`master`]}},[e]:{tasks:a,metadata:{created:new Date().toISOString(),updatedAt:new Date().toISOString(),description:t?.description||`Tag created on ${new Date().toLocaleDateString()}`,tags:[e]}}}}})}catch(e){throw e.code===`ENOENT`?Error(`Tasks file not found - initialize project first`):e}}async deleteTag(e){let t=this.pathResolver.getTasksPath();try{let n=!1;await this.fileOps.modifyJson(t,t=>{if(this.formatHandler.detectFormat(t)!==`legacy`&&e===`master`)return n=!0,t;if(this.formatHandler.detectFormat(t)===`legacy`){if(e in t)return delete t[e],t;throw Error(`Tag ${e} not found`)}else throw Error(`Tag ${e} not found in standard format`)}),n&&await this.fileOps.deleteFile(t)}catch(t){throw t.code===`ENOENT`?Error(`Tag ${e} not found - file doesn't exist`):t}}async renameTag(e,t){let n=this.pathResolver.getTasksPath();try{await this.fileOps.modifyJson(n,n=>{if(this.formatHandler.detectFormat(n)===`legacy`){if(e in n)return n[t]=n[e],delete n[e],n[t].metadata&&(n[t].metadata.tags=[t]),n;throw Error(`Tag ${e} not found`)}else if(e===`master`){let e=n.tasks||[],r=n.metadata||{};return{[t]:{tasks:e,metadata:{...r,tags:[t]}}}}else throw Error(`Tag ${e} not found in standard format`)})}catch(t){throw t.code===`ENOENT`?Error(`Tag ${e} not found - file doesn't exist`):t}}async copyTag(e,t){let n=await this.loadTasks(e);if(n.length===0)throw Error(`Source tag ${e} not found or has no tasks`);await this.saveTasks(n,t)}async getTagsWithStats(){let e=await this.getAllTags(),t=await this.getActiveTagFromState(),n=await Promise.all(e.map(async e=>{try{let n=await this.loadTasks(e),r={},i=0,a={totalSubtasks:0,subtasksByStatus:{}};n.forEach(e=>{let t=e.status||`pending`;r[t]=(r[t]||0)+1,t===`done`&&i++,e.subtasks&&e.subtasks.length>0&&(a.totalSubtasks+=e.subtasks.length,e.subtasks.forEach(e=>{let t=e.status||`pending`;a.subtasksByStatus[t]=(a.subtasksByStatus[t]||0)+1}))});let o=await this.loadMetadata(e);return{name:e,isCurrent:e===t,taskCount:n.length,completedTasks:i,statusBreakdown:r,subtaskCounts:a.totalSubtasks>0?a:void 0,created:o?.created,description:o?.description}}catch{return{name:e,isCurrent:e===t,taskCount:0,completedTasks:0,statusBreakdown:{}}}}));return{tags:n,currentTag:t,totalTags:n.length}}async getActiveTagFromState(){try{let e=t.join(this.pathResolver.getBasePath(),`state.json`);return(await this.fileOps.readJson(e))?.currentTag||`master`}catch{return`master`}}async watch(e,t){let n=this.pathResolver.getTasksPath(),r=t?.debounceMs??100;if(!await this.fileOps.exists(n))throw new O(`Tasks file not found. Initialize the project first.`,D.NOT_FOUND,{path:n});let i,a=!1,o=m.watch(n,(t,n)=>{a||n&&t===`change`&&(i&&clearTimeout(i),i=setTimeout(()=>{a||e({type:`change`,timestamp:new Date})},r))});return o.on(`error`,t=>{a||e({type:`error`,timestamp:new Date,error:t})}),{unsubscribe:()=>{a=!0,i&&clearTimeout(i),o.close()}}}async enrichTasksWithComplexity(e,t){let n=e.map(e=>e.id),r=await this.complexityManager.getComplexityForTasks(n,t);return r.size===0?e:e.map(e=>{let t=r.get(String(e.id));return t?{...e,complexity:t.complexityScore,recommendedSubtasks:t.recommendedSubtasks,expansionPrompt:t.expansionPrompt,complexityReasoning:t.complexityReasoning}:e})}},De=class{static async createFromStorageConfig(e,t){return new Ee(e.basePath||t)}},Oe=class e{id;title;description;status;priority;dependencies;details;testStrategy;subtasks;createdAt;updatedAt;effort;actualEffort;tags;assignee;complexity;recommendedSubtasks;expansionPrompt;complexityReasoning;metadata;constructor(e){this.validate(e),this.id=String(e.id),this.title=e.title,this.description=e.description,this.status=e.status,this.priority=e.priority,this.dependencies=(e.dependencies||[]).map(e=>String(e)),this.details=e.details,this.testStrategy=e.testStrategy,this.subtasks=(e.subtasks||[]).map(e=>({...e,id:String(e.id),parentId:String(e.parentId)})),this.createdAt=e.createdAt,this.updatedAt=e.updatedAt,this.effort=e.effort,this.actualEffort=e.actualEffort,this.tags=e.tags,this.assignee=e.assignee,this.complexity=e.complexity,this.recommendedSubtasks=e.recommendedSubtasks,this.expansionPrompt=e.expansionPrompt,this.complexityReasoning=e.complexityReasoning,this.metadata=e.metadata}validate(e){if(e.id===void 0||e.id===null||typeof e.id!=`string`&&typeof e.id!=`number`)throw new O(`Task ID is required and must be a string or number`,D.VALIDATION_ERROR);if(!e.title||e.title.trim().length===0)throw new O(`Task title is required`,D.VALIDATION_ERROR);if(!e.description||e.description.trim().length===0)throw new O(`Task description is required`,D.VALIDATION_ERROR);if(!this.isValidStatus(e.status))throw new O(`Invalid task status: ${e.status}`,D.VALIDATION_ERROR);if(!this.isValidPriority(e.priority))throw new O(`Invalid task priority: ${e.priority}`,D.VALIDATION_ERROR)}isValidStatus(e){return[`pending`,`in-progress`,`done`,`deferred`,`cancelled`,`blocked`,`review`].includes(e)}isValidPriority(e){return[`low`,`medium`,`high`,`critical`].includes(e)}canComplete(){return this.status===`done`||this.status===`cancelled`||this.status===`blocked`?!1:this.subtasks.every(e=>e.status===`done`||e.status===`cancelled`)}markAsComplete(){if(!this.canComplete())throw new O(`Task cannot be marked as complete`,D.TASK_STATUS_ERROR,{taskId:this.id,currentStatus:this.status,hasIncompleteSubtasks:this.subtasks.some(e=>e.status!==`done`&&e.status!==`cancelled`)});this.status=`done`,this.updatedAt=new Date().toISOString()}hasDependencies(){return this.dependencies.length>0}hasSubtasks(){return this.subtasks.length>0}addSubtask(e){let t=this.subtasks.length+1;this.subtasks.push({...e,id:t,parentId:this.id}),this.updatedAt=new Date().toISOString()}updateStatus(e){if(!this.isValidStatus(e))throw new O(`Invalid status: ${e}`,D.VALIDATION_ERROR);if(this.status===`done`&&e===`pending`)throw new O(`Cannot move completed task back to pending`,D.TASK_STATUS_ERROR);this.status=e,this.updatedAt=new Date().toISOString()}toJSON(){return{id:this.id,title:this.title,description:this.description,status:this.status,priority:this.priority,dependencies:this.dependencies,details:this.details,testStrategy:this.testStrategy,subtasks:this.subtasks,createdAt:this.createdAt,updatedAt:this.updatedAt,effort:this.effort,actualEffort:this.actualEffort,tags:this.tags,assignee:this.assignee,complexity:this.complexity,recommendedSubtasks:this.recommendedSubtasks,expansionPrompt:this.expansionPrompt,complexityReasoning:this.complexityReasoning,metadata:this.metadata}}static fromObject(t){return new e(t)}static fromArray(t){return t.map(t=>new e(t))}},ke=class{configManager;storage;initialized=!1;logger=E(`TaskService`);constructor(e){this.configManager=e,this.storage=null}async initialize(){if(this.initialized)return;let e=this.configManager.getStorageConfig(),t=this.configManager.getProjectRoot();this.storage=await De.createFromStorageConfig(e,t),await this.storage.initialize(),this.initialized=!0}async getTaskList(e={}){let t=this.configManager.getActiveTag(),n=e.tag||t;try{let t=e.filter?.status&&!e.filter.priority&&!e.filter.tags&&!e.filter.assignee&&!e.filter.search&&e.filter.hasSubtasks===void 0,r={};if(t){let t=Array.isArray(e.filter.status)?e.filter.status:[e.filter.status];t.length===1&&(r.status=t[0])}e.includeSubtasks===!1&&(r.excludeSubtasks=!0);let i=await this.storage.loadTasks(n,r),a={};e.includeSubtasks===!1&&(a.excludeSubtasks=!0);let o=r.status===void 0?i:await this.storage.loadTasks(n,a),s=Oe.fromArray(i),c=s;return(e.filter&&!t||e.filter?.status&&Array.isArray(e.filter.status)&&e.filter.status.length>1)&&(c=this.applyFilters(s,e.filter)),{tasks:c.map(e=>e.toJSON()),total:o.length,filtered:c.length,tag:n}}catch(t){throw t instanceof O?t:(this.logger.error(`Failed to get task list`,t),new O(`Failed to get task list`,D.INTERNAL_ERROR,{operation:`getTaskList`,tag:n,hasFilter:!!e.filter},t))}}async getTask(e,t){let n=t||this.getActiveTag();try{return await this.storage.loadTask(String(e),n)}catch(t){throw t instanceof O?t:new O(`Failed to get task ${e}`,D.STORAGE_ERROR,{operation:`getTask`,resource:`task`,taskId:String(e),tag:n},t)}}async getTasksByStatus(e,t){let n=Array.isArray(e)?e:[e];return(await this.getTaskList({tag:t,filter:{status:n}})).tasks}async getTaskStats(e){let t=await this.getTaskList({tag:e,includeSubtasks:!0}),n={total:t.total,byStatus:{},withSubtasks:0,blocked:0};return[`pending`,`in-progress`,`done`,`deferred`,`cancelled`,`blocked`,`review`].forEach(e=>{n.byStatus[e]=0}),t.tasks.forEach(e=>{n.byStatus[e.status]++,e.subtasks&&e.subtasks.length>0&&n.withSubtasks++,e.status===`blocked`&&n.blocked++}),n}async getNextTask(e){let t=(await this.getTaskList({tag:e,filter:{status:[`pending`,`in-progress`,`done`]}})).tasks,n={critical:4,high:3,medium:2,low:1},r=(e,t)=>typeof t==`string`&&t.includes(`.`)?t:`${e}.${t}`,i=new Set;t.forEach(e=>{e.status===`done`&&i.add(String(e.id)),Array.isArray(e.subtasks)&&e.subtasks.forEach(t=>{t.status===`done`&&i.add(`${e.id}.${t.id}`)})});let a=[];if(t.filter(e=>e.status===`in-progress`&&Array.isArray(e.subtasks)).forEach(e=>{e.subtasks.forEach(t=>{let n=(t.status||`pending`).toLowerCase();if(n!==`pending`&&n!==`in-progress`)return;let o=t.dependencies?.map(t=>r(String(e.id),t))??[];(o.length===0||o.every(e=>i.has(String(e))))&&a.push({id:`${e.id}.${t.id}`,title:t.title||`Subtask ${t.id}`,status:t.status||`pending`,priority:t.priority||e.priority||`medium`,dependencies:o,parentId:String(e.id),description:t.description,details:t.details,testStrategy:t.testStrategy,subtasks:[]})})}),a.length>0)return a.sort((e,t)=>{let r=n[e.priority]??2,i=n[t.priority]??2;if(i!==r)return i-r;if(e.dependencies.length!==t.dependencies.length)return e.dependencies.length-t.dependencies.length;let[a,o]=String(e.id).split(`.`).map(Number),[s,c]=String(t.id).split(`.`).map(Number);return a===s?o-c:a-s}),a[0];let o=t.filter(e=>{let t=(e.status||`pending`).toLowerCase();return t!==`pending`&&t!==`in-progress`?!1:(e.dependencies??[]).every(e=>i.has(String(e)))});return o.length===0?null:o.sort((e,t)=>{let r=n[e.priority]??2,i=n[t.priority]??2;if(i!==r)return i-r;let a=(e.dependencies??[]).length,o=(t.dependencies??[]).length;return a===o?Number(e.id)-Number(t.id):a-o})[0]}applyFilters(e,t){return e.filter(e=>{if(t.status&&!(Array.isArray(t.status)?t.status:[t.status]).includes(e.status)||t.priority&&!(Array.isArray(t.priority)?t.priority:[t.priority]).includes(e.priority)||t.tags&&t.tags.length>0&&(!e.tags||!t.tags.some(t=>e.tags?.includes(t)))||t.assignee&&e.assignee!==t.assignee)return!1;if(t.search){let n=t.search.toLowerCase(),r=e.title.toLowerCase().includes(n),i=e.description.toLowerCase().includes(n),a=e.details.toLowerCase().includes(n);if(!r&&!i&&!a)return!1}return!(t.hasSubtasks!==void 0&&e.subtasks.length>0!==t.hasSubtasks)})}getStorage(){return this.storage}getActiveTag(){return this.configManager.getActiveTag()}async setActiveTag(e){await this.configManager.setActiveTag(e)}async updateTask(e,t,n){if(!this.storage)throw new O(`Storage not initialized`,D.STORAGE_ERROR);this.initialized||await this.initialize();let r=n||this.getActiveTag(),i=String(e);try{await this.storage.updateTask(i,t,r)}catch(t){throw t instanceof O?t:new O(`Failed to update task ${e}`,D.STORAGE_ERROR,{operation:`updateTask`,resource:`task`,taskId:i,tag:r},t)}}async updateTaskStatus(e,t,n){if(!this.storage)throw new O(`Storage not initialized`,D.STORAGE_ERROR);let r=n||this.getActiveTag(),i=String(e);try{return await this.storage.updateTaskStatus(i,t,r)}catch(e){throw e instanceof O?e:new O(`Failed to update task status for ${i}`,D.STORAGE_ERROR,{operation:`updateTaskStatus`,resource:`task`,taskId:i,newStatus:t,tag:r},e)}}async getTagsWithStats(){if(!this.storage)throw new O(`Storage not initialized`,D.STORAGE_ERROR);this.initialized||await this.initialize();try{return await this.storage.getTagsWithStats()}catch(e){throw e instanceof O?e:new O(`Failed to get tags with stats`,D.STORAGE_ERROR,{operation:`getTagsWithStats`,resource:`tags`},e)}}async close(){this.storage&&await this.storage.close(),this.initialized=!1}},Ae=class{constructor(e){this.taskService=e}async startTask(e,t={}){try{let{parentId:n,subtaskId:r}=this.parseTaskId(e);if(!t.force){let t=await this.checkInProgressConflicts(e);if(!t.canProceed)return{task:null,found:!1,started:!1,error:`Conflicting tasks in progress: ${t.conflictingTasks.map(e=>`#${e.id}: ${e.title}`).join(`, `)}`}}let i=await this.taskService.getTask(n);if(!i)return{task:null,found:!1,started:!1,error:`Task ${n} not found`};let a;if(r&&i.subtasks&&(a=i.subtasks.find(e=>String(e.id)===r)),t.updateStatus&&!t.dryRun)try{await this.taskService.updateTaskStatus(n,`in-progress`)}catch(e){console.warn(`Could not update task status: ${e instanceof Error?e.message:String(e)}`)}let o=!1,s=`Task ready to execute`,c;return t.dryRun?(o=!0,s=`Dry run - task would be executed`,c=await this.prepareExecutionCommand(i,a)):(c=await this.prepareExecutionCommand(i,a),o=!!c,s=c?`Command prepared: ${c.executable} ${c.args.join(` `)}`:`Failed to prepare execution command`),{task:i,found:!0,started:o,subtaskId:r,subtask:a,executionOutput:s,command:c||void 0}}catch(e){return{task:null,found:!1,started:!1,error:e instanceof Error?e.message:String(e)}}}async checkInProgressConflicts(e){let t=(await this.taskService.getTaskList()).tasks.filter(e=>e.status===`in-progress`);if(t.find(t=>t.id===e))return{canProceed:!0,conflictingTasks:[]};let n=e.includes(`.`);if(n){let n=e.split(`.`)[0];if(t.find(e=>e.id===n))return{canProceed:!0,conflictingTasks:[]}}let r=t.filter(t=>{if(t.id===e)return!1;if(n){let n=e.split(`.`)[0];if(t.id===n)return!1}if(t.id.toString().includes(`.`)){let r=t.id.toString().split(`.`)[0];if(n&&r===e.split(`.`)[0])return!1}return!0});return r.length>0?{canProceed:!1,conflictingTasks:r,reason:`Other tasks are already in progress`}:{canProceed:!0,conflictingTasks:[]}}async getNextAvailableTask(){return(await this.taskService.getNextTask())?.id||null}parseTaskId(e){if(e.includes(`.`)){let[t,n]=e.split(`.`);return{parentId:t,subtaskId:n}}return{parentId:e}}async canStartTask(e,t=!1){return t?!0:(await this.checkInProgressConflicts(e)).canProceed}async prepareExecutionCommand(e,t){try{return{executable:`claude`,args:[this.formatTaskPrompt(e,t)],cwd:process.cwd()}}catch(e){return console.warn(`Failed to prepare execution command: ${e instanceof Error?e.message:String(e)}`),null}}formatTaskPrompt(e,t){let n=t||e,r=t?`Subtask`:`Task`,i=`${r} #${t?`${e.id}.${t.id}`:e.id}: ${n.title}\n\n`;return n.description&&(i+=`Description:\n${n.description}\n\n`),n.details&&(i+=`Implementation Details:\n${n.details}\n\n`),n.testStrategy&&(i+=`Test Strategy:\n${n.testStrategy}\n\n`),e.dependencies&&e.dependencies.length>0&&(i+=`Dependencies: ${e.dependencies.join(`, `)}\n\n`),i+=`Please help me implement this ${r.toLowerCase()}.`,i}async getTaskWithSubtask(e){let{parentId:t,subtaskId:n}=this.parseTaskId(e),r=await this.taskService.getTask(t);return r?n&&r.subtasks?{task:r,subtask:r.subtasks.find(e=>String(e.id)===n),subtaskId:n}:{task:r}:{task:null}}},je=`taskgraph-ai`,Me=`0.52.0`;const z={CLAUDE_CODE:`claude-code`},B=Object.values(z);[...B];const V=`.taskgraph/tasks/tasks.json`,H=[`.taskgraph`,`.taskgraph/config.json`,V],U=`.git,.svn,.hg,.fossil,.github,.gitlab,.circleci,.travis.yml,.jenkins,.buildkite,.vscode,.idea,.project,.devcontainer,package-lock.json,yarn.lock,pnpm-lock.yaml,bun.lockb,bun.lock,deno.lock,deno.json,deno.jsonc,package.json,lerna.json,nx.json,turbo.json,rush.json,pnpm-workspace.yaml,Cargo.toml,Cargo.lock,go.mod,go.sum,go.work,pyproject.toml,setup.py,setup.cfg,poetry.lock,Pipfile,Pipfile.lock,uv.lock,Gemfile,Gemfile.lock,composer.json,composer.lock,build.gradle,build.gradle.kts,settings.gradle,settings.gradle.kts,pom.xml,build.sbt,project.clj,deps.edn,mix.exs,rebar.config,pubspec.yaml,Package.swift,CMakeLists.txt,Makefile,meson.build,BUILD.bazel,WORKSPACE,flake.nix,shell.nix,default.nix,Dockerfile,docker-compose.yml,docker-compose.yaml,Containerfile,kubernetes.yml,kubernetes.yaml,helm/Chart.yaml`.split(`,`),W=[`tasks.json`,...U,`requirements.txt`];[...H,...W];const G=[`pending`,`in-progress`,`done`,`deferred`,`cancelled`,`blocked`,`review`],Ne=[`done`,`completed`,`cancelled`];function K(e){return Ne.includes(e)}const Pe=[`text`,`json`,`compact`],Fe={done:`✓`,completed:`✓`,"in-progress":`►`,blocked:`⭕`,pending:`○`,deferred:`⏸`,cancelled:`✗`,review:`👁`},q=E(`TaskLoader`);var Ie=class{taskService;constructor(e){if(!e)throw Error(`taskService is required for TaskLoaderService`);this.taskService=e}async loadAndValidateTask(e){q.info(`Loading task ${e}...`);let t=await this.loadTask(e);if(!t)return{success:!1,errorType:`task_not_found`,errorMessage:`Task with ID "${e}" not found`,suggestion:`Use "taskgraph list" to see available tasks or verify the task ID is correct.`};let n=this.validateTaskStatus(t);if(!n.success)return n;let r=this.validateSubtasksExist(t);if(!r.success)return r;let i=this.validateSubtaskStructure(t);if(!i.success)return i;let a=this.validateDependencies(t);return a.success?(q.info(`Task ${e} validated successfully`),{success:!0,task:t}):a}async loadTask(e){try{return await this.taskService.getTask(e)}catch(t){return q.error(`Failed to load task ${e}:`,t),null}}validateTaskStatus(e){return K(e.status)?{success:!1,errorType:`task_completed`,errorMessage:`Task "${e.title}" is already ${e.status}`,suggestion:`Autopilot can only execute tasks that are pending or in-progress. Use a different task.`}:{success:!0}}validateSubtasksExist(e){return!e.subtasks||e.subtasks.length===0?{success:!1,errorType:`no_subtasks`,errorMessage:`Task "${e.title}" has no subtasks`,suggestion:this.buildExpansionSuggestion(e)}:{success:!0}}buildExpansionSuggestion(e){let t=[`Autopilot requires tasks to be broken down into subtasks for execution.`];return t.push(`
179
179
  Expand this task using:`),t.push(` taskgraph expand --id=${e.id}`),e.complexity||e.recommendedSubtasks?(t.push(`
180
180
  This task has complexity analysis available. Consider reviewing it first:`),t.push(` taskgraph show ${e.id}`)):(t.push(`
181
181
  Or analyze task complexity first to determine optimal subtask count:`),t.push(` taskgraph analyze-complexity --from=${e.id}`)),t.join(`
182
182
  `)}validateSubtaskStructure(e){for(let t of e.subtasks){if(!t.title||!t.description)return{success:!1,errorType:`invalid_structure`,errorMessage:`Subtask ${e.id}.${t.id} is missing required fields`,suggestion:`Subtasks must have title and description. Re-expand the task or manually fix the subtask structure.`};if(t.dependencies&&!Array.isArray(t.dependencies))return{success:!1,errorType:`invalid_structure`,errorMessage:`Subtask ${e.id}.${t.id} has invalid dependencies format`,suggestion:`Dependencies must be an array. Fix the task structure manually.`}}return{success:!0}}validateDependencies(e){let t=[],n=new Set(e.subtasks.map(e=>String(e.id)));for(let r of e.subtasks){let i=`${e.id}.${r.id}`;if(r.dependencies&&r.dependencies.length>0)for(let e of r.dependencies){let r=String(e);n.has(r)||t.push({subtaskId:i,issueType:`missing`,message:`References non-existent subtask ${r}`,dependencyRef:r})}let a=this.detectCircularDependency(r,e.subtasks,new Set);a&&t.push({subtaskId:i,issueType:`circular`,message:`Circular dependency detected: ${a.join(` -> `)}`})}return t.length>0?{success:!1,errorType:t[0].issueType===`circular`?`circular_dependencies`:`missing_dependencies`,errorMessage:`Task "${e.title}" has dependency issues`,suggestion:`Fix dependency issues manually or re-expand the task:
183
183
  `+t.map(e=>` - ${e.subtaskId}: ${e.message}`).join(`
184
- `),dependencyIssues:t}:{success:!0}}detectCircularDependency(e,t,n){let r=String(e.id);if(n.has(r))return[r];if(n.add(r),e.dependencies&&e.dependencies.length>0)for(let i of e.dependencies){let e=String(i),a=t.find(t=>String(t.id)===e);if(a){let e=this.detectCircularDependency(a,t,new Set(n));if(e)return[r,...e]}}return null}getExecutionOrder(e){let t=[],n=new Set;for(;t.length<e.subtasks.length;){let r=!1;for(let i of e.subtasks){let e=String(i.id);if(!n.has(e)&&(!i.dependencies||i.dependencies.length===0||i.dependencies.every(e=>n.has(String(e))))){t.push(i),n.add(e),r=!0;break}}if(!r&&t.length<e.subtasks.length){K.warn(`Could not determine complete execution order for task ${e.id}`);for(let r of e.subtasks)n.has(String(r.id))||t.push(r);break}}return t}async cleanup(){}};const q=re(ne);async function Re(e){if(!e)throw Error(`projectRoot is required for isGitRepository`);try{return await q(`git rev-parse --git-dir`,{cwd:e}),!0}catch{return!1}}async function ze(e){if(!e)throw Error(`projectRoot is required for getLocalBranches`);try{let{stdout:t}=await q(`git branch --format="%(refname:short)"`,{cwd:e,maxBuffer:10*1024*1024});return t.trim().split(`
185
- `).filter(e=>e.length>0).map(e=>e.trim())}catch{return[]}}async function Be(e){if(!e)throw Error(`projectRoot is required for getRemoteBranches`);try{let{stdout:t}=await q(`git branch -r --format="%(refname:short)"`,{cwd:e,maxBuffer:10*1024*1024}),n=t.trim().split(`
186
- `).filter(e=>e.length>0&&!e.includes(`HEAD`)).map(e=>e.replace(/^[^/]+\//,``).trim());return Array.from(new Set(n))}catch{return[]}}async function Ve(e){try{return await q(`gh auth status`,e?{cwd:e}:{}),!0}catch{return!1}}async function He(e){if(!e)throw Error(`projectRoot is required for getGitHubRepoInfo`);try{let{stdout:t}=await q(`gh repo view --json name,owner,defaultBranchRef`,{cwd:e});return JSON.parse(t)}catch{return null}}async function Ue(e){if(!e)throw Error(`projectRoot is required for getDefaultBranch`);try{if(await Ve(e)){let t=await He(e);if(t&&t.defaultBranchRef)return t.defaultBranchRef.name}let t=(await q(`git remote`,{cwd:e})).stdout.trim().split(`
187
- `).filter(Boolean);if(t.length>0){let n=t.includes(`origin`)?`origin`:t[0];try{let{stdout:t}=await q(`git remote show ${n}`,{cwd:e,maxBuffer:10*1024*1024}),r=t.match(/HEAD branch:\s+([^\s]+)/);if(r)return r[1].trim()}catch{}try{let{stdout:t}=await q(`git symbolic-ref refs/remotes/${n}/HEAD`,{cwd:e});return t.replace(`refs/remotes/${n}/`,``).trim()}catch{}}throw Error(`default-branch-not-found`)}catch{let t=[`main`,`master`],n=await ze(e),r=await Be(e);for(let e of t)if(n.includes(e)||r.includes(e))return e;return null}}const J=E(`PreflightChecker`);var We=class{projectRoot;constructor(e){if(!e)throw Error(`projectRoot is required for PreflightChecker`);this.projectRoot=e}async detectTestCommand(){try{let e=ee(l(this.projectRoot,`package.json`),`utf-8`),t=JSON.parse(e);if(!t.scripts||!t.scripts.test)return{success:!1,message:`No test script found in package.json. Please add a "test" script.`};let n=t.scripts.test;return{success:!0,value:n,message:`Test command: ${n}`}}catch(e){return e.code===`ENOENT`?{success:!1,message:`package.json not found in project root`}:{success:!1,message:`Failed to read package.json: ${e.message}`}}}async checkGitWorkingTree(){try{return await Re(this.projectRoot)?y(`git status --porcelain`,{cwd:this.projectRoot,encoding:`utf-8`,timeout:5e3}).trim().length>0?{success:!1,value:`dirty`,message:`Working tree has uncommitted or untracked changes. Please commit or stash them.`}:{success:!0,value:`clean`,message:`Working tree is clean`}:{success:!1,message:`Not a git repository. Initialize git first.`}}catch(e){return{success:!1,message:`Git check failed: ${e.message}`}}}detectProjectTypes(){let e=[];return g(l(this.projectRoot,`package.json`))&&e.push(`node`),(g(l(this.projectRoot,`requirements.txt`))||g(l(this.projectRoot,`setup.py`))||g(l(this.projectRoot,`pyproject.toml`)))&&e.push(`python`),(g(l(this.projectRoot,`pom.xml`))||g(l(this.projectRoot,`build.gradle`)))&&e.push(`java`),g(l(this.projectRoot,`go.mod`))&&e.push(`go`),g(l(this.projectRoot,`Cargo.toml`))&&e.push(`rust`),g(l(this.projectRoot,`composer.json`))&&e.push(`php`),g(l(this.projectRoot,`Gemfile`))&&e.push(`ruby`),te(this.projectRoot).some(e=>e.endsWith(`.csproj`)||e.endsWith(`.sln`))&&e.push(`dotnet`),e}getToolsForProjectType(e){return{node:[{command:`node`,args:[`--version`]},{command:`npm`,args:[`--version`]}],python:[{command:`python3`,args:[`--version`]},{command:`pip3`,args:[`--version`]}],java:[{command:`java`,args:[`--version`]}],go:[{command:`go`,args:[`version`]}],rust:[{command:`cargo`,args:[`--version`]}],php:[{command:`php`,args:[`--version`]},{command:`composer`,args:[`--version`]}],ruby:[{command:`ruby`,args:[`--version`]},{command:`bundle`,args:[`--version`]}],dotnet:[{command:`dotnet`,args:[`--version`]}]}[e]||[]}async validateRequiredTools(){let e=[];e.push(this.checkTool(`git`,[`--version`])),e.push(await this.checkGhCli());let t=this.detectProjectTypes();t.length===0?J.warn(`No recognized project type detected`):J.info(`Detected project types: ${t.join(`, `)}`);for(let n of t){let t=this.getToolsForProjectType(n);for(let n of t)e.push(this.checkTool(n.command,n.args))}let n=e.every(e=>e.available),r=e.filter(e=>!e.available).map(e=>e.name);return n?{success:!0,value:e,message:`All required tools are available`}:{success:!1,value:e,message:`Missing required tools: ${r.join(`, `)}`}}checkTool(e,t){try{let n=y(`${e} ${t.join(` `)}`,{cwd:this.projectRoot,encoding:`utf-8`,stdio:`pipe`,timeout:5e3}).trim().split(`
184
+ `),dependencyIssues:t}:{success:!0}}detectCircularDependency(e,t,n){let r=String(e.id);if(n.has(r))return[r];if(n.add(r),e.dependencies&&e.dependencies.length>0)for(let i of e.dependencies){let e=String(i),a=t.find(t=>String(t.id)===e);if(a){let e=this.detectCircularDependency(a,t,new Set(n));if(e)return[r,...e]}}return null}getExecutionOrder(e){let t=[],n=new Set;for(;t.length<e.subtasks.length;){let r=!1;for(let i of e.subtasks){let e=String(i.id);if(!n.has(e)&&(!i.dependencies||i.dependencies.length===0||i.dependencies.every(e=>n.has(String(e))))){t.push(i),n.add(e),r=!0;break}}if(!r&&t.length<e.subtasks.length){q.warn(`Could not determine complete execution order for task ${e.id}`);for(let r of e.subtasks)n.has(String(r.id))||t.push(r);break}}return t}async cleanup(){}};const J=re(ne);async function Le(e){if(!e)throw Error(`projectRoot is required for isGitRepository`);try{return await J(`git rev-parse --git-dir`,{cwd:e}),!0}catch{return!1}}async function Re(e){if(!e)throw Error(`projectRoot is required for getLocalBranches`);try{let{stdout:t}=await J(`git branch --format="%(refname:short)"`,{cwd:e,maxBuffer:10*1024*1024});return t.trim().split(`
185
+ `).filter(e=>e.length>0).map(e=>e.trim())}catch{return[]}}async function ze(e){if(!e)throw Error(`projectRoot is required for getRemoteBranches`);try{let{stdout:t}=await J(`git branch -r --format="%(refname:short)"`,{cwd:e,maxBuffer:10*1024*1024}),n=t.trim().split(`
186
+ `).filter(e=>e.length>0&&!e.includes(`HEAD`)).map(e=>e.replace(/^[^/]+\//,``).trim());return Array.from(new Set(n))}catch{return[]}}async function Y(e){try{return await J(`gh auth status`,e?{cwd:e}:{}),!0}catch{return!1}}async function Be(e){if(!e)throw Error(`projectRoot is required for getGitHubRepoInfo`);try{let{stdout:t}=await J(`gh repo view --json name,owner,defaultBranchRef`,{cwd:e});return JSON.parse(t)}catch{return null}}async function Ve(e){if(!e)throw Error(`projectRoot is required for getDefaultBranch`);try{if(await Y(e)){let t=await Be(e);if(t&&t.defaultBranchRef)return t.defaultBranchRef.name}let t=(await J(`git remote`,{cwd:e})).stdout.trim().split(`
187
+ `).filter(Boolean);if(t.length>0){let n=t.includes(`origin`)?`origin`:t[0];try{let{stdout:t}=await J(`git remote show ${n}`,{cwd:e,maxBuffer:10*1024*1024}),r=t.match(/HEAD branch:\s+([^\s]+)/);if(r)return r[1].trim()}catch{}try{let{stdout:t}=await J(`git symbolic-ref refs/remotes/${n}/HEAD`,{cwd:e});return t.replace(`refs/remotes/${n}/`,``).trim()}catch{}}throw Error(`default-branch-not-found`)}catch{let t=[`main`,`master`],n=await Re(e),r=await ze(e);for(let e of t)if(n.includes(e)||r.includes(e))return e;return null}}const X=E(`PreflightChecker`);var He=class{projectRoot;constructor(e){if(!e)throw Error(`projectRoot is required for PreflightChecker`);this.projectRoot=e}async detectTestCommand(){try{let e=ee(l(this.projectRoot,`package.json`),`utf-8`),t=JSON.parse(e);if(!t.scripts||!t.scripts.test)return{success:!1,message:`No test script found in package.json. Please add a "test" script.`};let n=t.scripts.test;return{success:!0,value:n,message:`Test command: ${n}`}}catch(e){return e.code===`ENOENT`?{success:!1,message:`package.json not found in project root`}:{success:!1,message:`Failed to read package.json: ${e.message}`}}}async checkGitWorkingTree(){try{return await Le(this.projectRoot)?y(`git status --porcelain`,{cwd:this.projectRoot,encoding:`utf-8`,timeout:5e3}).trim().length>0?{success:!1,value:`dirty`,message:`Working tree has uncommitted or untracked changes. Please commit or stash them.`}:{success:!0,value:`clean`,message:`Working tree is clean`}:{success:!1,message:`Not a git repository. Initialize git first.`}}catch(e){return{success:!1,message:`Git check failed: ${e.message}`}}}detectProjectTypes(){let e=[];return g(l(this.projectRoot,`package.json`))&&e.push(`node`),(g(l(this.projectRoot,`requirements.txt`))||g(l(this.projectRoot,`setup.py`))||g(l(this.projectRoot,`pyproject.toml`)))&&e.push(`python`),(g(l(this.projectRoot,`pom.xml`))||g(l(this.projectRoot,`build.gradle`)))&&e.push(`java`),g(l(this.projectRoot,`go.mod`))&&e.push(`go`),g(l(this.projectRoot,`Cargo.toml`))&&e.push(`rust`),g(l(this.projectRoot,`composer.json`))&&e.push(`php`),g(l(this.projectRoot,`Gemfile`))&&e.push(`ruby`),te(this.projectRoot).some(e=>e.endsWith(`.csproj`)||e.endsWith(`.sln`))&&e.push(`dotnet`),e}getToolsForProjectType(e){return{node:[{command:`node`,args:[`--version`]},{command:`npm`,args:[`--version`]}],python:[{command:`python3`,args:[`--version`]},{command:`pip3`,args:[`--version`]}],java:[{command:`java`,args:[`--version`]}],go:[{command:`go`,args:[`version`]}],rust:[{command:`cargo`,args:[`--version`]}],php:[{command:`php`,args:[`--version`]},{command:`composer`,args:[`--version`]}],ruby:[{command:`ruby`,args:[`--version`]},{command:`bundle`,args:[`--version`]}],dotnet:[{command:`dotnet`,args:[`--version`]}]}[e]||[]}async validateRequiredTools(){let e=[];e.push(this.checkTool(`git`,[`--version`])),e.push(await this.checkGhCli());let t=this.detectProjectTypes();t.length===0?X.warn(`No recognized project type detected`):X.info(`Detected project types: ${t.join(`, `)}`);for(let n of t){let t=this.getToolsForProjectType(n);for(let n of t)e.push(this.checkTool(n.command,n.args))}let n=e.every(e=>e.available),r=e.filter(e=>!e.available).map(e=>e.name);return n?{success:!0,value:e,message:`All required tools are available`}:{success:!1,value:e,message:`Missing required tools: ${r.join(`, `)}`}}checkTool(e,t){try{let n=y(`${e} ${t.join(` `)}`,{cwd:this.projectRoot,encoding:`utf-8`,stdio:`pipe`,timeout:5e3}).trim().split(`
188
188
  `)[0];return{name:e,available:!0,version:n,message:`${e} ${n}`}}catch{return{name:e,available:!1,message:`${e} not found`}}}async checkGhCli(){try{return{name:`gh`,available:!0,version:y(`gh --version`,{cwd:this.projectRoot,encoding:`utf-8`,stdio:`pipe`,timeout:5e3}).trim().split(`
189
- `)[0],message:await Ve(this.projectRoot)?`GitHub CLI installed (authenticated)`:`GitHub CLI installed (not authenticated)`}}catch{return{name:`gh`,available:!1,message:`GitHub CLI not found`}}}async detectDefaultBranch(){try{let e=await Ue(this.projectRoot);return e?{success:!0,value:e,message:`Default branch: ${e}`}:{success:!1,message:`Could not determine default branch. Make sure remote is configured.`}}catch(e){return{success:!1,message:`Failed to detect default branch: ${e.message}`}}}async runAllChecks(){J.info(`Running preflight checks...`);let e=await this.detectTestCommand(),t=await this.checkGitWorkingTree(),n=await this.validateRequiredTools(),r=await this.detectDefaultBranch(),i=e.success&&t.success&&n.success&&r.success,a=[],o=[];e.success?a.push(`Test command`):o.push(`Test command`),t.success?a.push(`Git working tree`):o.push(`Git working tree`),n.success?a.push(`Required tools`):o.push(`Required tools`),r.success?a.push(`Default branch`):o.push(`Default branch`);let s=a.length+o.length,c=i?`All preflight checks passed (${a.length}/${s})`:`Preflight checks failed: ${o.join(`, `)} (${a.length}/${s} passed)`;return J.info(c),{success:i,testCommand:e,gitWorkingTree:t,requiredTools:n,defaultBranch:r,summary:c}}};const Ge=[`master`];var Ke=class{constructor(e){this.storage=e}validateTagName(e,t=`Tag name`){if(!e||typeof e!=`string`)throw new O(`${t} is required and must be a string`,D.VALIDATION_ERROR);if(e.length>50)throw new O(`${t} must be 50 characters or less`,D.VALIDATION_ERROR,{tagName:e,maxLength:50});if(!/^[a-zA-Z0-9_-]+$/.test(e))throw new O(`${t} can only contain letters, numbers, hyphens, and underscores`,D.VALIDATION_ERROR,{tagName:e});if(Ge.includes(e.toLowerCase()))throw new O(`"${e}" is a reserved tag name`,D.VALIDATION_ERROR,{tagName:e,reserved:!0})}async createTag(e,t={}){this.validateTagName(e);let n=await this.storage.getAllTags();if(n.includes(e))throw new O(`Tag "${e}" already exists`,D.VALIDATION_ERROR,{tagName:e});if(t.copyFromTag&&!n.includes(t.copyFromTag))throw new O(`Cannot copy from missing tag "${t.copyFromTag}"`,D.NOT_FOUND,{tagName:t.copyFromTag});let r;return t.copyFromTag?r=t.copyFromTag:t.copyFromCurrent&&(r=(await this.storage.getTagsWithStats()).currentTag||void 0),await this.storage.createTag(e,{copyFrom:r,description:t.description}),{name:e,taskCount:0,completedTasks:0,isCurrent:!1,statusBreakdown:{},description:t.description||`Tag created on ${new Date().toLocaleDateString()}`}}async deleteTag(e,t={}){if(this.validateTagName(e),e===`master`)throw new O(`Cannot delete the "master" tag`,D.VALIDATION_ERROR,{tagName:e,protected:!0});if(!(await this.storage.getAllTags()).includes(e))throw new O(`Tag "${e}" does not exist`,D.NOT_FOUND,{tagName:e});await this.storage.deleteTag(e)}async renameTag(e,t){if(this.validateTagName(e,`Old tag name`),this.validateTagName(t,`New tag name`),e===`master`)throw new O(`Cannot rename the "master" tag`,D.VALIDATION_ERROR,{tagName:e,protected:!0});let n=await this.storage.getAllTags();if(!n.includes(e))throw new O(`Tag "${e}" does not exist`,D.NOT_FOUND,{tagName:e});if(n.includes(t))throw new O(`Tag "${t}" already exists`,D.VALIDATION_ERROR,{tagName:t});await this.storage.renameTag(e,t)}async copyTag(e,t,n={}){this.validateTagName(e,`Source tag name`),this.validateTagName(t,`Target tag name`);let r=await this.storage.getAllTags();if(!r.includes(e))throw new O(`Source tag "${e}" does not exist`,D.NOT_FOUND,{tagName:e});if(r.includes(t))throw new O(`Target tag "${t}" already exists`,D.VALIDATION_ERROR,{tagName:t});await this.storage.copyTag(e,t)}async getTagsWithStats(){return await this.storage.getTagsWithStats()}},qe=class{constructor(e,t,n){this.storage=e,this.projectPath=t,this.configManager=n}async generateTaskFiles(e={}){let n=e.tag||this.configManager.getActiveTag(),r=e.outputDir||t.join(this.projectPath,`.taskgraph`,`tasks`);try{await i.mkdir(r,{recursive:!0});let e=await this.storage.loadTasks(n);if(e.length===0)return{success:!0,count:0,directory:r,orphanedFilesRemoved:0};let a=await this.cleanupOrphanedFiles(r,e,n),o={},s=await Promise.allSettled(e.map(async a=>{let o=this.formatTaskContent(a,e),s=this.getTaskFileName(a.id,n),c=t.join(r,s);return await i.writeFile(c,o,`utf-8`),a.id})),c=0;for(let t=0;t<s.length;t++){let n=s[t];if(n.status===`fulfilled`)c++;else{let r=String(e[t].id);o[r]=n.reason?.message||`Unknown error`}}return{success:Object.keys(o).length===0,count:c,directory:r,orphanedFilesRemoved:a,...Object.keys(o).length>0&&{fileErrors:o}}}catch(e){return{success:!1,count:0,directory:r,orphanedFilesRemoved:0,error:e.message}}}getTaskFileName(e,t){let n=String(e).padStart(3,`0`);return t===`master`?`task_${n}.md`:`task_${n}_${t}.md`}escapeRegExp(e){return e.replace(/[.*+?^${}()|[\]\\]/g,`\\$&`)}async cleanupOrphanedFiles(e,n,r){let a=0;try{let o=await i.readdir(e),s=n.map(e=>String(e.id)),c=/^task_(\d+)\.md$/,l=RegExp(`^task_(\\d+)_${this.escapeRegExp(r)}\\.md$`),u=[];for(let e of o){let t=null,n=null;if(r===`master`?(t=e.match(c),t&&(n=t[1])):(t=e.match(l),t&&(n=t[1])),n!==null){let t=String(parseInt(n,10));s.includes(t)||u.push(e)}}await Promise.all(u.map(async n=>{let r=t.join(e,n);await i.unlink(r)})),a=u.length}catch{}return a}formatTaskContent(e,t){let n=`# Task ID: ${e.id}\n\n`;if(n+=`**Title:** ${e.title}\n\n`,n+=`**Status:** ${e.status||`pending`}\n\n`,e.dependencies&&e.dependencies.length>0){let r=this.formatDependenciesWithStatus(e.dependencies,t);n+=`**Dependencies:** ${r}\n\n`}else n+=`**Dependencies:** None
189
+ `)[0],message:await Y(this.projectRoot)?`GitHub CLI installed (authenticated)`:`GitHub CLI installed (not authenticated)`}}catch{return{name:`gh`,available:!1,message:`GitHub CLI not found`}}}async detectDefaultBranch(){try{let e=await Ve(this.projectRoot);return e?{success:!0,value:e,message:`Default branch: ${e}`}:{success:!1,message:`Could not determine default branch. Make sure remote is configured.`}}catch(e){return{success:!1,message:`Failed to detect default branch: ${e.message}`}}}async runAllChecks(){X.info(`Running preflight checks...`);let e=await this.detectTestCommand(),t=await this.checkGitWorkingTree(),n=await this.validateRequiredTools(),r=await this.detectDefaultBranch(),i=e.success&&t.success&&n.success&&r.success,a=[],o=[];e.success?a.push(`Test command`):o.push(`Test command`),t.success?a.push(`Git working tree`):o.push(`Git working tree`),n.success?a.push(`Required tools`):o.push(`Required tools`),r.success?a.push(`Default branch`):o.push(`Default branch`);let s=a.length+o.length,c=i?`All preflight checks passed (${a.length}/${s})`:`Preflight checks failed: ${o.join(`, `)} (${a.length}/${s} passed)`;return X.info(c),{success:i,testCommand:e,gitWorkingTree:t,requiredTools:n,defaultBranch:r,summary:c}}};const Ue=[`master`];var We=class{constructor(e){this.storage=e}validateTagName(e,t=`Tag name`){if(!e||typeof e!=`string`)throw new O(`${t} is required and must be a string`,D.VALIDATION_ERROR);if(e.length>50)throw new O(`${t} must be 50 characters or less`,D.VALIDATION_ERROR,{tagName:e,maxLength:50});if(!/^[a-zA-Z0-9_-]+$/.test(e))throw new O(`${t} can only contain letters, numbers, hyphens, and underscores`,D.VALIDATION_ERROR,{tagName:e});if(Ue.includes(e.toLowerCase()))throw new O(`"${e}" is a reserved tag name`,D.VALIDATION_ERROR,{tagName:e,reserved:!0})}async createTag(e,t={}){this.validateTagName(e);let n=await this.storage.getAllTags();if(n.includes(e))throw new O(`Tag "${e}" already exists`,D.VALIDATION_ERROR,{tagName:e});if(t.copyFromTag&&!n.includes(t.copyFromTag))throw new O(`Cannot copy from missing tag "${t.copyFromTag}"`,D.NOT_FOUND,{tagName:t.copyFromTag});let r;return t.copyFromTag?r=t.copyFromTag:t.copyFromCurrent&&(r=(await this.storage.getTagsWithStats()).currentTag||void 0),await this.storage.createTag(e,{copyFrom:r,description:t.description}),{name:e,taskCount:0,completedTasks:0,isCurrent:!1,statusBreakdown:{},description:t.description||`Tag created on ${new Date().toLocaleDateString()}`}}async deleteTag(e,t={}){if(this.validateTagName(e),e===`master`)throw new O(`Cannot delete the "master" tag`,D.VALIDATION_ERROR,{tagName:e,protected:!0});if(!(await this.storage.getAllTags()).includes(e))throw new O(`Tag "${e}" does not exist`,D.NOT_FOUND,{tagName:e});await this.storage.deleteTag(e)}async renameTag(e,t){if(this.validateTagName(e,`Old tag name`),this.validateTagName(t,`New tag name`),e===`master`)throw new O(`Cannot rename the "master" tag`,D.VALIDATION_ERROR,{tagName:e,protected:!0});let n=await this.storage.getAllTags();if(!n.includes(e))throw new O(`Tag "${e}" does not exist`,D.NOT_FOUND,{tagName:e});if(n.includes(t))throw new O(`Tag "${t}" already exists`,D.VALIDATION_ERROR,{tagName:t});await this.storage.renameTag(e,t)}async copyTag(e,t,n={}){this.validateTagName(e,`Source tag name`),this.validateTagName(t,`Target tag name`);let r=await this.storage.getAllTags();if(!r.includes(e))throw new O(`Source tag "${e}" does not exist`,D.NOT_FOUND,{tagName:e});if(r.includes(t))throw new O(`Target tag "${t}" already exists`,D.VALIDATION_ERROR,{tagName:t});await this.storage.copyTag(e,t)}async getTagsWithStats(){return await this.storage.getTagsWithStats()}},Ge=class{constructor(e,t,n){this.storage=e,this.projectPath=t,this.configManager=n}async generateTaskFiles(e={}){let n=e.tag||this.configManager.getActiveTag(),r=e.outputDir||t.join(this.projectPath,`.taskgraph`,`tasks`);try{await i.mkdir(r,{recursive:!0});let e=await this.storage.loadTasks(n);if(e.length===0)return{success:!0,count:0,directory:r,orphanedFilesRemoved:0};let a=await this.cleanupOrphanedFiles(r,e,n),o={},s=await Promise.allSettled(e.map(async a=>{let o=this.formatTaskContent(a,e),s=this.getTaskFileName(a.id,n),c=t.join(r,s);return await i.writeFile(c,o,`utf-8`),a.id})),c=0;for(let t=0;t<s.length;t++){let n=s[t];if(n.status===`fulfilled`)c++;else{let r=String(e[t].id);o[r]=n.reason?.message||`Unknown error`}}return{success:Object.keys(o).length===0,count:c,directory:r,orphanedFilesRemoved:a,...Object.keys(o).length>0&&{fileErrors:o}}}catch(e){return{success:!1,count:0,directory:r,orphanedFilesRemoved:0,error:e.message}}}getTaskFileName(e,t){let n=String(e).padStart(3,`0`);return t===`master`?`task_${n}.md`:`task_${n}_${t}.md`}escapeRegExp(e){return e.replace(/[.*+?^${}()|[\]\\]/g,`\\$&`)}async cleanupOrphanedFiles(e,n,r){let a=0;try{let o=await i.readdir(e),s=n.map(e=>String(e.id)),c=/^task_(\d+)\.md$/,l=RegExp(`^task_(\\d+)_${this.escapeRegExp(r)}\\.md$`),u=[];for(let e of o){let t=null,n=null;if(r===`master`?(t=e.match(c),t&&(n=t[1])):(t=e.match(l),t&&(n=t[1])),n!==null){let t=String(parseInt(n,10));s.includes(t)||u.push(e)}}await Promise.all(u.map(async n=>{let r=t.join(e,n);await i.unlink(r)})),a=u.length}catch{}return a}formatTaskContent(e,t){let n=`# Task ID: ${e.id}\n\n`;if(n+=`**Title:** ${e.title}\n\n`,n+=`**Status:** ${e.status||`pending`}\n\n`,e.dependencies&&e.dependencies.length>0){let r=this.formatDependenciesWithStatus(e.dependencies,t);n+=`**Dependencies:** ${r}\n\n`}else n+=`**Dependencies:** None
190
190
 
191
191
  `;if(n+=`**Priority:** ${e.priority||`medium`}\n\n`,n+=`**Description:** ${e.description||``}\n\n`,n+=`**Details:**
192
192
 
@@ -198,6 +198,6 @@ Or analyze task complexity first to determine optimal subtask count:`),t.push(`
198
198
 
199
199
  `)}formatSubtaskContent(e,t){let n=`\n### ${t.id}.${e.id}. ${e.title}\n\n`;if(n+=`**Status:** ${e.status||`pending`} \n`,e.dependencies&&e.dependencies.length>0){let r=e.dependencies.map(e=>{let n=String(e);return n.includes(`.`)?n:`${t.id}.${n}`}).join(`, `);n+=`**Dependencies:** ${r} \n`}else n+=`**Dependencies:** None
200
200
  `;return n+=`
201
- `,e.description&&(n+=`${e.description}\n`),e.details&&(n+=`\n**Details:**\n\n${e.details}\n`),n}formatDependenciesWithStatus(e,t){return e.map(e=>{let n=t.find(t=>String(t.id)===String(e));return n?`${e}${this.getStatusSymbol(n.status)}`:String(e)}).join(`, `)}getStatusSymbol(e){switch(e){case`done`:return` ✓`;case`in-progress`:return` ⧖`;case`blocked`:return` ⛔`;case`cancelled`:return` ✗`;case`deferred`:return` ⏸`;default:return``}}},Je=class{taskService;executionService;loaderService;preflightChecker;tagService;taskFileGenerator;projectRoot;configManager;constructor(e){this.projectRoot=e.getProjectRoot(),this.configManager=e,this.taskService=new ke(e),this.executionService=new Ae(this.taskService),this.loaderService=new Le(this.taskService),this.preflightChecker=new We(this.projectRoot)}async initialize(){await this.taskService.initialize(),this.tagService=new Ke(this.taskService.getStorage()),this.taskFileGenerator=new qe(this.taskService.getStorage(),this.projectRoot,this.configManager)}async list(e){return this.taskService.getTaskList(e)}async get(e,t){let n=e.split(`.`),r=n[0],i=n[1],a=await this.taskService.getTask(r,t);if(!a)return{task:null,isSubtask:!1};if(i&&a.subtasks){let e=a.subtasks.find(e=>String(e.id)===i);return e?{task:e,isSubtask:!0}:{task:null,isSubtask:!0}}return{task:a,isSubtask:!1}}async getByStatus(e,t){return this.taskService.getTasksByStatus(e,t)}async getStats(e){return this.taskService.getTaskStats(e)}async getNext(e){return this.taskService.getNextTask(e)}async getCount(e,t){let n=await this.list({tag:t}),r=0;for(let t of n.tasks)if(t.status===e&&r++,t.subtasks&&t.subtasks.length>0)for(let n of t.subtasks)(n.status===e||e===`pending`&&!n.status)&&r++;return r}async update(e,t,n){return this.taskService.updateTask(e,t,n)}async updateStatus(e,t,n){return this.taskService.updateTaskStatus(e,t,n)}async setActiveTag(e){return this.taskService.setActiveTag(e)}async start(e,t){return this.executionService.startTask(e,t)}async checkInProgressConflicts(e){return this.executionService.checkInProgressConflicts(e)}async getNextAvailable(){return this.executionService.getNextAvailableTask()}async canStart(e,t){return this.executionService.canStartTask(e,t)}async loadAndValidate(e){return this.loaderService.loadAndValidateTask(e)}getExecutionOrder(e){return this.loaderService.getExecutionOrder(e)}async runPreflightChecks(){return this.preflightChecker.runAllChecks()}async detectTestCommand(){return this.preflightChecker.detectTestCommand()}async checkGitWorkingTree(){return this.preflightChecker.checkGitWorkingTree()}async validateRequiredTools(){return this.preflightChecker.validateRequiredTools()}async detectDefaultBranch(){return this.preflightChecker.detectDefaultBranch()}async createTag(e,t){return this.tagService.createTag(e,t)}async deleteTag(e,t){return this.tagService.deleteTag(e,t)}async renameTag(e,t){return this.tagService.renameTag(e,t)}async copyTag(e,t,n){return this.tagService.copyTag(e,t,n)}async getTagsWithStats(){return this.tagService.getTagsWithStats()}async watch(e,t){return this.taskService.getStorage().watch(e,t)}async generateTaskFiles(e){return this.taskFileGenerator.generateTaskFiles(e)}async close(){await this.taskService.close()}},Ye=class{projectRoot;statePath;backupDir;sessionDir;maxBackups;logger=E(`WorkflowStateManager`);writer=null;writerInitPromise=null;constructor(e,n=5){this.projectRoot=t.resolve(e),this.maxBackups=n;let r=this.getProjectIdentifier(this.projectRoot),i=ie.homedir(),a=t.join(i,`.taskgraph`,r);this.sessionDir=t.join(a,`sessions`),this.statePath=t.join(this.sessionDir,`workflow-state.json`),this.backupDir=t.join(this.sessionDir,`backups`)}getProjectIdentifier(e){return`-`+t.resolve(e).replace(/^\//,``).replace(/[^a-zA-Z0-9]+/g,`-`).replace(/-+/g,`-`).replace(/-+$/,``)}async ensureWriter(){if(!this.writer){if(this.writerInitPromise){await this.writerInitPromise;return}this.writerInitPromise=(async()=>{await i.mkdir(this.sessionDir,{recursive:!0}),this.writer=new v(this.statePath)})(),await this.writerInitPromise,this.writerInitPromise=null}}async exists(){try{return await i.access(this.statePath),!0}catch{return!1}}async load(){try{let e=await i.readFile(this.statePath,`utf-8`);return JSON.parse(e)}catch(e){throw e.code===`ENOENT`?Error(`Workflow state file not found at ${this.statePath}`):Error(`Failed to load workflow state: ${e.message}`)}}async save(e){try{await this.ensureWriter();let t=JSON.stringify(e,null,2);try{JSON.parse(t)}catch{throw this.logger.error(`Generated invalid JSON:`,t),Error(`Failed to generate valid JSON from workflow state`)}await this.writer.write(t+`
202
- `),this.logger.debug(`Saved workflow state (${t.length} bytes)`)}catch(e){throw Error(`Failed to save workflow state: ${e.message}`)}}async createBackup(){try{if(!await this.exists())return;let e=await this.load();await i.mkdir(this.backupDir,{recursive:!0});let n=new Date().toISOString().replace(/[:.]/g,`-`),r=t.join(this.backupDir,`workflow-state-${n}.json`),a={timestamp:new Date().toISOString(),state:e};await i.writeFile(r,JSON.stringify(a,null,2),`utf-8`),await this.pruneBackups()}catch(e){throw Error(`Failed to create backup: ${e.message}`)}}async delete(){try{await i.unlink(this.statePath)}catch(e){if(e.code!==`ENOENT`)throw Error(`Failed to delete workflow state: ${e.message}`)}}async listBackups(){try{return(await i.readdir(this.backupDir)).filter(e=>e.startsWith(`workflow-state-`)&&e.endsWith(`.json`)).sort().reverse()}catch(e){if(e.code===`ENOENT`)return[];throw Error(`Failed to list backups: ${e.message}`)}}async restoreBackup(e){try{let n=t.join(this.backupDir,e),r=await i.readFile(n,`utf-8`),a=JSON.parse(r);await this.save(a.state)}catch(e){throw Error(`Failed to restore backup: ${e.message}`)}}async pruneBackups(){try{let e=await this.listBackups();if(e.length>this.maxBackups){let n=e.slice(this.maxBackups);for(let e of n)await i.unlink(t.join(this.backupDir,e))}}catch(e){this.logger.warn(`Failed to prune backups: ${e.message}`)}}getStatePath(){return this.statePath}getBackupDir(){return this.backupDir}getSessionDir(){return this.sessionDir}getProjectRoot(){return this.projectRoot}getActivityLogPath(){return t.join(this.sessionDir,`activity.jsonl`)}},Xe=class{currentPhase;context;transitions;eventListeners;persistCallback;autoPersistEnabled=!1;phaseGuards;aborted=!1;testResultValidator;gitOperationHook;executeHook;constructor(e){this.currentPhase=`PREFLIGHT`,this.context={...e},this.transitions=this.defineTransitions(),this.eventListeners=new Map,this.phaseGuards=new Map}defineTransitions(){return[{from:`PREFLIGHT`,to:`BRANCH_SETUP`,event:`PREFLIGHT_COMPLETE`},{from:`BRANCH_SETUP`,to:`SUBTASK_LOOP`,event:`BRANCH_CREATED`},{from:`SUBTASK_LOOP`,to:`FINALIZE`,event:`ALL_SUBTASKS_COMPLETE`},{from:`FINALIZE`,to:`COMPLETE`,event:`FINALIZE_COMPLETE`}]}getCurrentPhase(){return this.currentPhase}getCurrentTDDPhase(){if(this.currentPhase===`SUBTASK_LOOP`)return this.context.currentTDDPhase||`RED`}getContext(){return{...this.context}}async transition(e){if(this.aborted&&e.type!==`ABORT`)throw Error(`Workflow has been aborted`);if(e.type===`ERROR`){this.handleError(e.error),await this.triggerAutoPersist();return}if(e.type===`ABORT`){this.aborted=!0,await this.triggerAutoPersist();return}if(e.type===`RETRY`){this.handleRetry(),await this.triggerAutoPersist();return}if(this.currentPhase===`SUBTASK_LOOP`){await this.handleTDDPhaseTransition(e),await this.triggerAutoPersist();return}let t=this.transitions.find(t=>t.from===this.currentPhase&&t.event===e.type);if(!t)throw Error(`Invalid transition: ${e.type} from ${this.currentPhase}`);this.executeTransition(t,e),await this.triggerAutoPersist()}async handleTDDPhaseTransition(e){let t=this.context.currentTDDPhase||`RED`;switch(e.type){case`RED_PHASE_COMPLETE`:if(t!==`RED`)throw Error(`Invalid transition: RED_PHASE_COMPLETE from non-RED phase`);if(!e.testResults)throw Error(`Test results required for RED phase transition`);if(this.context.lastTestResults=e.testResults,e.testResults.failed===0){this.emit(`tdd:red:completed`),this.emit(`tdd:feature-already-implemented`,{subtaskId:this.getCurrentSubtaskId(),testResults:e.testResults});let t=this.context.subtasks[this.context.currentSubtaskIndex];t&&(t.status=`completed`),this.emit(`subtask:completed`),this.context.currentSubtaskIndex++;let n=this.getProgress();this.emit(`progress:updated`,{completed:n.completed,total:n.total,percentage:n.percentage}),this.context.currentSubtaskIndex<this.context.subtasks.length?(this.context.currentTDDPhase=`RED`,this.emit(`tdd:red:started`),this.emit(`subtask:started`)):await this.transition({type:`ALL_SUBTASKS_COMPLETE`});break}this.emit(`tdd:red:completed`),this.context.currentTDDPhase=`GREEN`,this.emit(`tdd:green:started`);break;case`GREEN_PHASE_COMPLETE`:if(t!==`GREEN`)throw Error(`Invalid transition: GREEN_PHASE_COMPLETE from non-GREEN phase`);if(!e.testResults)throw Error(`Test results required for GREEN phase transition`);if(e.testResults.failed!==0)throw Error(`GREEN phase must have zero failures`);this.context.lastTestResults=e.testResults,this.emit(`tdd:green:completed`),this.context.currentTDDPhase=`COMMIT`,this.emit(`tdd:commit:started`);break;case`COMMIT_COMPLETE`:if(t!==`COMMIT`)throw Error(`Invalid transition: COMMIT_COMPLETE from non-COMMIT phase`);this.emit(`tdd:commit:completed`);let n=this.context.subtasks[this.context.currentSubtaskIndex];n&&(n.status=`completed`);break;case`SUBTASK_COMPLETE`:this.emit(`subtask:completed`),this.context.currentSubtaskIndex++;let r=this.getProgress();this.emit(`progress:updated`,{completed:r.completed,total:r.total,percentage:r.percentage}),this.context.currentSubtaskIndex<this.context.subtasks.length?(this.context.currentTDDPhase=`RED`,this.emit(`tdd:red:started`),this.emit(`subtask:started`)):await this.transition({type:`ALL_SUBTASKS_COMPLETE`});break;case`ALL_SUBTASKS_COMPLETE`:this.emit(`phase:exited`),this.currentPhase=`FINALIZE`,this.context.currentTDDPhase=void 0,this.emit(`phase:entered`);break;default:throw Error(`Invalid transition: ${e.type} in SUBTASK_LOOP`)}}executeTransition(e,t){if(e.guard&&!e.guard(this.context))throw Error(`Guard condition failed for transition to ${e.to}`);let n=this.phaseGuards.get(e.to);if(n&&!n(this.context))throw Error(`Guard condition failed`);this.emit(`phase:exited`),this.updateContext(t),this.currentPhase=e.to,this.emit(`phase:entered`),this.currentPhase===`SUBTASK_LOOP`&&(this.context.currentTDDPhase=`RED`,this.emit(`tdd:red:started`),this.emit(`subtask:started`))}updateContext(e){switch(e.type){case`BRANCH_CREATED`:this.context.branchName=e.branchName,this.emit(`git:branch:created`,{branchName:e.branchName}),this.gitOperationHook&&this.gitOperationHook(`branch:created`,{branchName:e.branchName});break;case`ERROR`:this.context.errors.push(e.error),this.emit(`error:occurred`,{error:e.error});break}}getState(){return{phase:this.currentPhase,context:{...this.context}}}restoreState(e){this.currentPhase=e.phase,this.context={...e.context},this.emit(`workflow:resumed`,{phase:this.currentPhase,progress:this.getProgress()})}on(e,t){this.eventListeners.has(e)||this.eventListeners.set(e,new Set),this.eventListeners.get(e).add(t)}off(e,t){let n=this.eventListeners.get(e);n&&n.delete(t)}emit(e,t){let n={type:e,timestamp:new Date,phase:this.currentPhase,tddPhase:this.context.currentTDDPhase,subtaskId:this.getCurrentSubtaskId(),data:{...t,adapters:{testValidator:!!this.testResultValidator,gitHook:!!this.gitOperationHook,executeHook:!!this.executeHook}}},r=this.eventListeners.get(e);r&&r.forEach(e=>e(n))}getCurrentSubtaskId(){return this.context.subtasks[this.context.currentSubtaskIndex]?.id}onStatePersist(e){this.persistCallback=e}enableAutoPersist(e){this.persistCallback=e,this.autoPersistEnabled=!0}disableAutoPersist(){this.autoPersistEnabled=!1}async persistState(){this.persistCallback&&await this.persistCallback(this.getState()),this.emit(`state:persisted`)}async triggerAutoPersist(){this.autoPersistEnabled&&this.persistCallback&&await this.persistCallback(this.getState())}addGuard(e,t){this.phaseGuards.set(e,t)}removeGuard(e){this.phaseGuards.delete(e)}getCurrentSubtask(){return this.context.subtasks[this.context.currentSubtaskIndex]}getProgress(){let e=this.context.subtasks.filter(e=>e.status===`completed`).length,t=this.context.subtasks.length;return{completed:e,total:t,current:this.context.currentSubtaskIndex+1,percentage:t>0?Math.round(e/t*100):0}}canProceed(){return this.currentPhase===`SUBTASK_LOOP`?this.getCurrentSubtask()?.status===`completed`:!1}incrementAttempts(){let e=this.getCurrentSubtask();e&&e.attempts++}hasExceededMaxAttempts(){let e=this.getCurrentSubtask();return!e||!e.maxAttempts?!1:e.attempts>e.maxAttempts}handleError(e){this.context.errors.push(e),this.emit(`error:occurred`,{error:e})}handleRetry(){this.currentPhase===`SUBTASK_LOOP`&&(this.context.currentTDDPhase=`RED`,this.emit(`tdd:red:started`))}retryCurrentSubtask(){this.currentPhase===`SUBTASK_LOOP`&&(this.context.currentTDDPhase=`RED`,this.emit(`tdd:red:started`))}handleMaxAttemptsExceeded(){let e=this.getCurrentSubtask();e&&(e.status=`failed`,this.emit(`subtask:failed`,{subtaskId:e.id,attempts:e.attempts,maxAttempts:e.maxAttempts}))}isAborted(){return this.aborted}canResumeFromState(e){return!(![`PREFLIGHT`,`BRANCH_SETUP`,`SUBTASK_LOOP`,`FINALIZE`,`COMPLETE`].includes(e.phase)||!e.context||typeof e.context!=`object`||!e.context.taskId||!Array.isArray(e.context.subtasks)||typeof e.context.currentSubtaskIndex!=`number`||!Array.isArray(e.context.errors))}setTestResultValidator(e){this.testResultValidator=e,this.emit(`adapter:configured`,{adapterType:`test-validator`})}hasTestResultValidator(){return!!this.testResultValidator}removeTestResultValidator(){this.testResultValidator=void 0}onGitOperation(e){this.gitOperationHook=e}onExecute(e){this.executeHook=e}executeCommand(e){this.executeHook&&this.executeHook(e,this.context)}};async function Ze(e,t){let n={...t,timestamp:new Date().toISOString()};await u.ensureDir(c.dirname(e));let r=JSON.stringify(n)+`
203
- `;await u.appendFile(e,r,`utf-8`)}const Qe=[`workflow:started`,`workflow:completed`,`workflow:error`,`workflow:resumed`,`phase:entered`,`phase:exited`,`tdd:feature-already-implemented`,`tdd:red:started`,`tdd:red:completed`,`tdd:green:started`,`tdd:green:completed`,`tdd:commit:started`,`tdd:commit:completed`,`subtask:started`,`subtask:completed`,`subtask:failed`,`test:run`,`test:passed`,`test:failed`,`git:branch:created`,`git:commit:created`,`error:occurred`,`state:persisted`,`progress:updated`,`adapter:configured`];var $e=class{activityLogPath;orchestrator;logger=E(`WorkflowActivityLogger`);listenerMap=new Map;isActive=!1;constructor(e,t){this.orchestrator=e,this.activityLogPath=t}start(){if(this.isActive){this.logger.warn(`Activity logger is already active`);return}Qe.forEach(e=>{let t=e=>this.logEvent(e);this.listenerMap.set(e,t),this.orchestrator.on(e,t)}),this.isActive=!0,this.logger.debug(`Activity logger started, logging to: ${this.activityLogPath}`)}stop(){this.isActive&&(this.listenerMap.forEach((e,t)=>{this.orchestrator.off(t,e)}),this.listenerMap.clear(),this.isActive=!1,this.logger.debug(`Activity logger stopped and listeners removed`))}async logEvent(e){if(this.isActive)try{let t=e.timestamp instanceof Date?e.timestamp.toISOString():new Date(e.timestamp).toISOString(),n={type:e.type,phase:e.phase,tddPhase:e.tddPhase,subtaskId:e.subtaskId,eventTimestamp:t,...e.data||{}};await Ze(this.activityLogPath,n)}catch(t){this.logger.error(`Failed to log activity event ${e.type}: ${t.message}`)}}getActivityLogPath(){return this.activityLogPath}isLogging(){return this.isActive}},et=class{projectRoot;stateManager;taskStatusUpdater;tag;logger=E(`WorkflowService`);orchestrator;activityLogger;constructor(e){typeof e==`string`?this.projectRoot=e:(this.projectRoot=e.projectRoot,this.taskStatusUpdater=e.taskStatusUpdater,this.tag=e.tag),this.stateManager=new Ye(this.projectRoot)}async updateTaskStatus(e,t,n){if(this.taskStatusUpdater)try{await this.taskStatusUpdater.updateStatus(e,t,n??this.tag)}catch(t){let n=t instanceof Error?t.message:String(t);this.logger.warn(`Failed to update task ${e} status: ${n}`)}}async hasWorkflow(){return await this.stateManager.exists()}async startWorkflow(e){let{taskId:t,taskTitle:n,subtasks:r,maxAttempts:i=3,force:a,tag:o}=e;if(await this.hasWorkflow()&&!a)throw Error(`Workflow already exists. Use force=true to override or resume existing workflow.`);let s=new A(this.projectRoot);await s.ensureGitRepository(),await s.ensureCleanWorkingTree();let c=r.map(e=>({id:e.id,title:e.title,status:e.status===`done`?`completed`:`pending`,attempts:0,maxAttempts:e.maxAttempts||i})),l=c.findIndex(e=>e.status!==`completed`);if(l===-1)throw Error(`All subtasks for task ${t} are already completed. Nothing to do.`);this.orchestrator=new Xe({taskId:t,subtasks:c,currentSubtaskIndex:l,tag:o,errors:[],metadata:{startedAt:new Date().toISOString(),taskTitle:n,resumedFromSubtask:l>0?c[l].id:void 0}}),this.orchestrator.enableAutoPersist(async e=>{await this.stateManager.save(e)}),this.activityLogger=new $e(this.orchestrator,this.stateManager.getActivityLogPath()),this.activityLogger.start(),await this.orchestrator.transition({type:`PREFLIGHT_COMPLETE`});let u=this.generateBranchName(t,n,o);return await s.getCurrentBranch()!==u&&await s.createAndCheckoutBranch(u),await this.orchestrator.transition({type:`BRANCH_CREATED`,branchName:u}),await this.updateTaskStatus(t,`in-progress`,o),this.getStatus()}async resumeWorkflow(){let e=await this.stateManager.load();if(this.orchestrator=new Xe(e.context),!this.orchestrator.canResumeFromState(e))throw Error(`Invalid workflow state. State may be corrupted. Consider starting a new workflow.`);return this.orchestrator.restoreState(e),this.orchestrator.enableAutoPersist(async e=>{await this.stateManager.save(e)}),this.activityLogger=new $e(this.orchestrator,this.stateManager.getActivityLogPath()),this.activityLogger.start(),this.getStatus()}getStatus(){if(!this.orchestrator)throw Error(`No active workflow. Start or resume a workflow first.`);let e=this.orchestrator.getContext(),t=this.orchestrator.getProgress(),n=this.orchestrator.getCurrentSubtask();return{taskId:e.taskId,phase:this.orchestrator.getCurrentPhase(),tddPhase:this.orchestrator.getCurrentTDDPhase(),branchName:e.branchName,currentSubtask:n?{id:n.id,title:n.title,attempts:n.attempts,maxAttempts:n.maxAttempts||3}:void 0,progress:t}}getContext(){if(!this.orchestrator)throw Error(`No active workflow. Start or resume a workflow first.`);return this.orchestrator.getContext()}getNextAction(){if(!this.orchestrator)throw Error(`No active workflow. Start or resume a workflow first.`);let e=this.orchestrator.getCurrentPhase(),t=this.orchestrator.getCurrentTDDPhase(),n=this.orchestrator.getCurrentSubtask();if(e===`COMPLETE`)return{action:`workflow_complete`,description:`All subtasks completed`,nextSteps:`All subtasks completed! Review the entire implementation and merge your branch when ready.`,phase:e};if(e===`FINALIZE`)return{action:`finalize_workflow`,description:`Finalize and complete the workflow`,nextSteps:`All subtasks are complete! Use autopilot_finalize to verify no uncommitted changes remain and mark the workflow as complete.`,phase:e};if(e!==`SUBTASK_LOOP`||!t||!n)return{action:`unknown`,description:`Workflow is not in active state`,nextSteps:`Use autopilot_status to check workflow state.`,phase:e};let r={phase:e,tddPhase:t,subtask:{id:n.id,title:n.title}};switch(t){case`RED`:return{...r,action:`generate_test`,description:`Generate failing test for current subtask`,nextSteps:`Write failing tests for subtask ${n.id}: "${n.title}". Create test file(s) that validate the expected behavior. Run tests and use autopilot_complete_phase with results. Note: If all tests pass (0 failures), the feature is already implemented and the subtask will be auto-completed.`};case`GREEN`:return{...r,action:`implement_code`,description:`Implement feature to make tests pass`,nextSteps:`Implement code to make tests pass for subtask ${n.id}: "${n.title}". Write the minimal code needed to pass all tests (GREEN phase), then use autopilot_complete_phase with test results.`};case`COMMIT`:return{...r,action:`commit_changes`,description:`Commit RED-GREEN cycle changes`,nextSteps:`Review and commit your changes for subtask ${n.id}: "${n.title}". Use autopilot_commit to create the commit and advance to the next subtask.`};default:return{...r,action:`unknown`,description:`Unknown TDD phase`,nextSteps:`Use autopilot_status to check workflow state.`}}}async completePhase(e){if(!this.orchestrator)throw Error(`No active workflow. Start or resume a workflow first.`);let t=this.orchestrator.getCurrentTDDPhase();if(!t)throw Error(`Not in active TDD phase`);switch(t){case`RED`:await this.orchestrator.transition({type:`RED_PHASE_COMPLETE`,testResults:e});break;case`GREEN`:await this.orchestrator.transition({type:`GREEN_PHASE_COMPLETE`,testResults:e});break;case`COMMIT`:throw Error(`Cannot complete COMMIT phase with test results. Use commit() instead.`);default:throw Error(`Unknown TDD phase: ${t}`)}return this.getStatus()}async commit(){if(!this.orchestrator)throw Error(`No active workflow. Start or resume a workflow first.`);let e=this.orchestrator.getCurrentTDDPhase();if(e!==`COMMIT`)throw Error(`Cannot commit in ${e} phase. Complete RED and GREEN phases first.`);let t=this.orchestrator.getCurrentSubtask()?.id;await this.orchestrator.transition({type:`COMMIT_COMPLETE`});let n=this.orchestrator.getProgress();if(n.current<n.total?await this.orchestrator.transition({type:`SUBTASK_COMPLETE`}):await this.orchestrator.transition({type:`ALL_SUBTASKS_COMPLETE`}),t){let e=this.orchestrator.getContext();await this.updateTaskStatus(t,`done`,e.tag)}return this.getStatus()}async finalizeWorkflow(){if(!this.orchestrator)throw Error(`No active workflow. Start or resume a workflow first.`);let e=this.orchestrator.getCurrentPhase();if(e!==`FINALIZE`)throw Error(`Cannot finalize workflow in ${e} phase. Complete all subtasks first.`);let t=await new A(this.projectRoot).getStatusSummary();if(!t.isClean)throw Error(`Cannot finalize workflow: working tree has uncommitted changes.\nStaged: ${t.staged}, Modified: ${t.modified}, Deleted: ${t.deleted}, Untracked: ${t.untracked}\nPlease commit all changes before finalizing the workflow.`);let n=this.orchestrator.getContext(),r=n.taskId;await this.orchestrator.transition({type:`FINALIZE_COMPLETE`});let i=this.getStatus();return await this.updateTaskStatus(r,`done`,n.tag),await this.stateManager.delete(),this.orchestrator=void 0,i}async abortWorkflow(){this.orchestrator&&await this.orchestrator.transition({type:`ABORT`}),await this.stateManager.delete(),this.orchestrator=void 0}generateBranchName(e,t,n){let r=t.toLowerCase().replace(/[^a-z0-9]+/g,`-`).replace(/^-+|-+$/g,``).substring(0,50),i=e.replace(/\./g,`-`);return`${n?`tm/${n}`:`tm`}/task-${i}-${r}`}},tt=class{workflowService=null;projectRoot;configManager;tasksDomain=null;constructor(e){this.configManager=e,this.projectRoot=e.getProjectRoot()}setTasksDomain(e){this.tasksDomain=e}getWorkflowService(){if(!this.workflowService){let e=this.configManager.getActiveTag(),t=this.tasksDomain?{updateStatus:async(e,t,n)=>{await this.tasksDomain.updateStatus(e,t,n)}}:void 0;this.workflowService=new et({projectRoot:this.projectRoot,taskStatusUpdater:t,tag:e})}return this.workflowService}resetWorkflowService(){this.workflowService=null}async start(e){return this.resetWorkflowService(),this.getWorkflowService().startWorkflow(e)}async resume(){return this.resetWorkflowService(),this.getWorkflowService().resumeWorkflow()}getStatus(){return this.getWorkflowService().getStatus()}getContext(){return this.getWorkflowService().getContext()}getNextAction(){return this.getWorkflowService().getNextAction()}async completePhase(e){return this.getWorkflowService().completePhase(e)}async commit(){return this.getWorkflowService().commit()}async finalize(){let e=await this.getWorkflowService().finalizeWorkflow();return this.resetWorkflowService(),e}async abort(){await this.getWorkflowService().abortWorkflow(),this.resetWorkflowService()}async hasWorkflow(){return this.getWorkflowService().hasWorkflow()}},nt=class e{_projectPath;_configManager;_logger;_tasks;_workflow;_git;_config;_loop;get tasks(){return this._tasks}get workflow(){return this._workflow}get git(){return this._git}get config(){return this._config}get loop(){return this._loop}get logger(){return this._logger}static async create(t){let n=new e(t);return await n.initialize(),n}_options;constructor(e){if(!e.projectPath)throw new O(`Project path is required`,D.MISSING_CONFIGURATION);if(!t.isAbsolute(e.projectPath))throw new O(`Project path must be an absolute path, received: "${e.projectPath}"`,D.INVALID_INPUT);this._projectPath=t.resolve(e.projectPath),this._options=e}async initialize(){try{this._logger=T(this._options.loggerConfig),this._configManager=await pe.create(this._projectPath),this._options.configuration&&await this._configManager.updateConfig(this._options.configuration),this._tasks=new Je(this._configManager),this._workflow=new tt(this._configManager),this._git=new ye(this._projectPath),this._config=new oe(this._configManager),this._loop=new xe(this._configManager),await this._tasks.initialize(),this._workflow.setTasksDomain(this._tasks),this._logger.info(`TmCore initialized successfully`)}catch(e){throw this._logger&&this._logger.error(`Failed to initialize TmCore:`,e),new O(`Failed to initialize TmCore`,D.INTERNAL_ERROR,{operation:`initialize`},e)}}get projectPath(){return this._projectPath}async close(){this._tasks&&await this._tasks.close()}};async function rt(e){return nt.create(e)}function it(e,n){try{return m.existsSync(t.join(e,n))}catch{return!1}}function Y(e,t){return t.some(t=>it(e,t))}function at(e=process.cwd()){let n=t.resolve(e),r=t.parse(n).root,i=0,a=null;if(Y(n,H)||Y(n,U))return n;let o=t.dirname(n);for(i=1;i<50;){let e=Y(o,H),n=Y(o,U);if(e&&(n||i===1))return o;if(n&&!e){a=o;break}if(o===r)break;let s=t.dirname(o);if(s===o)break;o=s,i++}for(n=a||t.resolve(e),i=0;i<50;){if(Y(n,Ne))return n;if(n===r)break;let e=t.dirname(n);if(e===n)break;n=e,i++}return t.resolve(e)}function ot(e){if(!e)return``;let n=String(e).split(t.sep),r=n.findIndex(e=>e===`.taskgraph`);return r===-1?String(e):n.slice(0,r).join(t.sep)||t.sep}function st(e){let t=e?r(process.cwd(),e):at();return{projectRoot:t,tasksPath:n(t,V)}}function ct(e){return ae(e,`hh:mm:ss a`)}function X(e){if(!e)return e;let t=e.trim();if(/^\d+(\.\d+)?$/.test(t))return t;let n=t.match(/^([a-zA-Z]{3})-?(\d+)$/);return n?`${n[1].toUpperCase()}-${n[2]}`:t}const lt=/^\d+$/,ut=/^\d+\.\d+$/,dt=/^[a-zA-Z]{3}-?\d+$/;function ft(e){if(!e)return!1;let t=e.trim();return!!(lt.test(t)||ut.test(t)||dt.test(t))}function pt(e){if(!e)return!1;let t=e.trim();return!!(lt.test(t)||dt.test(t))}const Z=b.string().trim().refine(ft,{message:`Invalid task ID format. Expected: numeric ("1", "1.2") or prefixed with hyphen ("HAM-1")`}),Q=b.string().trim().refine(ft,{message:`Invalid task ID format. Expected: numeric ("1") or prefixed with hyphen ("HAM-1")`}).refine(pt,{message:`Subtask IDs are not allowed. Please provide a main task ID (e.g., "1", "HAM-1")`}),mt=Z.transform(X),ht=Q.transform(X),gt=Z,_t=Q,vt=/^(\d+(\.\d+)*|[A-Za-z]+-?\d+)$/;function $(e){return vt.test(e)}b.string().min(1,`Task ID cannot be empty`).refine($,{message:`Invalid task ID format. Expected numeric (e.g., '15'), subtask (e.g., '15.2'), or display ID (e.g., 'HAM-123')`});const yt=b.string().min(1,`Task ID(s) cannot be empty`).refine(e=>{let t=e.split(`,`).map(e=>e.trim()).filter(e=>e.length>0);return t.length>0&&t.every($)},{message:`Invalid task ID format. Expected numeric (e.g., '15'), subtask (e.g., '15.2'), or display ID (e.g., 'HAM-123'). Multiple IDs should be comma-separated.`});function bt(e){let t=e.split(`,`).map(e=>e.trim()).filter(e=>e.length>0);if(t.length===0)throw Error(`No valid task IDs provided`);let n=t.filter(e=>!$(e));if(n.length>0)throw Error(`Invalid task ID format: ${n.join(`, `)}. Expected numeric (e.g., '15'), subtask (e.g., '15.2'), or display ID (e.g., 'HAM-123')`);return t.map(X)}const xt=E(`TaskFilters`),St=[`pending`,`in-progress`,`review`];function Ct(e){let t=new Map(e.map(e=>[String(e.id),[]])),n=[];for(let r of e)for(let e of r.dependencies??[]){let i=String(e),a=t.get(i);a?a.push(String(r.id)):n.push({taskId:String(r.id),depId:i})}return{blocksMap:t,invalidDependencies:n}}function wt(e){let t=new Set(e.filter(e=>G(e.status)).map(e=>String(e.id)));return e.filter(e=>(W.includes(e.status)||xt.warn(`Task ${e.id} has unexpected status "${e.status}". Valid statuses are: ${W.join(`, `)}`),St.includes(e.status)?(e.dependencies??[]).every(e=>t.has(String(e))):!1))}function Tt(e){return e.filter(e=>e.blocks.length>0)}export{Me as C,A as E,je as S,M as T,Ie as _,yt as a,z as b,mt as c,ct as d,st as f,Fe as g,rt as h,bt as i,gt as l,ot as m,Tt as n,ht as o,at as p,wt as r,_t as s,Ct as t,X as u,W as v,P as w,B as x,G as y};
201
+ `,e.description&&(n+=`${e.description}\n`),e.details&&(n+=`\n**Details:**\n\n${e.details}\n`),n}formatDependenciesWithStatus(e,t){return e.map(e=>{let n=t.find(t=>String(t.id)===String(e));return n?`${e}${this.getStatusSymbol(n.status)}`:String(e)}).join(`, `)}getStatusSymbol(e){switch(e){case`done`:return` ✓`;case`in-progress`:return` ⧖`;case`blocked`:return` ⛔`;case`cancelled`:return` ✗`;case`deferred`:return` ⏸`;default:return``}}},Ke=class{taskService;executionService;loaderService;preflightChecker;tagService;taskFileGenerator;projectRoot;configManager;constructor(e){this.projectRoot=e.getProjectRoot(),this.configManager=e,this.taskService=new ke(e),this.executionService=new Ae(this.taskService),this.loaderService=new Ie(this.taskService),this.preflightChecker=new He(this.projectRoot)}async initialize(){await this.taskService.initialize(),this.tagService=new We(this.taskService.getStorage()),this.taskFileGenerator=new Ge(this.taskService.getStorage(),this.projectRoot,this.configManager)}async list(e){return this.taskService.getTaskList(e)}async get(e,t){let n=e.split(`.`),r=n[0],i=n[1],a=await this.taskService.getTask(r,t);if(!a)return{task:null,isSubtask:!1};if(i&&a.subtasks){let e=a.subtasks.find(e=>String(e.id)===i);return e?{task:e,isSubtask:!0}:{task:null,isSubtask:!0}}return{task:a,isSubtask:!1}}async getByStatus(e,t){return this.taskService.getTasksByStatus(e,t)}async getStats(e){return this.taskService.getTaskStats(e)}async getNext(e){return this.taskService.getNextTask(e)}async getCount(e,t){let n=await this.list({tag:t}),r=0;for(let t of n.tasks)if(t.status===e&&r++,t.subtasks&&t.subtasks.length>0)for(let n of t.subtasks)(n.status===e||e===`pending`&&!n.status)&&r++;return r}async update(e,t,n){return this.taskService.updateTask(e,t,n)}async updateStatus(e,t,n){return this.taskService.updateTaskStatus(e,t,n)}async setActiveTag(e){return this.taskService.setActiveTag(e)}async start(e,t){return this.executionService.startTask(e,t)}async checkInProgressConflicts(e){return this.executionService.checkInProgressConflicts(e)}async getNextAvailable(){return this.executionService.getNextAvailableTask()}async canStart(e,t){return this.executionService.canStartTask(e,t)}async loadAndValidate(e){return this.loaderService.loadAndValidateTask(e)}getExecutionOrder(e){return this.loaderService.getExecutionOrder(e)}async runPreflightChecks(){return this.preflightChecker.runAllChecks()}async detectTestCommand(){return this.preflightChecker.detectTestCommand()}async checkGitWorkingTree(){return this.preflightChecker.checkGitWorkingTree()}async validateRequiredTools(){return this.preflightChecker.validateRequiredTools()}async detectDefaultBranch(){return this.preflightChecker.detectDefaultBranch()}async createTag(e,t){return this.tagService.createTag(e,t)}async deleteTag(e,t){return this.tagService.deleteTag(e,t)}async renameTag(e,t){return this.tagService.renameTag(e,t)}async copyTag(e,t,n){return this.tagService.copyTag(e,t,n)}async getTagsWithStats(){return this.tagService.getTagsWithStats()}async watch(e,t){return this.taskService.getStorage().watch(e,t)}async generateTaskFiles(e){return this.taskFileGenerator.generateTaskFiles(e)}async close(){await this.taskService.close()}},qe=class{projectRoot;statePath;backupDir;sessionDir;maxBackups;logger=E(`WorkflowStateManager`);writer=null;writerInitPromise=null;constructor(e,n=5){this.projectRoot=t.resolve(e),this.maxBackups=n;let r=this.getProjectIdentifier(this.projectRoot),i=ie.homedir(),a=t.join(i,`.taskgraph`,r);this.sessionDir=t.join(a,`sessions`),this.statePath=t.join(this.sessionDir,`workflow-state.json`),this.backupDir=t.join(this.sessionDir,`backups`)}getProjectIdentifier(e){return`-`+t.resolve(e).replace(/^\//,``).replace(/[^a-zA-Z0-9]+/g,`-`).replace(/-+/g,`-`).replace(/-+$/,``)}async ensureWriter(){if(!this.writer){if(this.writerInitPromise){await this.writerInitPromise;return}this.writerInitPromise=(async()=>{await i.mkdir(this.sessionDir,{recursive:!0}),this.writer=new v(this.statePath)})(),await this.writerInitPromise,this.writerInitPromise=null}}async exists(){try{return await i.access(this.statePath),!0}catch{return!1}}async load(){try{let e=await i.readFile(this.statePath,`utf-8`);return JSON.parse(e)}catch(e){throw e.code===`ENOENT`?Error(`Workflow state file not found at ${this.statePath}`):Error(`Failed to load workflow state: ${e.message}`)}}async save(e){try{await this.ensureWriter();let t=JSON.stringify(e,null,2);try{JSON.parse(t)}catch{throw this.logger.error(`Generated invalid JSON:`,t),Error(`Failed to generate valid JSON from workflow state`)}await this.writer.write(t+`
202
+ `),this.logger.debug(`Saved workflow state (${t.length} bytes)`)}catch(e){throw Error(`Failed to save workflow state: ${e.message}`)}}async createBackup(){try{if(!await this.exists())return;let e=await this.load();await i.mkdir(this.backupDir,{recursive:!0});let n=new Date().toISOString().replace(/[:.]/g,`-`),r=t.join(this.backupDir,`workflow-state-${n}.json`),a={timestamp:new Date().toISOString(),state:e};await i.writeFile(r,JSON.stringify(a,null,2),`utf-8`),await this.pruneBackups()}catch(e){throw Error(`Failed to create backup: ${e.message}`)}}async delete(){try{await i.unlink(this.statePath)}catch(e){if(e.code!==`ENOENT`)throw Error(`Failed to delete workflow state: ${e.message}`)}}async listBackups(){try{return(await i.readdir(this.backupDir)).filter(e=>e.startsWith(`workflow-state-`)&&e.endsWith(`.json`)).sort().reverse()}catch(e){if(e.code===`ENOENT`)return[];throw Error(`Failed to list backups: ${e.message}`)}}async restoreBackup(e){try{let n=t.join(this.backupDir,e),r=await i.readFile(n,`utf-8`),a=JSON.parse(r);await this.save(a.state)}catch(e){throw Error(`Failed to restore backup: ${e.message}`)}}async pruneBackups(){try{let e=await this.listBackups();if(e.length>this.maxBackups){let n=e.slice(this.maxBackups);for(let e of n)await i.unlink(t.join(this.backupDir,e))}}catch(e){this.logger.warn(`Failed to prune backups: ${e.message}`)}}getStatePath(){return this.statePath}getBackupDir(){return this.backupDir}getSessionDir(){return this.sessionDir}getProjectRoot(){return this.projectRoot}getActivityLogPath(){return t.join(this.sessionDir,`activity.jsonl`)}},Je=class{currentPhase;context;transitions;eventListeners;persistCallback;autoPersistEnabled=!1;phaseGuards;aborted=!1;testResultValidator;gitOperationHook;executeHook;constructor(e){this.currentPhase=`PREFLIGHT`,this.context={...e},this.transitions=this.defineTransitions(),this.eventListeners=new Map,this.phaseGuards=new Map}defineTransitions(){return[{from:`PREFLIGHT`,to:`BRANCH_SETUP`,event:`PREFLIGHT_COMPLETE`},{from:`BRANCH_SETUP`,to:`SUBTASK_LOOP`,event:`BRANCH_CREATED`},{from:`SUBTASK_LOOP`,to:`FINALIZE`,event:`ALL_SUBTASKS_COMPLETE`},{from:`FINALIZE`,to:`COMPLETE`,event:`FINALIZE_COMPLETE`}]}getCurrentPhase(){return this.currentPhase}getCurrentTDDPhase(){if(this.currentPhase===`SUBTASK_LOOP`)return this.context.currentTDDPhase||`RED`}getContext(){return{...this.context}}async transition(e){if(this.aborted&&e.type!==`ABORT`)throw Error(`Workflow has been aborted`);if(e.type===`ERROR`){this.handleError(e.error),await this.triggerAutoPersist();return}if(e.type===`ABORT`){this.aborted=!0,await this.triggerAutoPersist();return}if(e.type===`RETRY`){this.handleRetry(),await this.triggerAutoPersist();return}if(this.currentPhase===`SUBTASK_LOOP`){await this.handleTDDPhaseTransition(e),await this.triggerAutoPersist();return}let t=this.transitions.find(t=>t.from===this.currentPhase&&t.event===e.type);if(!t)throw Error(`Invalid transition: ${e.type} from ${this.currentPhase}`);this.executeTransition(t,e),await this.triggerAutoPersist()}async handleTDDPhaseTransition(e){let t=this.context.currentTDDPhase||`RED`;switch(e.type){case`RED_PHASE_COMPLETE`:if(t!==`RED`)throw Error(`Invalid transition: RED_PHASE_COMPLETE from non-RED phase`);if(!e.testResults)throw Error(`Test results required for RED phase transition`);if(this.context.lastTestResults=e.testResults,e.testResults.failed===0){this.emit(`tdd:red:completed`),this.emit(`tdd:feature-already-implemented`,{subtaskId:this.getCurrentSubtaskId(),testResults:e.testResults});let t=this.context.subtasks[this.context.currentSubtaskIndex];t&&(t.status=`completed`),this.emit(`subtask:completed`),this.context.currentSubtaskIndex++;let n=this.getProgress();this.emit(`progress:updated`,{completed:n.completed,total:n.total,percentage:n.percentage}),this.context.currentSubtaskIndex<this.context.subtasks.length?(this.context.currentTDDPhase=`RED`,this.emit(`tdd:red:started`),this.emit(`subtask:started`)):await this.transition({type:`ALL_SUBTASKS_COMPLETE`});break}this.emit(`tdd:red:completed`),this.context.currentTDDPhase=`GREEN`,this.emit(`tdd:green:started`);break;case`GREEN_PHASE_COMPLETE`:if(t!==`GREEN`)throw Error(`Invalid transition: GREEN_PHASE_COMPLETE from non-GREEN phase`);if(!e.testResults)throw Error(`Test results required for GREEN phase transition`);if(e.testResults.failed!==0)throw Error(`GREEN phase must have zero failures`);this.context.lastTestResults=e.testResults,this.emit(`tdd:green:completed`),this.context.currentTDDPhase=`COMMIT`,this.emit(`tdd:commit:started`);break;case`COMMIT_COMPLETE`:if(t!==`COMMIT`)throw Error(`Invalid transition: COMMIT_COMPLETE from non-COMMIT phase`);this.emit(`tdd:commit:completed`);let n=this.context.subtasks[this.context.currentSubtaskIndex];n&&(n.status=`completed`);break;case`SUBTASK_COMPLETE`:this.emit(`subtask:completed`),this.context.currentSubtaskIndex++;let r=this.getProgress();this.emit(`progress:updated`,{completed:r.completed,total:r.total,percentage:r.percentage}),this.context.currentSubtaskIndex<this.context.subtasks.length?(this.context.currentTDDPhase=`RED`,this.emit(`tdd:red:started`),this.emit(`subtask:started`)):await this.transition({type:`ALL_SUBTASKS_COMPLETE`});break;case`ALL_SUBTASKS_COMPLETE`:this.emit(`phase:exited`),this.currentPhase=`FINALIZE`,this.context.currentTDDPhase=void 0,this.emit(`phase:entered`);break;default:throw Error(`Invalid transition: ${e.type} in SUBTASK_LOOP`)}}executeTransition(e,t){if(e.guard&&!e.guard(this.context))throw Error(`Guard condition failed for transition to ${e.to}`);let n=this.phaseGuards.get(e.to);if(n&&!n(this.context))throw Error(`Guard condition failed`);this.emit(`phase:exited`),this.updateContext(t),this.currentPhase=e.to,this.emit(`phase:entered`),this.currentPhase===`SUBTASK_LOOP`&&(this.context.currentTDDPhase=`RED`,this.emit(`tdd:red:started`),this.emit(`subtask:started`))}updateContext(e){switch(e.type){case`BRANCH_CREATED`:this.context.branchName=e.branchName,this.emit(`git:branch:created`,{branchName:e.branchName}),this.gitOperationHook&&this.gitOperationHook(`branch:created`,{branchName:e.branchName});break;case`ERROR`:this.context.errors.push(e.error),this.emit(`error:occurred`,{error:e.error});break}}getState(){return{phase:this.currentPhase,context:{...this.context}}}restoreState(e){this.currentPhase=e.phase,this.context={...e.context},this.emit(`workflow:resumed`,{phase:this.currentPhase,progress:this.getProgress()})}on(e,t){this.eventListeners.has(e)||this.eventListeners.set(e,new Set),this.eventListeners.get(e).add(t)}off(e,t){let n=this.eventListeners.get(e);n&&n.delete(t)}emit(e,t){let n={type:e,timestamp:new Date,phase:this.currentPhase,tddPhase:this.context.currentTDDPhase,subtaskId:this.getCurrentSubtaskId(),data:{...t,adapters:{testValidator:!!this.testResultValidator,gitHook:!!this.gitOperationHook,executeHook:!!this.executeHook}}},r=this.eventListeners.get(e);r&&r.forEach(e=>e(n))}getCurrentSubtaskId(){return this.context.subtasks[this.context.currentSubtaskIndex]?.id}onStatePersist(e){this.persistCallback=e}enableAutoPersist(e){this.persistCallback=e,this.autoPersistEnabled=!0}disableAutoPersist(){this.autoPersistEnabled=!1}async persistState(){this.persistCallback&&await this.persistCallback(this.getState()),this.emit(`state:persisted`)}async triggerAutoPersist(){this.autoPersistEnabled&&this.persistCallback&&await this.persistCallback(this.getState())}addGuard(e,t){this.phaseGuards.set(e,t)}removeGuard(e){this.phaseGuards.delete(e)}getCurrentSubtask(){return this.context.subtasks[this.context.currentSubtaskIndex]}getProgress(){let e=this.context.subtasks.filter(e=>e.status===`completed`).length,t=this.context.subtasks.length;return{completed:e,total:t,current:this.context.currentSubtaskIndex+1,percentage:t>0?Math.round(e/t*100):0}}canProceed(){return this.currentPhase===`SUBTASK_LOOP`?this.getCurrentSubtask()?.status===`completed`:!1}incrementAttempts(){let e=this.getCurrentSubtask();e&&e.attempts++}hasExceededMaxAttempts(){let e=this.getCurrentSubtask();return!e||!e.maxAttempts?!1:e.attempts>e.maxAttempts}handleError(e){this.context.errors.push(e),this.emit(`error:occurred`,{error:e})}handleRetry(){this.currentPhase===`SUBTASK_LOOP`&&(this.context.currentTDDPhase=`RED`,this.emit(`tdd:red:started`))}retryCurrentSubtask(){this.currentPhase===`SUBTASK_LOOP`&&(this.context.currentTDDPhase=`RED`,this.emit(`tdd:red:started`))}handleMaxAttemptsExceeded(){let e=this.getCurrentSubtask();e&&(e.status=`failed`,this.emit(`subtask:failed`,{subtaskId:e.id,attempts:e.attempts,maxAttempts:e.maxAttempts}))}isAborted(){return this.aborted}canResumeFromState(e){return!(![`PREFLIGHT`,`BRANCH_SETUP`,`SUBTASK_LOOP`,`FINALIZE`,`COMPLETE`].includes(e.phase)||!e.context||typeof e.context!=`object`||!e.context.taskId||!Array.isArray(e.context.subtasks)||typeof e.context.currentSubtaskIndex!=`number`||!Array.isArray(e.context.errors))}setTestResultValidator(e){this.testResultValidator=e,this.emit(`adapter:configured`,{adapterType:`test-validator`})}hasTestResultValidator(){return!!this.testResultValidator}removeTestResultValidator(){this.testResultValidator=void 0}onGitOperation(e){this.gitOperationHook=e}onExecute(e){this.executeHook=e}executeCommand(e){this.executeHook&&this.executeHook(e,this.context)}};async function Ye(e,t){let n={...t,timestamp:new Date().toISOString()};await u.ensureDir(c.dirname(e));let r=JSON.stringify(n)+`
203
+ `;await u.appendFile(e,r,`utf-8`)}const Xe=[`workflow:started`,`workflow:completed`,`workflow:error`,`workflow:resumed`,`phase:entered`,`phase:exited`,`tdd:feature-already-implemented`,`tdd:red:started`,`tdd:red:completed`,`tdd:green:started`,`tdd:green:completed`,`tdd:commit:started`,`tdd:commit:completed`,`subtask:started`,`subtask:completed`,`subtask:failed`,`test:run`,`test:passed`,`test:failed`,`git:branch:created`,`git:commit:created`,`error:occurred`,`state:persisted`,`progress:updated`,`adapter:configured`];var Ze=class{activityLogPath;orchestrator;logger=E(`WorkflowActivityLogger`);listenerMap=new Map;isActive=!1;constructor(e,t){this.orchestrator=e,this.activityLogPath=t}start(){if(this.isActive){this.logger.warn(`Activity logger is already active`);return}Xe.forEach(e=>{let t=e=>this.logEvent(e);this.listenerMap.set(e,t),this.orchestrator.on(e,t)}),this.isActive=!0,this.logger.debug(`Activity logger started, logging to: ${this.activityLogPath}`)}stop(){this.isActive&&(this.listenerMap.forEach((e,t)=>{this.orchestrator.off(t,e)}),this.listenerMap.clear(),this.isActive=!1,this.logger.debug(`Activity logger stopped and listeners removed`))}async logEvent(e){if(this.isActive)try{let t=e.timestamp instanceof Date?e.timestamp.toISOString():new Date(e.timestamp).toISOString(),n={type:e.type,phase:e.phase,tddPhase:e.tddPhase,subtaskId:e.subtaskId,eventTimestamp:t,...e.data||{}};await Ye(this.activityLogPath,n)}catch(t){this.logger.error(`Failed to log activity event ${e.type}: ${t.message}`)}}getActivityLogPath(){return this.activityLogPath}isLogging(){return this.isActive}},Qe=class{projectRoot;stateManager;taskStatusUpdater;tag;logger=E(`WorkflowService`);orchestrator;activityLogger;constructor(e){typeof e==`string`?this.projectRoot=e:(this.projectRoot=e.projectRoot,this.taskStatusUpdater=e.taskStatusUpdater,this.tag=e.tag),this.stateManager=new qe(this.projectRoot)}async updateTaskStatus(e,t,n){if(this.taskStatusUpdater)try{await this.taskStatusUpdater.updateStatus(e,t,n??this.tag)}catch(t){let n=t instanceof Error?t.message:String(t);this.logger.warn(`Failed to update task ${e} status: ${n}`)}}async hasWorkflow(){return await this.stateManager.exists()}async startWorkflow(e){let{taskId:t,taskTitle:n,subtasks:r,maxAttempts:i=3,force:a,tag:o}=e;if(await this.hasWorkflow()&&!a)throw Error(`Workflow already exists. Use force=true to override or resume existing workflow.`);let s=new A(this.projectRoot);await s.ensureGitRepository(),await s.ensureCleanWorkingTree();let c=r.map(e=>({id:e.id,title:e.title,status:e.status===`done`?`completed`:`pending`,attempts:0,maxAttempts:e.maxAttempts||i})),l=c.findIndex(e=>e.status!==`completed`);if(l===-1)throw Error(`All subtasks for task ${t} are already completed. Nothing to do.`);this.orchestrator=new Je({taskId:t,subtasks:c,currentSubtaskIndex:l,tag:o,errors:[],metadata:{startedAt:new Date().toISOString(),taskTitle:n,resumedFromSubtask:l>0?c[l].id:void 0}}),this.orchestrator.enableAutoPersist(async e=>{await this.stateManager.save(e)}),this.activityLogger=new Ze(this.orchestrator,this.stateManager.getActivityLogPath()),this.activityLogger.start(),await this.orchestrator.transition({type:`PREFLIGHT_COMPLETE`});let u=this.generateBranchName(t,n,o);return await s.getCurrentBranch()!==u&&await s.createAndCheckoutBranch(u),await this.orchestrator.transition({type:`BRANCH_CREATED`,branchName:u}),await this.updateTaskStatus(t,`in-progress`,o),this.getStatus()}async resumeWorkflow(){let e=await this.stateManager.load();if(this.orchestrator=new Je(e.context),!this.orchestrator.canResumeFromState(e))throw Error(`Invalid workflow state. State may be corrupted. Consider starting a new workflow.`);return this.orchestrator.restoreState(e),this.orchestrator.enableAutoPersist(async e=>{await this.stateManager.save(e)}),this.activityLogger=new Ze(this.orchestrator,this.stateManager.getActivityLogPath()),this.activityLogger.start(),this.getStatus()}getStatus(){if(!this.orchestrator)throw Error(`No active workflow. Start or resume a workflow first.`);let e=this.orchestrator.getContext(),t=this.orchestrator.getProgress(),n=this.orchestrator.getCurrentSubtask();return{taskId:e.taskId,phase:this.orchestrator.getCurrentPhase(),tddPhase:this.orchestrator.getCurrentTDDPhase(),branchName:e.branchName,currentSubtask:n?{id:n.id,title:n.title,attempts:n.attempts,maxAttempts:n.maxAttempts||3}:void 0,progress:t}}getContext(){if(!this.orchestrator)throw Error(`No active workflow. Start or resume a workflow first.`);return this.orchestrator.getContext()}getNextAction(){if(!this.orchestrator)throw Error(`No active workflow. Start or resume a workflow first.`);let e=this.orchestrator.getCurrentPhase(),t=this.orchestrator.getCurrentTDDPhase(),n=this.orchestrator.getCurrentSubtask();if(e===`COMPLETE`)return{action:`workflow_complete`,description:`All subtasks completed`,nextSteps:`All subtasks completed! Review the entire implementation and merge your branch when ready.`,phase:e};if(e===`FINALIZE`)return{action:`finalize_workflow`,description:`Finalize and complete the workflow`,nextSteps:`All subtasks are complete! Use autopilot_finalize to verify no uncommitted changes remain and mark the workflow as complete.`,phase:e};if(e!==`SUBTASK_LOOP`||!t||!n)return{action:`unknown`,description:`Workflow is not in active state`,nextSteps:`Use autopilot_status to check workflow state.`,phase:e};let r={phase:e,tddPhase:t,subtask:{id:n.id,title:n.title}};switch(t){case`RED`:return{...r,action:`generate_test`,description:`Generate failing test for current subtask`,nextSteps:`Write failing tests for subtask ${n.id}: "${n.title}". Create test file(s) that validate the expected behavior. Run tests and use autopilot_complete_phase with results. Note: If all tests pass (0 failures), the feature is already implemented and the subtask will be auto-completed.`};case`GREEN`:return{...r,action:`implement_code`,description:`Implement feature to make tests pass`,nextSteps:`Implement code to make tests pass for subtask ${n.id}: "${n.title}". Write the minimal code needed to pass all tests (GREEN phase), then use autopilot_complete_phase with test results.`};case`COMMIT`:return{...r,action:`commit_changes`,description:`Commit RED-GREEN cycle changes`,nextSteps:`Review and commit your changes for subtask ${n.id}: "${n.title}". Use autopilot_commit to create the commit and advance to the next subtask.`};default:return{...r,action:`unknown`,description:`Unknown TDD phase`,nextSteps:`Use autopilot_status to check workflow state.`}}}async completePhase(e){if(!this.orchestrator)throw Error(`No active workflow. Start or resume a workflow first.`);let t=this.orchestrator.getCurrentTDDPhase();if(!t)throw Error(`Not in active TDD phase`);switch(t){case`RED`:await this.orchestrator.transition({type:`RED_PHASE_COMPLETE`,testResults:e});break;case`GREEN`:await this.orchestrator.transition({type:`GREEN_PHASE_COMPLETE`,testResults:e});break;case`COMMIT`:throw Error(`Cannot complete COMMIT phase with test results. Use commit() instead.`);default:throw Error(`Unknown TDD phase: ${t}`)}return this.getStatus()}async commit(){if(!this.orchestrator)throw Error(`No active workflow. Start or resume a workflow first.`);let e=this.orchestrator.getCurrentTDDPhase();if(e!==`COMMIT`)throw Error(`Cannot commit in ${e} phase. Complete RED and GREEN phases first.`);let t=this.orchestrator.getCurrentSubtask()?.id;await this.orchestrator.transition({type:`COMMIT_COMPLETE`});let n=this.orchestrator.getProgress();if(n.current<n.total?await this.orchestrator.transition({type:`SUBTASK_COMPLETE`}):await this.orchestrator.transition({type:`ALL_SUBTASKS_COMPLETE`}),t){let e=this.orchestrator.getContext();await this.updateTaskStatus(t,`done`,e.tag)}return this.getStatus()}async finalizeWorkflow(){if(!this.orchestrator)throw Error(`No active workflow. Start or resume a workflow first.`);let e=this.orchestrator.getCurrentPhase();if(e!==`FINALIZE`)throw Error(`Cannot finalize workflow in ${e} phase. Complete all subtasks first.`);let t=await new A(this.projectRoot).getStatusSummary();if(!t.isClean)throw Error(`Cannot finalize workflow: working tree has uncommitted changes.\nStaged: ${t.staged}, Modified: ${t.modified}, Deleted: ${t.deleted}, Untracked: ${t.untracked}\nPlease commit all changes before finalizing the workflow.`);let n=this.orchestrator.getContext(),r=n.taskId;await this.orchestrator.transition({type:`FINALIZE_COMPLETE`});let i=this.getStatus();return await this.updateTaskStatus(r,`done`,n.tag),await this.stateManager.delete(),this.orchestrator=void 0,i}async abortWorkflow(){this.orchestrator&&await this.orchestrator.transition({type:`ABORT`}),await this.stateManager.delete(),this.orchestrator=void 0}generateBranchName(e,t,n){let r=t.toLowerCase().replace(/[^a-z0-9]+/g,`-`).replace(/^-+|-+$/g,``).substring(0,50),i=e.replace(/\./g,`-`);return`${n?`tm/${n}`:`tm`}/task-${i}-${r}`}},$e=class{workflowService=null;projectRoot;configManager;tasksDomain=null;constructor(e){this.configManager=e,this.projectRoot=e.getProjectRoot()}setTasksDomain(e){this.tasksDomain=e}getWorkflowService(){if(!this.workflowService){let e=this.configManager.getActiveTag(),t=this.tasksDomain?{updateStatus:async(e,t,n)=>{await this.tasksDomain.updateStatus(e,t,n)}}:void 0;this.workflowService=new Qe({projectRoot:this.projectRoot,taskStatusUpdater:t,tag:e})}return this.workflowService}resetWorkflowService(){this.workflowService=null}async start(e){return this.resetWorkflowService(),this.getWorkflowService().startWorkflow(e)}async resume(){return this.resetWorkflowService(),this.getWorkflowService().resumeWorkflow()}getStatus(){return this.getWorkflowService().getStatus()}getContext(){return this.getWorkflowService().getContext()}getNextAction(){return this.getWorkflowService().getNextAction()}async completePhase(e){return this.getWorkflowService().completePhase(e)}async commit(){return this.getWorkflowService().commit()}async finalize(){let e=await this.getWorkflowService().finalizeWorkflow();return this.resetWorkflowService(),e}async abort(){await this.getWorkflowService().abortWorkflow(),this.resetWorkflowService()}async hasWorkflow(){return this.getWorkflowService().hasWorkflow()}},et=class e{_projectPath;_configManager;_logger;_tasks;_workflow;_git;_config;_loop;get tasks(){return this._tasks}get workflow(){return this._workflow}get git(){return this._git}get config(){return this._config}get loop(){return this._loop}get logger(){return this._logger}static async create(t){let n=new e(t);return await n.initialize(),n}_options;constructor(e){if(!e.projectPath)throw new O(`Project path is required`,D.MISSING_CONFIGURATION);if(!t.isAbsolute(e.projectPath))throw new O(`Project path must be an absolute path, received: "${e.projectPath}"`,D.INVALID_INPUT);this._projectPath=t.resolve(e.projectPath),this._options=e}async initialize(){try{this._logger=T(this._options.loggerConfig),this._configManager=await pe.create(this._projectPath),this._options.configuration&&await this._configManager.updateConfig(this._options.configuration),this._tasks=new Ke(this._configManager),this._workflow=new $e(this._configManager),this._git=new ye(this._projectPath),this._config=new oe(this._configManager),this._loop=new xe(this._configManager),await this._tasks.initialize(),this._workflow.setTasksDomain(this._tasks),this._logger.info(`TmCore initialized successfully`)}catch(e){throw this._logger&&this._logger.error(`Failed to initialize TmCore:`,e),new O(`Failed to initialize TmCore`,D.INTERNAL_ERROR,{operation:`initialize`},e)}}get projectPath(){return this._projectPath}async close(){this._tasks&&await this._tasks.close()}};async function tt(e){return et.create(e)}function nt(e,n){try{return m.existsSync(t.join(e,n))}catch{return!1}}function Z(e,t){return t.some(t=>nt(e,t))}function rt(e=process.cwd()){let n=t.resolve(e),r=t.parse(n).root,i=0,a=null;if(Z(n,H)||Z(n,U))return n;let o=t.dirname(n);for(i=1;i<50;){let e=Z(o,H),n=Z(o,U);if(e&&(n||i===1))return o;if(n&&!e){a=o;break}if(o===r)break;let s=t.dirname(o);if(s===o)break;o=s,i++}for(n=a||t.resolve(e),i=0;i<50;){if(Z(n,W))return n;if(n===r)break;let e=t.dirname(n);if(e===n)break;n=e,i++}return t.resolve(e)}function it(e){if(!e)return``;let n=String(e).split(t.sep),r=n.findIndex(e=>e===`.taskgraph`);return r===-1?String(e):n.slice(0,r).join(t.sep)||t.sep}function at(e){let t=e?r(process.cwd(),e):rt();return{projectRoot:t,tasksPath:n(t,V)}}function ot(e){return ae(e,`hh:mm:ss a`)}const st=/^\d+(\.\d+)*$/;function Q(e){return st.test(e)}b.string().min(1,`Task ID cannot be empty`).refine(Q,{message:`Invalid task ID format. Expected numeric (e.g., '15') or subtask (e.g., '15.2')`});const ct=b.string().min(1,`Task ID(s) cannot be empty`).refine(e=>{let t=e.split(`,`).map(e=>e.trim()).filter(e=>e.length>0);return t.length>0&&t.every(Q)},{message:`Invalid task ID format. Expected numeric (e.g., '15') or subtask (e.g., '15.2'). Multiple IDs should be comma-separated.`});function lt(e){let t=e.split(`,`).map(e=>e.trim()).filter(e=>e.length>0);if(t.length===0)throw Error(`No valid task IDs provided`);let n=t.filter(e=>!Q(e));if(n.length>0)throw Error(`Invalid task ID format: ${n.join(`, `)}. Expected numeric (e.g., '15') or subtask (e.g., '15.2')`);return t}const ut=/^\d+$/,dt=/^\d+\.\d+$/;function $(e){if(!e)return!1;let t=e.trim();return ut.test(t)||dt.test(t)}function ft(e){return e?ut.test(e.trim()):!1}const pt=b.string().trim().refine($,{message:`Invalid task ID format. Expected numeric ("1") or subtask ("1.2")`}),mt=b.string().trim().refine($,{message:`Invalid task ID format. Expected numeric ("1")`}).refine(ft,{message:`Subtask IDs are not allowed. Please provide a main task ID (e.g., "1")`}),ht=E(`TaskFilters`),gt=[`pending`,`in-progress`,`review`];function _t(e){let t=new Map(e.map(e=>[String(e.id),[]])),n=[];for(let r of e)for(let e of r.dependencies??[]){let i=String(e),a=t.get(i);a?a.push(String(r.id)):n.push({taskId:String(r.id),depId:i})}return{blocksMap:t,invalidDependencies:n}}function vt(e){let t=new Set(e.filter(e=>K(e.status)).map(e=>String(e.id)));return e.filter(e=>(G.includes(e.status)||ht.warn(`Task ${e.id} has unexpected status "${e.status}". Valid statuses are: ${G.join(`, `)}`),gt.includes(e.status)?(e.dependencies??[]).every(e=>t.has(String(e))):!1))}function yt(e){return e.filter(e=>e.blocks.length>0)}export{A as C,M as S,z as _,pt as a,Me as b,ot as c,it as d,tt as f,K as g,G as h,mt as i,at as l,Fe as m,yt as n,lt as o,Pe as p,vt as r,ct as s,_t as t,rt as u,B as v,P as x,je as y};
@@ -0,0 +1 @@
1
+ import"./ai-services-unified-D8KwE3rg.js";import"./src-D5YOCTZ3.js";import"./config-manager-BUm0w7j9.js";import"./git-utils-CrYiSKu0.js";import{$ as e,Q as t,X as n,Z as r,et as i,it as a,nt as o,rt as s,tt as c}from"./dependency-manager-LVhwG4fY.js";import"./response-language-lNB7-WgQ.js";export{n as copyTag,r as createTag,t as createTagFromBranch,e as deleteTag,i as renameTag,c as switchCurrentTag,o as tags,s as updateBranchTagMapping,a as useTag};
@@ -1 +1 @@
1
- import"./ai-services-unified-DbjBfAvG.js";import"./src-lvp18X-h.js";import{J as e,st as t}from"./config-manager-Da0wEujO.js";import"./git-utils-CrYiSKu0.js";import{A as n,B as r,C as i,D as a,E as o,F as s,H as c,I as l,L as u,M as d,N as f,O as p,R as m,S as h,T as g,U as _,V as v,at as y,j as b,k as x,w as S,x as C,z as w}from"./dependency-manager-DIbDdrUV.js";import{t as T}from"./response-language-Cc70IGmg.js";export{_ as addSubtask,c as addTask,v as analyzeTaskComplexity,r as clearSubtasks,m as expandAllTasks,w as expandTask,y as findNextTask,e as findTaskById,u as isTaskDependentOn,l as listTasks,s as moveTask,f as parsePRD,x as performResearch,t as readComplexityReport,d as removeSubtask,n as removeTask,o as scopeDownTask,a as scopeUpTask,T as setResponseLanguage,S as setTaskStatus,b as taskExists,g as updateSingleTaskStatus,i as updateSubtaskById,h as updateTaskById,C as updateTasks,p as validateStrength};
1
+ import"./ai-services-unified-D8KwE3rg.js";import"./src-D5YOCTZ3.js";import{J as e,st as t}from"./config-manager-BUm0w7j9.js";import"./git-utils-CrYiSKu0.js";import{A as n,B as r,C as i,D as a,E as o,F as s,H as c,I as l,L as u,M as d,N as f,O as p,R as m,S as h,T as g,U as _,V as v,at as y,j as b,k as x,w as S,x as C,z as w}from"./dependency-manager-LVhwG4fY.js";import{t as T}from"./response-language-lNB7-WgQ.js";export{_ as addSubtask,c as addTask,v as analyzeTaskComplexity,r as clearSubtasks,m as expandAllTasks,w as expandTask,y as findNextTask,e as findTaskById,u as isTaskDependentOn,l as listTasks,s as moveTask,f as parsePRD,x as performResearch,t as readComplexityReport,d as removeSubtask,n as removeTask,o as scopeDownTask,a as scopeUpTask,T as setResponseLanguage,S as setTaskStatus,b as taskExists,g as updateSingleTaskStatus,i as updateSubtaskById,h as updateTaskById,C as updateTasks,p as validateStrength};
package/dist/taskgraph.js CHANGED
@@ -1,2 +1,2 @@
1
1
  #!/usr/bin/env node
2
- import{p as e}from"./src-lvp18X-h.js";import t from"chalk";import{join as n}from"node:path";import r from"dotenv";function i(e,n=t){e.NO_COLOR&&e.FORCE_COLOR===void 0&&(e.FORCE_COLOR=`0`,n.level=0)}i(process.env);const a=process.cwd(),o=e();r.config({path:n(o,`.env`)}),process.env.TASKGRAPH_ORIGINAL_CWD=a,process.env.DEBUG===`1`&&console.error(`DEBUG - dev.js received args:`,process.argv.slice(2));const{runCLI:s}=await import(`./commands-2aOf3ERj.js`);s(process.argv);export{};
2
+ import{u as e}from"./src-D5YOCTZ3.js";import t from"chalk";import{join as n}from"node:path";import r from"dotenv";function i(e,n=t){e.NO_COLOR&&e.FORCE_COLOR===void 0&&(e.FORCE_COLOR=`0`,n.level=0)}i(process.env);const a=process.cwd(),o=e();r.config({path:n(o,`.env`)}),process.env.TASKGRAPH_ORIGINAL_CWD=a,process.env.DEBUG===`1`&&console.error(`DEBUG - dev.js received args:`,process.argv.slice(2));const{runCLI:s}=await import(`./commands-Btm2oO97.js`);s(process.argv);export{};
@@ -0,0 +1 @@
1
+ import"./ai-services-unified-D8KwE3rg.js";import"./src-D5YOCTZ3.js";import"./config-manager-BUm0w7j9.js";import"./git-utils-CrYiSKu0.js";import{C as e}from"./dependency-manager-LVhwG4fY.js";import"./response-language-lNB7-WgQ.js";export{e as default};
@@ -0,0 +1 @@
1
+ import"./ai-services-unified-D8KwE3rg.js";import"./src-D5YOCTZ3.js";import"./config-manager-BUm0w7j9.js";import"./git-utils-CrYiSKu0.js";import{S as e}from"./dependency-manager-LVhwG4fY.js";import"./response-language-lNB7-WgQ.js";export{e as default};
@@ -1 +1 @@
1
- import"./src-lvp18X-h.js";import{$ as e,B as t,G as n,H as r,J as i,K as a,Q as o,U as s,V as c,W as l,X as u,Y as d,Z as f,at as p,ct as m,dt as h,et as g,ft as _,ht as v,it as y,lt as b,mt as x,nt as S,ot as C,pt as w,q as T,rt as E,st as D,tt as O,ut as k,z as A}from"./config-manager-Da0wEujO.js";import"./git-utils-CrYiSKu0.js";export{A as LOG_LEVELS,t as addComplexityToTask,c as aggregateTelemetry,r as createStateJson,s as disableSilentMode,l as enableSilentMode,n as ensureTagMetadata,a as findCycles,T as findProjectRoot,i as findTaskById,d as findTaskInComplexityReport,u as flattenTasksWithSubtasks,f as formatTaskId,o as getCurrentTag,e as getTasksForTag,g as isEmpty,O as isSilentMode,S as log,E as markMigrationForNotice,y as migrateConfigJson,p as normalizeTaskIds,C as performCompleteTagMigration,D as readComplexityReport,m as readJSON,b as resolveEnvVariable,k as resolveTag,h as taskExists,_ as traverseDependencies,w as truncate,x as withFileLockSync,v as writeJSON};
1
+ import"./src-D5YOCTZ3.js";import{$ as e,B as t,G as n,H as r,J as i,K as a,Q as o,U as s,V as c,W as l,X as u,Y as d,Z as f,at as p,ct as m,dt as h,et as g,ft as _,ht as v,it as y,lt as b,mt as x,nt as S,ot as C,pt as w,q as T,rt as E,st as D,tt as O,ut as k,z as A}from"./config-manager-BUm0w7j9.js";import"./git-utils-CrYiSKu0.js";export{A as LOG_LEVELS,t as addComplexityToTask,c as aggregateTelemetry,r as createStateJson,s as disableSilentMode,l as enableSilentMode,n as ensureTagMetadata,a as findCycles,T as findProjectRoot,i as findTaskById,d as findTaskInComplexityReport,u as flattenTasksWithSubtasks,f as formatTaskId,o as getCurrentTag,e as getTasksForTag,g as isEmpty,O as isSilentMode,S as log,E as markMigrationForNotice,y as migrateConfigJson,p as normalizeTaskIds,C as performCompleteTagMigration,D as readComplexityReport,m as readJSON,b as resolveEnvVariable,k as resolveTag,h as taskExists,_ as traverseDependencies,w as truncate,x as withFileLockSync,v as writeJSON};
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "taskgraph-ai",
3
- "version": "0.50.1",
3
+ "version": "0.52.0",
4
4
  "description": "Task management for AI-driven development, built for Claude Code: plan from a PRD, then work tasks one at a time with slash commands, a CLI or an MCP server.",
5
5
  "main": "index.js",
6
6
  "type": "module",
@@ -1 +0,0 @@
1
- import{a as e,i as t,n,r,t as i}from"./ai-services-unified-DbjBfAvG.js";import"./src-lvp18X-h.js";import"./config-manager-Da0wEujO.js";import"./git-utils-CrYiSKu0.js";export{i as generateObjectService,n as generateTextService,r as logAiUsage,t as streamObjectService,e as streamTextService};
@@ -1 +0,0 @@
1
- import"./ai-services-unified-DbjBfAvG.js";import"./src-lvp18X-h.js";import"./config-manager-Da0wEujO.js";import"./git-utils-CrYiSKu0.js";import{k as e}from"./dependency-manager-DIbDdrUV.js";import"./response-language-Cc70IGmg.js";export{e as performResearch};
@@ -1 +0,0 @@
1
- import"./src-lvp18X-h.js";import"./config-manager-Da0wEujO.js";import"./git-utils-CrYiSKu0.js";import{t as e}from"./response-language-Cc70IGmg.js";export{e as default};
@@ -1 +0,0 @@
1
- import"./ai-services-unified-DbjBfAvG.js";import"./src-lvp18X-h.js";import"./config-manager-Da0wEujO.js";import"./git-utils-CrYiSKu0.js";import{$ as e,Q as t,X as n,Z as r,et as i,it as a,nt as o,rt as s,tt as c}from"./dependency-manager-DIbDdrUV.js";import"./response-language-Cc70IGmg.js";export{n as copyTag,r as createTag,t as createTagFromBranch,e as deleteTag,i as renameTag,c as switchCurrentTag,o as tags,s as updateBranchTagMapping,a as useTag};
@@ -1 +0,0 @@
1
- import"./ai-services-unified-DbjBfAvG.js";import"./src-lvp18X-h.js";import"./config-manager-Da0wEujO.js";import"./git-utils-CrYiSKu0.js";import{C as e}from"./dependency-manager-DIbDdrUV.js";import"./response-language-Cc70IGmg.js";export{e as default};
@@ -1 +0,0 @@
1
- import"./ai-services-unified-DbjBfAvG.js";import"./src-lvp18X-h.js";import"./config-manager-Da0wEujO.js";import"./git-utils-CrYiSKu0.js";import{S as e}from"./dependency-manager-DIbDdrUV.js";import"./response-language-Cc70IGmg.js";export{e as default};