warp-task-master
Version:
BETA: Experimental Task Master fork with Warp AI integration and human-readable profile names. For production use, see task-master-ai.
49 lines (46 loc) âĸ 52.7 kB
JavaScript
import{__export as e}from"./ai-services-unified-Bp0J8TPk.js";import{ENV_EXAMPLE_FILE as t,EXAMPLE_PRD_FILE as n,GITIGNORE_FILE as r,TASKMASTER_CONFIG_FILE as i,TASKMASTER_DIR as a,TASKMASTER_DOCS_DIR as o,TASKMASTER_REPORTS_DIR as s,TASKMASTER_STATE_FILE as c,TASKMASTER_TASKS_DIR as l,TASKMASTER_TEMPLATES_DIR as u,isSilentMode as d,log as f,supported_models_default as p}from"./utils-Can7ymw4.js";import{insideGitWorkTree as m}from"./git-utils-TLODVPko.js";import h from"path";import g from"chalk";import _ from"boxen";import v from"fs";import y from"inquirer";import{fileURLToPath as b}from"url";import{execSync as x}from"child_process";import S from"figlet";import C from"gradient-string";import w from"readline";const T=b(import.meta.url),E=h.dirname(T);function D(){let e=[h.join(E,`assets`),h.join(E,`..`,`assets`),h.join(E,`..`,`..`,`public`,`assets`),h.join(process.cwd(),`assets`),h.join(process.cwd(),`node_modules`,`task-master-ai`,`dist`,`assets`),h.join(process.cwd(),`node_modules`,`task-master-ai`,`assets`)];for(let t of e)if(v.existsSync(t)){let e=h.join(t,`rules`,`taskmaster.mdc`);if(v.existsSync(e))return t}throw Error(`Assets directory not found. This is likely a packaging issue.`)}function ee(e){let t=D();return h.join(t,e)}function te(e){try{let t=ee(e);return v.existsSync(t)}catch(e){return!1}}function O(e,t=`utf8`){let n=ee(e);return v.readFileSync(n,t)}function k(e){let t=JSON.stringify(e,null,` `);return t=t.replace(/(\[\n\t+)([^[\]]+?)(\n\t+\])/g,(e,t,n,r)=>!n.includes(`{`)&&!n.includes(`[`)?`[${n.replace(/\n\t+/g,` `).replace(/\s+/g,` `).trim()}]`:e),t}function ne(e,t){if(!t){f(`debug`,`[MCP Config] No mcpConfigPath provided, skipping MCP configuration setup`);return}let n=h.join(e,t),r=h.dirname(n);f(`info`,`Setting up MCP configuration at ${n}...`);let i={"task-master-ai":{command:`npx`,args:[`-y`,`task-master-ai`],env:{ANTHROPIC_API_KEY:`YOUR_ANTHROPIC_API_KEY_HERE`,PERPLEXITY_API_KEY:`YOUR_PERPLEXITY_API_KEY_HERE`,OPENAI_API_KEY:`YOUR_OPENAI_KEY_HERE`,GOOGLE_API_KEY:`YOUR_GOOGLE_KEY_HERE`,XAI_API_KEY:`YOUR_XAI_KEY_HERE`,OPENROUTER_API_KEY:`YOUR_OPENROUTER_KEY_HERE`,MISTRAL_API_KEY:`YOUR_MISTRAL_KEY_HERE`,AZURE_OPENAI_API_KEY:`YOUR_AZURE_KEY_HERE`,OLLAMA_API_KEY:`YOUR_OLLAMA_API_KEY_HERE`}}};if(v.existsSync(r)||v.mkdirSync(r,{recursive:!0}),v.existsSync(n)){f(`info`,`MCP configuration file already exists, checking for existing task-master-ai...`);try{let e=JSON.parse(v.readFileSync(n,`utf8`));if(e.mcpServers||(e.mcpServers={}),Object.values(e.mcpServers).some(e=>e.args&&Array.isArray(e.args)&&e.args.some(e=>typeof e==`string`&&e.includes(`task-master-ai`)))){f(`info`,`Found existing task-master-ai MCP configuration in mcp.json, leaving untouched`);return}e.mcpServers[`task-master-ai`]?f(`info`,`task-master-ai server already configured in mcp.json`):(e.mcpServers[`task-master-ai`]=i[`task-master-ai`],f(`info`,`Added task-master-ai server to existing MCP configuration`)),v.writeFileSync(n,k(e)+`
`),f(`success`,`Updated MCP configuration file`)}catch(e){f(`error`,`Failed to update MCP configuration: ${e.message}`);let t=`${n}.backup-${Date.now()}`;v.existsSync(n)&&(v.copyFileSync(n,t),f(`info`,`Created backup of existing mcp.json at ${t}`));let r={mcpServers:i};v.writeFileSync(n,k(r)+`
`),f(`warn`,`Created new MCP configuration file (backup of original file was created if it existed)`)}}else{let e={mcpServers:i};v.writeFileSync(n,k(e)+`
`),f(`success`,`Created MCP configuration file at ${n}`)}f(`info`,`MCP server will use the installed task-master-ai package`)}function re(e,t){if(!t)return{success:!0,removed:!1,deleted:!1,error:null,hasOtherServers:!1};let n=h.join(e,t),r={success:!1,removed:!1,deleted:!1,error:null,hasOtherServers:!1};if(!v.existsSync(n))return r.success=!0,r.removed=!1,f(`debug`,`[MCP Config] MCP config file does not exist: ${n}`),r;try{let e=JSON.parse(v.readFileSync(n,`utf8`));if(!e.mcpServers)return r.success=!0,r.removed=!1,f(`debug`,`[MCP Config] No mcpServers section found in: ${n}`),r;if(!(e.mcpServers[`task-master-ai`]||Object.values(e.mcpServers).some(e=>e.args&&Array.isArray(e.args)&&e.args.some(e=>typeof e==`string`&&e.includes(`task-master-ai`)))))return r.success=!0,r.removed=!1,f(`debug`,`[MCP Config] Task Master not found in MCP config: ${n}`),r;delete e.mcpServers[`task-master-ai`],Object.keys(e.mcpServers).forEach(t=>{let n=e.mcpServers[t];n.args&&Array.isArray(n.args)&&n.args.some(e=>typeof e==`string`&&e.includes(`task-master-ai`))&&(delete e.mcpServers[t],f(`debug`,`[MCP Config] Removed server '${t}' containing task-master-ai`))});let t=Object.keys(e.mcpServers);r.hasOtherServers=t.length>0,r.hasOtherServers?(v.writeFileSync(n,k(e)+`
`),r.success=!0,r.removed=!0,r.deleted=!1,f(`info`,`[MCP Config] Removed Task Master from MCP config, preserving other servers: ${t.join(`, `)}`)):(v.rmSync(n,{force:!0}),r.success=!0,r.removed=!0,r.deleted=!0,f(`info`,`[MCP Config] Removed MCP config file (no other servers remaining): ${n}`))}catch(e){r.error=e.message,f(`error`,`[MCP Config] Failed to remove Task Master from MCP config: ${e.message}`)}return r}const A=[`amp`,`claude`,`cline`,`codex`,`cursor`,`gemini`,`kiro`,`opencode`,`kilo`,`roo`,`trae`,`vscode`,`windsurf`,`zed`],ie=[`architect`,`ask`,`orchestrator`,`code`,`debug`,`test`];function j(e){let{name:t,displayName:n=t,url:r,docsUrl:i,profileDir:a=`.${t.toLowerCase()}`,rulesDir:o=`${a}/rules`,mcpConfig:s=!0,mcpConfigName:c=s?`mcp.json`:null,fileExtension:l=`.mdc`,targetExtension:u=`.md`,toolMappings:d={},customReplacements:f=[],fileMap:p={},supportsRulesSubdirectories:m=!1,includeDefaultRules:g=!0,onAdd:_,onRemove:v,onPostConvert:y}=e,b=c?h.join(a,c):null,x=m?`taskmaster/`:``,S={"rules/cursor_rules.mdc":`${t.toLowerCase()}_rules${u}`,"rules/dev_workflow.mdc":`${x}dev_workflow${u}`,"rules/self_improve.mdc":`self_improve${u}`,"rules/taskmaster.mdc":`${x}taskmaster${u}`},C=g?{...S,...p}:p,w=[{from:/cursor\.so/gi,to:r},{from:/cursor\s*\.\s*so/gi,to:r},{from:/https?:\/\/cursor\.so/gi,to:`https://${r}`},{from:/https?:\/\/www\.cursor\.so/gi,to:`https://www.${r}`},{from:/\bedit_file\b/gi,to:d.edit_file||`edit_file`},{from:/\bsearch tool\b/gi,to:`${d.search||`search`} tool`},{from:/\bSearch Tool\b/g,to:`${d.search||`Search`} Tool`},{from:/\bcursor\b/gi,to:e=>e.charAt(0)===`C`?n:t.toLowerCase()},{from:/Cursor/g,to:n},{from:/CURSOR/g,to:n.toUpperCase()},...u===l?[]:[{from:RegExp(`\\${l}(?!\\])\\b`,`g`),to:u}],{from:/docs\.cursor\.com/gi,to:i},...f],T={search:`search`,read_file:`read_file`,edit_file:`edit_file`,create_file:`create_file`,run_command:`run_command`,terminal_command:`terminal_command`,use_mcp:`use_mcp`,switch_mode:`switch_mode`,...d},E={profileTerms:[{from:/cursor\.so/g,to:r},{from:/\[cursor\.so\]/g,to:`[${r}]`},{from:/href="https:\/\/cursor\.so/g,to:`href="https://${r}`},{from:/\(https:\/\/cursor\.so/g,to:`(https://${r}`},{from:/\bcursor\b/gi,to:e=>e===`Cursor`?n:t.toLowerCase()},{from:/Cursor/g,to:n}],fileExtensions:u===l?[]:[{from:RegExp(`\\${l}\\b`,`g`),to:u}],docUrls:[{from:RegExp(`https:\\/\\/docs\\.cursor\\.com\\/[^\\s)'"]+`,`g`),to:e=>e.replace(`docs.cursor.com`,i)},{from:RegExp(`https:\\/\\/${i}\\/`,`g`),to:`https://${i}/`}],toolNames:T,toolContexts:Object.entries(T).flatMap(([e,t])=>[{from:RegExp(`\\b${e} tool\\b`,`g`),to:`${t} tool`},{from:RegExp(`\\bthe ${e}\\b`,`g`),to:`the ${t}`},{from:RegExp(`\\bThe ${e}\\b`,`g`),to:`The ${t}`},{from:RegExp(`\\bCursor ${e}\\b`,`g`),to:`${n} ${t}`}]),toolGroups:[{from:/\bSearch tools\b/g,to:`Read Group tools`},{from:/\bEdit tools\b/g,to:`Edit Group tools`},{from:/\bRun tools\b/g,to:`Command Group tools`},{from:/\bMCP servers\b/g,to:`MCP Group tools`},{from:/\bSearch Group\b/g,to:`Read Group`},{from:/\bEdit Group\b/g,to:`Edit Group`},{from:/\bRun Group\b/g,to:`Command Group`}],fileReferences:{pathPattern:/\[(.+?)\]\(mdc:\.cursor\/rules\/(.+?)\.mdc\)/g,replacement:(e,n,r)=>{let i=h.basename(r,`.mdc`),a=C[`rules/${i}.mdc`]||`${i}${u}`,s=h.basename(a);return t.toLowerCase()===`cursor`?`[${s}](mdc:${o}/${a})`:`[${s}](${o}/${a})`}}};function D(e){return C[e]?C[e]:u===l?e:e.replace(RegExp(`\\${l}$`),u)}return{profileName:t,displayName:n,profileDir:a,rulesDir:o,mcpConfig:s,mcpConfigName:c,mcpConfigPath:b,supportsRulesSubdirectories:m,includeDefaultRules:g,fileMap:C,globalReplacements:w,conversionConfig:E,getTargetRuleFilename:D,targetExtension:u,..._&&{onAddRulesProfile:_},...v&&{onRemoveRulesProfile:v},...y&&{onPostConvertRulesProfile:y}}}const ae={STANDARD:{},ROO_STYLE:{edit_file:`apply_diff`,search:`search_files`,create_file:`write_to_file`,run_command:`execute_command`,terminal_command:`execute_command`,use_mcp:`use_mcp_tool`}};function oe(e){let t={};e.mcpServers&&(t[`amp.mcpServers`]=e.mcpServers);for(let[n,r]of Object.entries(e))n!==`mcpServers`&&(t[n]=r);return t}function se(e,t){let n=h.join(t,`AGENTS.md`),r=h.join(e,`AGENT.md`),i=h.join(e,`.taskmaster`,`AGENT.md`),a=`@./.taskmaster/AGENT.md`,o=`\n## Task Master AI Instructions\n**Import Task Master's development workflow commands and guidelines, treat as if import is in the main AGENT.md file.**\n${a}`;if(v.existsSync(n))try{let t=h.join(e,`.taskmaster`);if(v.existsSync(t)||v.mkdirSync(t,{recursive:!0}),v.copyFileSync(n,i),f(`debug`,`[Amp] Created Task Master instructions at ${i}`),v.existsSync(r)){let e=v.readFileSync(r,`utf8`);if(e.includes(a))f(`info`,`[Amp] Task Master import already present in ${r}`);else{let t=e.trim()+`
`+o+`
`;v.writeFileSync(r,t),f(`info`,`[Amp] Added Task Master import to existing ${r}`)}}else{let e=`# Amp Instructions\n${o}\n`;v.writeFileSync(r,e),f(`info`,`[Amp] Created ${r} with Task Master import`)}}catch(e){f(`error`,`[Amp] Failed to set up Amp instructions: ${e.message}`)}}function ce(e){let t=h.join(e,`AGENT.md`),n=h.join(e,`.taskmaster`,`AGENT.md`);try{if(v.existsSync(n)&&(v.rmSync(n,{force:!0}),f(`debug`,`[Amp] Removed ${n}`)),v.existsSync(t)){let e=v.readFileSync(t,`utf8`).split(`
`),n=[],r=0;for(let t=0;t<e.length;t++){if(r>0){r--;continue}if(e[t].includes(`## Task Master AI Instructions`)){r=2;continue}e[t].trim()!==`@./.taskmaster/AGENT.md`&&n.push(e[t])}let i=n.join(`
`).replace(/\n{3,}/g,`
`).trim();i===`# Amp Instructions`||i===``?(v.rmSync(t,{force:!0}),f(`debug`,`[Amp] Removed empty ${t}`)):(v.writeFileSync(t,i+`
`),f(`debug`,`[Amp] Removed Task Master import from ${t}`))}}catch(e){f(`error`,`[Amp] Failed to remove Amp instructions: ${e.message}`)}let r=h.join(e,`.vscode`,`settings.json`);if(!v.existsSync(r)){f(`debug`,`[Amp] No .vscode/settings.json found to clean up`);return}try{let t=v.readFileSync(r,`utf8`),n=JSON.parse(t);if(n[`amp.mcpServers`]&&n[`amp.mcpServers`][`task-master-ai`])if(delete n[`amp.mcpServers`][`task-master-ai`],Object.keys(n[`amp.mcpServers`]).length===0&&(delete n[`amp.mcpServers`],f(`debug`,`[Amp] Removed empty amp.mcpServers section`)),Object.keys(n).length===0){v.rmSync(r,{force:!0}),f(`info`,`[Amp] Removed empty settings.json file`);let t=h.join(e,`.vscode`);v.existsSync(t)&&v.readdirSync(t).length===0&&(v.rmSync(t,{recursive:!0,force:!0}),f(`debug`,`[Amp] Removed empty .vscode directory`))}else v.writeFileSync(r,JSON.stringify(n,null,` `)+`
`),f(`info`,`[Amp] Removed TaskMaster from settings.json, preserved other configurations`);else f(`debug`,`[Amp] TaskMaster not found in amp.mcpServers`)}catch(e){f(`error`,`[Amp] Failed to clean up settings.json: ${e.message}`)}}function le(e,t){se(e,t);let n=h.join(e,`.vscode`,`settings.json`);if(!v.existsSync(n)){f(`debug`,`[Amp] No .vscode/settings.json found to transform`);return}try{let e=v.readFileSync(n,`utf8`),t=JSON.parse(e);if(t[`amp.mcpServers`]){f(`info`,`[Amp] settings.json already in Amp format, skipping transformation`);return}let r=oe(t);v.writeFileSync(n,JSON.stringify(r,null,` `)+`
`),f(`info`,`[Amp] Transformed settings.json to Amp format`),f(`debug`,`[Amp] Renamed mcpServers to amp.mcpServers`)}catch(e){f(`error`,`[Amp] Failed to transform settings.json: ${e.message}`)}}const ue=j({name:`amp`,displayName:`Amp`,url:`ampcode.com`,docsUrl:`ampcode.com/manual`,profileDir:`.vscode`,rulesDir:`.`,mcpConfig:!0,mcpConfigName:`settings.json`,includeDefaultRules:!1,fileMap:{"AGENTS.md":`.taskmaster/AGENT.md`},onAdd:se,onRemove:ce,onPostConvert:le});function M(e,t){let n=v.existsSync(e),r=n&&v.statSync(e);n&&r.isDirectory()?(v.existsSync(t)||v.mkdirSync(t,{recursive:!0}),v.readdirSync(e).forEach(n=>{M(h.join(e,n),h.join(t,n))})):v.copyFileSync(e,t)}function de(e){if(v.existsSync(e))try{return v.rmSync(e,{recursive:!0,force:!0}),!0}catch(t){return f(`error`,`Failed to remove directory ${e}: ${t.message}`),!1}return!0}function N(e,t){let n=h.join(t,`claude`),r=h.join(e,`.claude`);if(!v.existsSync(n)){f(`error`,`[Claude] Source directory does not exist: ${n}`);return}try{M(n,r),f(`debug`,`[Claude] Copied .claude directory to ${r}`)}catch(e){f(`error`,`[Claude] An error occurred during directory copy: ${e.message}`)}let i=h.join(t,`AGENTS.md`),a=h.join(e,`CLAUDE.md`),o=h.join(e,`.taskmaster`,`CLAUDE.md`),s=`@./.taskmaster/CLAUDE.md`,c=`\n## Task Master AI Instructions\n**Import Task Master's development workflow commands and guidelines, treat as if import is in the main CLAUDE.md file.**\n${s}`;if(v.existsSync(i))try{let t=h.join(e,`.taskmaster`);if(v.existsSync(t)||v.mkdirSync(t,{recursive:!0}),v.copyFileSync(i,o),f(`debug`,`[Claude] Created Task Master instructions at ${o}`),v.existsSync(a)){let e=v.readFileSync(a,`utf8`);if(e.includes(s))f(`info`,`[Claude] Task Master import already present in ${a}`);else{let t=e.trim()+`
`+c+`
`;v.writeFileSync(a,t),f(`info`,`[Claude] Added Task Master import to existing ${a}`)}}else{let e=`# Claude Code Instructions\n${c}\n`;v.writeFileSync(a,e),f(`info`,`[Claude] Created ${a} with Task Master import`)}}catch(e){f(`error`,`[Claude] Failed to set up Claude instructions: ${e.message}`)}}function fe(e){let t=h.join(e,`.claude`);de(t)&&f(`debug`,`[Claude] Removed .claude directory from ${t}`);let n=h.join(e,`CLAUDE.md`),r=h.join(e,`.taskmaster`,`CLAUDE.md`);try{if(v.existsSync(r)&&(v.rmSync(r,{force:!0}),f(`debug`,`[Claude] Removed ${r}`)),v.existsSync(n)){let e=v.readFileSync(n,`utf8`).split(`
`),t=[],r=0;for(let n=0;n<e.length;n++){if(r>0){r--;continue}if(e[n].includes(`## Task Master AI Instructions`)){r=2;continue}e[n].trim()!==`@./.taskmaster/CLAUDE.md`&&t.push(e[n])}let i=t.join(`
`).replace(/\n{3,}/g,`
`).trim();i===`# Claude Code Instructions`||i===``?(v.rmSync(n,{force:!0}),f(`debug`,`[Claude] Removed empty ${n}`)):(v.writeFileSync(n,i+`
`),f(`debug`,`[Claude] Removed Task Master import from ${n}`))}}catch(e){f(`error`,`[Claude] Failed to remove Claude instructions: ${e.message}`)}}function pe(e){let t={};if(e.mcpServers){t.mcpServers={};for(let[n,r]of Object.entries(e.mcpServers)){let e={};e.type=`stdio`,r.command&&(e.command=r.command),r.args&&(e.args=r.args),r.env&&(e.env=r.env),Object.keys(r).forEach(t=>{[`command`,`args`,`env`,`type`].includes(t)||(e[t]=r[t])}),t.mcpServers[n]=e}}return t}function me(e,t){N(e,t);let n=h.join(e,`.mcp.json`);if(v.existsSync(n))try{let e=JSON.parse(v.readFileSync(n,`utf8`)),t=pe(e);v.writeFileSync(n,JSON.stringify(t,null,` `)+`
`),f(`debug`,`[Claude] Transformed MCP configuration to Claude format at ${n}`)}catch(e){f(`error`,`[Claude] Failed to transform MCP configuration: ${e.message}`)}}const he=j({name:`claude`,displayName:`Claude Code`,url:`claude.ai`,docsUrl:`docs.anthropic.com/en/docs/claude-code`,profileDir:`.`,rulesDir:`.`,mcpConfigName:`.mcp.json`,includeDefaultRules:!1,fileMap:{"AGENTS.md":`.taskmaster/CLAUDE.md`},onAdd:N,onRemove:fe,onPostConvert:me}),ge=j({name:`cline`,displayName:`Cline`,url:`cline.bot`,docsUrl:`docs.cline.bot`,profileDir:`.clinerules`,rulesDir:`.clinerules`,mcpConfig:!1}),_e=j({name:`codex`,displayName:`Codex`,url:`codex.ai`,docsUrl:`platform.openai.com/docs/codex`,profileDir:`.`,rulesDir:`.`,mcpConfig:!1,mcpConfigName:null,includeDefaultRules:!1,fileMap:{"AGENTS.md":`AGENTS.md`}}),ve=j({name:`cursor`,displayName:`Cursor`,url:`cursor.so`,docsUrl:`docs.cursor.com`,targetExtension:`.mdc`,supportsRulesSubdirectories:!0}),ye=j({name:`gemini`,displayName:`Gemini`,url:`codeassist.google`,docsUrl:`github.com/google-gemini/gemini-cli`,profileDir:`.gemini`,rulesDir:`.`,mcpConfigName:`settings.json`,includeDefaultRules:!1,fileMap:{"AGENTS.md":`GEMINI.md`}});function P(e){let t=[{from:/\broo\b/gi,to:e=>e.charAt(0)===`R`?`Kilo`:`kilo`},{from:/Roo/g,to:`Kilo`},{from:/ROO/g,to:`KILO`},{from:/roocode\.com/gi,to:`kilocode.com`},{from:/docs\.roocode\.com/gi,to:`docs.kilocode.com`},{from:/https?:\/\/roocode\.com/gi,to:`https://kilocode.com`},{from:/https?:\/\/docs\.roocode\.com/gi,to:`https://docs.kilocode.com`},{from:/\.roo\//g,to:`.kilo/`},{from:/\.roomodes/g,to:`.kilocodemodes`},{from:/roo-rules/g,to:`kilo-rules`},{from:/rules-roo/g,to:`rules-kilo`}],n=e;for(let e of t)n=n.replace(e.from,e.to);return n}function F(e,t){let n=v.existsSync(e),r=n&&v.statSync(e);n&&r.isDirectory()?(v.existsSync(t)||v.mkdirSync(t,{recursive:!0}),v.readdirSync(e).forEach(n=>{F(h.join(e,n),h.join(t,n))})):v.copyFileSync(e,t)}function I(e,t){let n=h.join(t,`roocode`);if(!v.existsSync(n)){f(`error`,`[Kilo] Source directory does not exist: ${n}`);return}F(n,e),f(`debug`,`[Kilo] Copied roocode directory to ${e}`);let r=h.join(n,`.roomodes`),i=h.join(e,`.kilocodemodes`);if(v.existsSync(r))try{let t=v.readFileSync(r,`utf8`),n=P(t);v.writeFileSync(i,n),f(`debug`,`[Kilo] Created .kilocodemodes at ${i}`),v.unlinkSync(h.join(e,`.roomodes`))}catch(e){f(`error`,`[Kilo] Failed to transform .roomodes: ${e.message}`)}let a=h.join(n,`.roo`),o=h.join(e,`.kilo`);v.existsSync(h.join(e,`.roo`))&&v.rmSync(h.join(e,`.roo`),{recursive:!0,force:!0});for(let e of ie){let t=h.join(a,`rules-${e}`,`${e}-rules`),n=h.join(o,`rules-${e}`,`${e}-rules`);if(v.existsSync(t))try{let r=h.dirname(n);v.existsSync(r)||v.mkdirSync(r,{recursive:!0});let i=v.readFileSync(t,`utf8`),a=P(i);v.writeFileSync(n,a),f(`debug`,`[Kilo] Transformed and copied ${e}-rules to ${n}`)}catch(e){f(`error`,`[Kilo] Failed to transform ${t} to ${n}: ${e.message}`)}}}function be(e){let t=h.join(e,`.kilocodemodes`);if(v.existsSync(t))try{v.rmSync(t,{force:!0}),f(`debug`,`[Kilo] Removed .kilocodemodes from ${t}`)}catch(e){f(`error`,`[Kilo] Failed to remove .kilocodemodes: ${e.message}`)}let n=h.join(e,`.kilo`);if(v.existsSync(n)&&(v.readdirSync(n).forEach(e=>{if(e.startsWith(`rules-`)){let t=h.join(n,e);try{v.rmSync(t,{recursive:!0,force:!0}),f(`debug`,`[Kilo] Removed ${e} directory from ${t}`)}catch(e){f(`error`,`[Kilo] Failed to remove ${t}: ${e.message}`)}}}),v.readdirSync(n).length===0))try{v.rmSync(n,{recursive:!0,force:!0}),f(`debug`,`[Kilo] Removed empty .kilo directory from ${n}`)}catch(e){f(`error`,`[Kilo] Failed to remove .kilo directory: ${e.message}`)}}function xe(e,t){I(e,t)}const Se=j({name:`kilo`,displayName:`Kilo Code`,url:`kilocode.com`,docsUrl:`docs.kilocode.com`,profileDir:`.kilo`,rulesDir:`.kilo/rules`,toolMappings:ae.ROO_STYLE,fileMap:{"rules/cursor_rules.mdc":`kilo_rules.md`,"rules/dev_workflow.mdc":`dev_workflow.md`,"rules/self_improve.mdc":`self_improve.md`,"rules/taskmaster.mdc":`taskmaster.md`},onAdd:I,onRemove:be,onPostConvert:xe}),Ce=j({name:`kiro`,displayName:`Kiro`,url:`kiro.dev`,docsUrl:`kiro.dev/docs`,profileDir:`.kiro`,rulesDir:`.kiro/steering`,mcpConfig:!0,mcpConfigName:`settings/mcp.json`,includeDefaultRules:!0,targetExtension:`.md`,fileMap:{"rules/taskmaster_hooks_workflow.mdc":`taskmaster_hooks_workflow.md`},customReplacements:[{from:/\.cursor\/rules/g,to:`.kiro/steering`},{from:/\.cursor\/mcp\.json/g,to:`.kiro/settings/mcp.json`},{from:/\.kiro\/rules/g,to:`.kiro/steering`},{from:/\[(.+?)\]\(mdc:\.cursor\/rules\/(.+?)\.mdc\)/g,to:`[$1](.kiro/steering/$2.md)`},{from:/rules directory/g,to:`steering directory`},{from:/cursor rules/gi,to:`Kiro steering files`},{from:/^---\n(?:description:\s*[^\n]*\n)?(?:globs:\s*[^\n]*\n)?(?:alwaysApply:\s*true\n)?---/m,to:`---
inclusion: always
---`}],onPostConvert:(e,t)=>{let n=h.join(t,`kiro-hooks`),r=h.join(e,`.kiro`,`hooks`);if(v.existsSync(r)||v.mkdirSync(r,{recursive:!0}),v.existsSync(n)){let e=v.readdirSync(n).filter(e=>e.endsWith(`.kiro.hook`));e.forEach(e=>{let t=h.join(n,e),i=h.join(r,e);v.copyFileSync(t,i)}),e.length>0&&f(`info`,`[Kiro] Installed ${e.length} Taskmaster hooks in .kiro/hooks/`)}}});function we(e){let t={$schema:`https://opencode.ai/config.json`};if(e.mcpServers){t.mcp={};for(let[n,r]of Object.entries(e.mcpServers)){let e={type:`local`};r.command&&r.args?e.command=[r.command,...r.args]:r.command&&(e.command=[r.command]),e.enabled=!0,r.env&&(e.environment=r.env),t.mcp[n]=e}}return t}function Te(e,t){let n=h.join(e,`opencode.json`);if(!v.existsSync(n)){f(`debug`,`[OpenCode] No opencode.json found to transform`);return}try{let e=v.readFileSync(n,`utf8`),t=JSON.parse(e);if(t.$schema){f(`info`,`[OpenCode] opencode.json already in OpenCode format, skipping transformation`);return}let r=we(t);v.writeFileSync(n,JSON.stringify(r,null,2)+`
`),f(`info`,`[OpenCode] Transformed opencode.json to OpenCode format`),f(`debug`,`[OpenCode] Added schema, renamed mcpServers->mcp, combined command+args, added type/enabled, renamed env->environment`)}catch(e){f(`error`,`[OpenCode] Failed to transform opencode.json: ${e.message}`)}}function Ee(e){let t=h.join(e,`opencode.json`);if(!v.existsSync(t)){f(`debug`,`[OpenCode] No opencode.json found to clean up`);return}try{let e=v.readFileSync(t,`utf8`),n=JSON.parse(e);n.mcp&&n.mcp[`taskmaster-ai`]?(delete n.mcp[`taskmaster-ai`],Object.keys(n.mcp).length===0&&delete n.mcp,Object.keys(n).filter(e=>e!==`$schema`).length===0?(v.rmSync(t,{force:!0}),f(`info`,`[OpenCode] Removed empty opencode.json file`)):(v.writeFileSync(t,JSON.stringify(n,null,2)+`
`),f(`info`,`[OpenCode] Removed TaskMaster from opencode.json, preserved other configurations`))):f(`debug`,`[OpenCode] TaskMaster not found in opencode.json`)}catch(e){f(`error`,`[OpenCode] Failed to clean up opencode.json: ${e.message}`)}}const De=j({name:`opencode`,displayName:`OpenCode`,url:`opencode.ai`,docsUrl:`opencode.ai/docs/`,profileDir:`.`,rulesDir:`.`,mcpConfigName:`opencode.json`,includeDefaultRules:!1,fileMap:{"AGENTS.md":`AGENTS.md`},onPostConvert:Te,onRemove:Ee});function L(e,t){let n=h.join(t,`roocode`);if(!v.existsSync(n)){f(`error`,`[Roo] Source directory does not exist: ${n}`);return}R(n,e),f(`debug`,`[Roo] Copied roocode directory to ${e}`);let r=h.join(n,`.roo`),i=h.join(n,`.roomodes`),a=h.join(e,`.roomodes`);if(v.existsSync(i))try{v.copyFileSync(i,a),f(`debug`,`[Roo] Copied .roomodes to ${a}`)}catch(e){f(`error`,`[Roo] Failed to copy .roomodes: ${e.message}`)}for(let t of ie){let n=h.join(r,`rules-${t}`,`${t}-rules`),i=h.join(e,`.roo`,`rules-${t}`,`${t}-rules`);if(v.existsSync(n))try{let e=h.dirname(i);v.existsSync(e)||v.mkdirSync(e,{recursive:!0}),v.copyFileSync(n,i),f(`debug`,`[Roo] Copied ${t}-rules to ${i}`)}catch(e){f(`error`,`[Roo] Failed to copy ${n} to ${i}: ${e.message}`)}}}function R(e,t){let n=v.existsSync(e),r=n&&v.statSync(e);n&&r.isDirectory()?(v.existsSync(t)||v.mkdirSync(t,{recursive:!0}),v.readdirSync(e).forEach(n=>{R(h.join(e,n),h.join(t,n))})):v.copyFileSync(e,t)}function Oe(e){let t=h.join(e,`.roomodes`);if(v.existsSync(t))try{v.rmSync(t,{force:!0}),f(`debug`,`[Roo] Removed .roomodes from ${t}`)}catch(e){f(`error`,`[Roo] Failed to remove .roomodes: ${e.message}`)}let n=h.join(e,`.roo`);if(v.existsSync(n)&&(v.readdirSync(n).forEach(e=>{if(e.startsWith(`rules-`)){let t=h.join(n,e);try{v.rmSync(t,{recursive:!0,force:!0}),f(`debug`,`[Roo] Removed ${e} directory from ${t}`)}catch(e){f(`error`,`[Roo] Failed to remove ${t}: ${e.message}`)}}}),v.readdirSync(n).length===0))try{v.rmSync(n,{recursive:!0,force:!0}),f(`debug`,`[Roo] Removed empty .roo directory from ${n}`)}catch(e){f(`error`,`[Roo] Failed to remove .roo directory: ${e.message}`)}}function ke(e,t){L(e,t)}const Ae=j({name:`roo`,displayName:`Roo Code`,url:`roocode.com`,docsUrl:`docs.roocode.com`,toolMappings:ae.ROO_STYLE,onAdd:L,onRemove:Oe,onPostConvert:ke}),je=j({name:`trae`,displayName:`Trae`,url:`trae.ai`,docsUrl:`docs.trae.ai`,mcpConfig:!1});function Me(e){let t={};if(e.mcpServers){t.servers={};for(let[n,r]of Object.entries(e.mcpServers)){let e={...r};if(e.env){let r={};e.command&&(r.command=e.command),e.args&&(r.args=e.args),e.env&&(r.env=e.env),r.type=`stdio`,Object.keys(e).forEach(t=>{[`command`,`args`,`env`,`type`].includes(t)||(r[t]=e[t])}),t.servers[n]=r}else e.type=`stdio`,t.servers[n]=e}}return t}function Ne(e,t){let n=h.join(e,`.vscode`,`mcp.json`);if(!v.existsSync(n)){f(`debug`,`[VS Code] No .vscode/mcp.json found to transform`);return}try{let e=v.readFileSync(n,`utf8`),t=JSON.parse(e);if(t.servers){f(`info`,`[VS Code] mcp.json already in VS Code format, skipping transformation`);return}let r=Me(t);v.writeFileSync(n,JSON.stringify(r,null,2)+`
`),f(`info`,`[VS Code] Transformed mcp.json to VS Code format`),f(`debug`,`[VS Code] Renamed mcpServers->servers, added type: "stdio"`)}catch(e){f(`error`,`[VS Code] Failed to transform mcp.json: ${e.message}`)}}function Pe(e){let t=h.join(e,`.vscode`,`mcp.json`);if(!v.existsSync(t)){f(`debug`,`[VS Code] No .vscode/mcp.json found to clean up`);return}try{let e=v.readFileSync(t,`utf8`),n=JSON.parse(e);if(n.servers&&n.servers[`task-master-ai`])if(delete n.servers[`task-master-ai`],Object.keys(n.servers).length===0){v.rmSync(t,{force:!0}),f(`info`,`[VS Code] Removed empty mcp.json file`);let e=h.dirname(t);try{v.readdirSync(e).length===0&&(v.rmSync(e,{recursive:!0,force:!0}),f(`debug`,`[VS Code] Removed empty .vscode directory`))}catch(e){}}else v.writeFileSync(t,JSON.stringify(n,null,2)+`
`),f(`info`,`[VS Code] Removed TaskMaster from mcp.json, preserved other configurations`);else f(`debug`,`[VS Code] TaskMaster not found in mcp.json`)}catch(e){f(`error`,`[VS Code] Failed to clean up mcp.json: ${e.message}`)}}const Fe=j({name:`vscode`,displayName:`VS Code`,url:`code.visualstudio.com`,docsUrl:`code.visualstudio.com/docs`,rulesDir:`.github/instructions`,profileDir:`.vscode`,mcpConfigName:`mcp.json`,targetExtension:`.instructions.md`,customReplacements:[{from:/\.cursor\/rules/g,to:`.github/instructions`},{from:/\.cursor\/mcp\.json/g,to:`.vscode/mcp.json`},{from:/\.vscode\/rules/g,to:`.github/instructions`},{from:/^globs:\s*(.+)$/gm,to:`applyTo: "$1"`},{from:/^alwaysApply:\s*(true|false)\s*\n?/gm,to:``},{from:/\[(.+?)\]\(mdc:\.cursor\/rules\/(.+?)\.mdc\)/g,to:`[$1](.github/instructions/$2.instructions.md)`},{from:/rules directory/g,to:`instructions directory`},{from:/cursor rules/gi,to:`VS Code instructions`}],onPostConvert:Ne,onRemove:Pe}),Ie=j({name:`windsurf`,displayName:`Windsurf`,url:`windsurf.com`,docsUrl:`docs.windsurf.com`});function Le(e){let t={};e.mcpServers&&(t.context_servers=e.mcpServers);for(let[n,r]of Object.entries(e))n!==`mcpServers`&&(t[n]=r);return t}function Re(e,t){}function ze(e){let t=h.join(e,`.rules`);try{v.existsSync(t)&&(v.rmSync(t,{force:!0}),f(`debug`,`[Zed] Removed ${t}`))}catch(e){f(`error`,`[Zed] Failed to remove Zed instructions: ${e.message}`)}let n=h.join(e,`.zed`,`settings.json`);if(!v.existsSync(n)){f(`debug`,`[Zed] No .zed/settings.json found to clean up`);return}try{let t=v.readFileSync(n,`utf8`),r=JSON.parse(t);if(r.context_servers&&r.context_servers[`task-master-ai`])if(delete r.context_servers[`task-master-ai`],Object.keys(r.context_servers).length===0&&(delete r.context_servers,f(`debug`,`[Zed] Removed empty context_servers section`)),Object.keys(r).length===0){v.rmSync(n,{force:!0}),f(`info`,`[Zed] Removed empty settings.json file`);let t=h.join(e,`.zed`);v.existsSync(t)&&v.readdirSync(t).length===0&&(v.rmSync(t,{recursive:!0,force:!0}),f(`debug`,`[Zed] Removed empty .zed directory`))}else v.writeFileSync(n,JSON.stringify(r,null,` `)+`
`),f(`info`,`[Zed] Removed TaskMaster from settings.json, preserved other configurations`);else f(`debug`,`[Zed] TaskMaster not found in context_servers`)}catch(e){f(`error`,`[Zed] Failed to clean up settings.json: ${e.message}`)}}function Be(e,t){let n=h.join(e,`.zed`,`settings.json`);if(!v.existsSync(n)){f(`debug`,`[Zed] No .zed/settings.json found to transform`);return}try{let e=v.readFileSync(n,`utf8`),t=JSON.parse(e);if(t.context_servers){f(`info`,`[Zed] settings.json already in Zed format, skipping transformation`);return}let r=Le(t);r.context_servers&&r.context_servers[`task-master-ai`]&&(r.context_servers[`task-master-ai`].source=`custom`),v.writeFileSync(n,JSON.stringify(r,null,` `)+`
`),f(`info`,`[Zed] Transformed settings.json to Zed format`),f(`debug`,`[Zed] Renamed mcpServers to context_servers`)}catch(e){f(`error`,`[Zed] Failed to transform settings.json: ${e.message}`)}}const Ve=j({name:`zed`,displayName:`Zed`,url:`zed.dev`,docsUrl:`zed.dev/docs`,profileDir:`.zed`,rulesDir:`.`,mcpConfig:!0,mcpConfigName:`settings.json`,includeDefaultRules:!1,fileMap:{"AGENTS.md":`.rules`},onAdd:Re,onRemove:ze,onPostConvert:Be});var He=e({ampProfile:()=>ue,claudeProfile:()=>he,clineProfile:()=>ge,codexProfile:()=>_e,cursorProfile:()=>ve,geminiProfile:()=>ye,kiloProfile:()=>Se,kiroProfile:()=>Ce,opencodeProfile:()=>De,rooProfile:()=>Ae,traeProfile:()=>je,vscodeProfile:()=>Fe,windsurfProfile:()=>Ie,zedProfile:()=>Ve});function z(e){return A.includes(e)}function B(e){if(!z(e))return null;let t=`${e}Profile`,n=He[t];if(!n)throw Error(`Profile not found: static import missing for '${e}'. Valid profiles: ${A.join(`, `)}`);return n}function Ue(e,t){let n=e;return t.profileTerms.forEach(e=>{n=(e.to,n.replace(e.from,e.to))}),t.fileExtensions.forEach(e=>{n=n.replace(e.from,e.to)}),n}function We(e,t){let n=e,r=t.toolNames,i=RegExp(`\\b(${Object.keys(r).join(`|`)})\\b`,`g`);return n=n.replace(i,(e,t)=>r[t]||t),t.toolContexts.forEach(e=>{n=n.replace(e.from,e.to)}),t.toolGroups.forEach(e=>{n=n.replace(e.from,e.to)}),n}function Ge(e,t){let n=e;return t.docUrls.forEach(e=>{n=(e.to,n.replace(e.from,e.to))}),n}function Ke(e,t){let{pathPattern:n,replacement:r}=t.fileReferences;return e.replace(n,r)}function qe(e,t,n){let r=e;return r=Ke(r,t),r=Ue(r,t),r=We(r,t),r=Ge(r,t),n.forEach(e=>{r=(e.to,r.replace(e.from,e.to))}),r}function V(e,t){let n=h.join(e,t.rulesDir),r=0,i=0;if(typeof t.onAddRulesProfile==`function`)try{let n=D();t.onAddRulesProfile(e,n),f(`debug`,`[Rule Transformer] Called onAddRulesProfile for ${t.profileName}`)}catch(e){f(`error`,`[Rule Transformer] onAddRulesProfile failed for ${t.profileName}: ${e.message}`),i++}let a=Object.keys(t.fileMap);if(a.length>0){v.existsSync(n)||v.mkdirSync(n,{recursive:!0});for(let e of a){let a=!e.startsWith(`rules/`);try{if(!te(e)){f(`warn`,`[Rule Transformer] Source file not found: ${e}, skipping`);continue}let i=t.fileMap[e],o=h.join(n,i),s=h.dirname(o);v.existsSync(s)||v.mkdirSync(s,{recursive:!0});let c=O(e,`utf8`);a||(c=qe(c,t.conversionConfig,t.globalReplacements)),v.writeFileSync(o,c,`utf8`),r++,f(`debug`,`[Rule Transformer] ${a?`Copied`:`Converted`} ${e} -> ${i} for ${t.profileName}`)}catch(n){i++,f(`error`,`[Rule Transformer] Failed to ${a?`copy`:`convert`} ${e} for ${t.profileName}: ${n.message}`)}}}if(t.mcpConfig!==!1)try{ne(e,t.mcpConfigPath),f(`debug`,`[Rule Transformer] Setup MCP configuration for ${t.profileName}`)}catch(e){f(`error`,`[Rule Transformer] MCP setup failed for ${t.profileName}: ${e.message}`)}if(typeof t.onPostConvertRulesProfile==`function`)try{let n=D();t.onPostConvertRulesProfile(e,n),f(`debug`,`[Rule Transformer] Called onPostConvertRulesProfile for ${t.profileName}`)}catch(e){f(`error`,`[Rule Transformer] onPostConvertRulesProfile failed for ${t.profileName}: ${e.message}`)}return{success:Math.max(r,1),failed:i}}function Je(e,t){let n=h.join(e,t.rulesDir),r=h.join(e,t.profileDir),i={profileName:t.profileName,success:!1,skipped:!1,error:null,filesRemoved:[],mcpResult:null,profileDirRemoved:!1,notice:null};try{if(typeof t.onRemoveRulesProfile==`function`)try{t.onRemoveRulesProfile(e),f(`debug`,`[Rule Transformer] Called onRemoveRulesProfile for ${t.profileName}`)}catch(e){f(`error`,`[Rule Transformer] onRemoveRulesProfile failed for ${t.profileName}: ${e.message}`)}let a=Object.keys(t.fileMap);if(a.length>0){if(!v.existsSync(r))return i.success=!0,i.skipped=!0,f(`debug`,`[Rule Transformer] Profile directory does not exist: ${r}`),i;let o=!1;if(v.existsSync(n)){let r=a.map(e=>t.fileMap[e]),s=[];if(n===e||t.rulesDir===`.`){let e=v.readdirSync(n);for(let t of e){if(t===`node_modules`||t===`.git`||t===`dist`)continue;let e=h.join(n,t);try{let n=v.lstatSync(e);n.isFile()?s.push(t):n.isDirectory()&&!n.isSymbolicLink()&&v.readdirSync(e,{recursive:!0}).forEach(e=>{s.push(h.join(t,e.toString()))})}catch(e){}}}else s=v.readdirSync(n,{recursive:!0});let c=s.filter(e=>{let t=h.join(n,e);try{return v.statSync(t).isFile()}catch(e){return!1}}).map(e=>e.toString());for(let e of r){let t=h.join(n,e);if(v.existsSync(t))try{v.rmSync(t,{force:!0}),i.filesRemoved.push(e),f(`debug`,`[Rule Transformer] Removed Task Master file: ${e}`)}catch(t){f(`error`,`[Rule Transformer] Failed to remove ${e}: ${t.message}`)}}let l=c.filter(e=>!r.includes(e));o=l.length>0,l.length===0?(v.rmSync(n,{recursive:!0,force:!0}),f(`debug`,`[Rule Transformer] Removed empty rules directory: ${n}`)):o&&(i.notice=`Preserved ${l.length} existing rule files in ${t.rulesDir}`,f(`info`,`[Rule Transformer] ${i.notice}`))}}if(t.mcpConfig!==!1)try{i.mcpResult=re(e,t.mcpConfigPath),i.mcpResult.hasOtherServers&&(i.notice?i.notice+=`; preserved other MCP server configurations`:i.notice=`Preserved other MCP server configurations`),f(`debug`,`[Rule Transformer] Processed MCP configuration for ${t.profileName}`)}catch(e){f(`error`,`[Rule Transformer] MCP cleanup failed for ${t.profileName}: ${e.message}`)}if(v.existsSync(r)){let e=v.readdirSync(r);if(e.length===0&&t.profileDir!==`.`)try{v.rmSync(r,{recursive:!0,force:!0}),i.profileDirRemoved=!0,f(`debug`,`[Rule Transformer] Removed empty profile directory: ${r}`)}catch(e){f(`error`,`[Rule Transformer] Failed to remove profile directory ${r}: ${e.message}`)}else if(e.length>0){let n=`Preserved ${e.length} existing files/folders in ${t.profileDir}`;i.notice?i.notice+=`; ${n.toLowerCase()}`:i.notice=n,f(`info`,`[Rule Transformer] ${n}`)}}i.success=!0,f(`debug`,`[Rule Transformer] Successfully removed ${t.profileName} Task Master files from ${e}`)}catch(e){i.error=e.message,f(`error`,`[Rule Transformer] Failed to remove ${t.profileName} rules: ${e.message}`)}return i}function Ye(e){try{return B(e).displayName||e}catch(t){return e}}function H(e){let t=[];for(let n of A)try{let r=B(n),i=h.join(e,r.profileDir);if(r.profileDir===`.`||v.existsSync(i)){let i=h.join(e,r.rulesDir);v.existsSync(i)&&Object.values(r.fileMap).some(e=>v.existsSync(h.join(i,e)))&&t.push(n)}}catch(e){}return t}function Xe(e,t){let n=H(e);return n.length===0?!1:n.filter(e=>!t.includes(e)).length===0}async function Ze(){let e=A.map(e=>{let t=Ye(e),n=B(e),r,i=Object.keys(n.fileMap).length>0,a=n.mcpConfig===!0;return n.includeDefaultRules?i&&a?r=e===`roo`?`Rule profile, MCP config, and agent modes`:`Rule profile and MCP config`:i&&(r=`Rule profile`):r=e===`claude`?`Integration guide with Task Master slash commands`:e===`codex`?`Comprehensive Task Master integration guide`:a?`Integration guide and MCP config`:`Integration guide`,{profileName:e,displayName:t,description:r}}).sort((e,t)=>e.displayName.localeCompare(t.displayName)),t=e.map(({displayName:e,description:t})=>`${g.white(`âĸ `)}${g.yellow(e)}${g.white(` - ${t}`)}`).join(`
`);console.log(_(`${g.white.bold(`Rule Profiles Setup`)}\n\n${g.white(`Rule profiles help enforce best practices and conventions for Task Master.
Each profile provides coding guidelines tailored for specific AI coding environments.
`)}${g.cyan(`Available Profiles:`)}\n${t}`,{padding:1,borderColor:`blue`,borderStyle:`round`,margin:{top:1,bottom:1}}));let n=e.map(({profileName:e,displayName:t})=>({name:t,value:e})),r={type:`checkbox`,name:`ruleProfiles`,message:`Which rule profiles would you like to add to your project?`,choices:n,pageSize:n.length,loop:!1,validate:e=>e.length>0||`You must select at least one.`},{ruleProfiles:i}=await y.prompt([r]);return i}function Qe(e,t){return B(e).includeDefaultRules?`Summary for ${e}: ${t.success} files processed, ${t.failed} failed.`:`Summary for ${e}: Integration guide installed.`}function $e(e,t){if(t.skipped)return`Summary for ${e}: Skipped (default or protected files)`;if(t.error&&!t.success)return`Summary for ${e}: Failed to remove - ${t.error}`;if(B(e).includeDefaultRules){let n=`Summary for ${e}: Rule profile removed`;return t.notice?`${n} (${t.notice})`:n}else{let n=`Summary for ${e}: Integration guide removed`;return t.notice?`${n} (${t.notice})`:n}}function et(e){let t=[],n=0,r=0;return e.forEach(e=>{n+=e.success,r+=e.failed,(e.success>0||e.failed===0)&&t.push(e.profileName)}),{successfulProfiles:t,allSuccessfulProfiles:t,totalSuccess:n,totalFailed:r}}function tt(e){let t=[],n=[],r=[],i=[];return e.forEach(e=>{e.success?t.push(e.profileName):e.skipped?n.push(e.profileName):e.error&&r.push(e),e.notice&&i.push(e)}),{successfulRemovals:t,skippedRemovals:n,failedRemovals:r,removalsWithNotices:i}}const U=`# Task files`,W=`tasks.json`,G=`tasks/`;function nt(e){return e.trim().replace(/^#/,``).trim()}function K(e){let t=nt(e);return t===W||t===G}function rt(e,t){return e.map(e=>{if(K(e)){let n=nt(e),r=e.match(/\s*$/)[0];return t?`# ${n}${r}`:`${n}${r}`}return e})}function it(e){let t=[],n=!1;for(let r of e){if(r.trim()===U){n=!0;continue}if(K(r)||n&&!r.trim())continue;n&&r.trim()&&!K(r)&&(n=!1),n||t.push(r)}return t}function at(e,t){return e.filter(e=>{let n=e.trim();return!n||K(e)||n===U?!1:!t.has(n)})}function ot(e){let t=[U];return e?t.push(`# ${W}`,`# ${G} `):t.push(W,`${G} `),t}function st(e){if(e.some(e=>e.trim())){let t=e[e.length-1];t&&t.trim()&&e.push(``)}}function ct(e,t,n){if(!e||typeof e!=`string`)throw Error(`targetPath must be a non-empty string`);if(!e.endsWith(`.gitignore`))throw Error(`targetPath must end with .gitignore`);if(!t||typeof t!=`string`)throw Error(`content must be a non-empty string`);if(typeof n!=`boolean`)throw Error(`storeTasksInGit must be a boolean`)}function lt(e,t,n){try{v.writeFileSync(e,t.join(`
`)+`
`),typeof n==`function`&&n(`success`,`Created ${e} with full template`)}catch(t){throw typeof n==`function`&&n(`error`,`Failed to create ${e}: ${t.message}`),t}}function ut(e,t,n,r){try{let i=v.readFileSync(e,`utf8`).split(`
`),a=it(i),o=new Set(a.map(e=>e.trim()).filter(e=>e)),s=at(t,o),c=[...a];if(s.length>0&&(st(c),c.push(...s)),st(c),c.push(...ot(n)),v.writeFileSync(e,c.join(`
`)+`
`),typeof r==`function`){let t=s.length>0?` and merged new content`:``;r(`success`,`Updated ${e} according to user preference${t}`)}}catch(t){throw typeof r==`function`&&r(`error`,`Failed to merge content with ${e}: ${t.message}`),t}}function dt(e,t,n=!0,r=null){ct(e,t,n);let i=t.split(`
`),a=rt(i,n);v.existsSync(e)?ut(e,a,n,r):lt(e,a,r)}function ft(e){try{let t=JSON.parse(v.readFileSync(e,`utf-8`));for(let e of[`main`,`research`,`fallback`])if(t.models&&t.models[e]){let n=t.models[e].provider,r=t.models[e].modelId;if(p[n]){let i=p[n].find(e=>e.id===r);i&&i.max_tokens&&(t.models[e].maxTokens=i.max_tokens)}}return v.writeFileSync(e,JSON.stringify(t,null,2)),!0}catch(e){return console.error(`Error updating config maxTokens:`,e.message),!1}}const q={debug:0,info:1,warn:2,error:3,success:4},pt=process.env.TASKMASTER_LOG_LEVEL?q[process.env.TASKMASTER_LOG_LEVEL.toLowerCase()]:q.info,mt=C([`#00b4d8`,`#0077b6`,`#03045e`]),ht=C([`#fb8b24`,`#e36414`,`#9a031e`]);function gt(){if(d())return;console.clear();let e=S.textSync(`Task Master AI`,{font:`Standard`,horizontalLayout:`default`,verticalLayout:`default`});console.log(mt(e)),console.log(g.dim(`by `)+g.cyan.underline(`https://x.com/eyaltoledano`)),console.log(_(g.white(`${g.bold(`Initializing`)} your new project`),{padding:1,margin:{top:0,bottom:1},borderStyle:`round`,borderColor:`cyan`}))}function J(e,...t){let n={debug:g.gray(`đ`),info:g.blue(`âšī¸`),warn:g.yellow(`â ī¸`),error:g.red(`â`),success:g.green(`â
`)};if(q[e]>=pt){let r=n[e]||``;d()||(e===`error`?console.error(r,g.red(...t)):e===`warn`?console.warn(r,g.yellow(...t)):e===`success`?console.log(r,g.green(...t)):e===`info`?console.log(r,g.blue(...t)):console.log(r,...t))}if(process.env.DEBUG===`true`){let n=`[${e.toUpperCase()}] ${t.join(` `)}\n`;v.appendFileSync(`init-debug.log`,n)}}function Y(e){v.existsSync(e)||(v.mkdirSync(e,{recursive:!0}),J(`info`,`Created directory: ${e}`))}function _t(){let e=process.env.HOME||process.env.USERPROFILE,t;if(process.env.SHELL?.includes(`zsh`))t=h.join(e,`.zshrc`);else if(process.env.SHELL?.includes(`bash`))t=h.join(e,`.bashrc`);else return J(`warn`,`Could not determine shell type. Aliases not added.`),!1;try{if(!v.existsSync(t))return J(`warn`,`Shell config file ${t} not found. Aliases not added.`),!1;if(v.readFileSync(t,`utf8`).includes(`alias tm='task-master'`))return J(`info`,`Task Master aliases already exist in shell config.`),!0;let e=`
# Task Master aliases added on ${new Date().toLocaleDateString()}
alias tm='task-master'
alias taskmaster='task-master'
`;return v.appendFileSync(t,e),J(`success`,`Added Task Master aliases to ${t}`),J(`info`,`To use the aliases in your current terminal, run: source ${t}`),!0}catch(e){return J(`error`,`Failed to add aliases: ${e.message}`),!1}}function vt(e){let t=h.join(e,c);if(v.existsSync(t)){J(`info`,`State file already exists, preserving current configuration`);return}let n={currentTag:`master`,lastSwitched:new Date().toISOString(),branchTagMapping:{},migrationNoticeShown:!1};try{v.writeFileSync(t,JSON.stringify(n,null,2)),J(`success`,`Created initial state file: ${t}`),J(`info`,`Default tag set to "master" for task organization`)}catch(e){J(`error`,`Failed to create state file: ${e.message}`)}}function X(e,t,n={}){if(!te(e)){J(`error`,`Source file not found: ${e}`);return}let r=O(e,`utf8`);if(Object.entries(n).forEach(([e,t])=>{let n=RegExp(`\\{\\{${e}\\}\\}`,`g`);r=r.replace(n,t)}),v.existsSync(t)){let e=h.basename(t);if(e===`.gitignore`){J(`info`,`${t} already exists, merging content...`);let e=v.readFileSync(t,`utf8`),n=new Set(e.split(`
`).map(e=>e.trim())),i=r.split(`
`).filter(e=>!n.has(e.trim()));if(i.length>0){let n=`${e.trim()}\n\n# Added by Task Master AI\n${i.join(`
`)}`;v.writeFileSync(t,n),J(`success`,`Updated ${t} with additional entries`)}else J(`info`,`No new content to add to ${t}`);return}if(e===`README-task-master.md`){J(`info`,`${t} already exists`);let e=h.join(h.dirname(t),`README-task-master.md`);v.writeFileSync(e,r),J(`success`,`Created ${e} (preserved original README-task-master.md)`);return}J(`warn`,`${t} already exists, skipping.`);return}v.writeFileSync(t,r),J(`info`,`Created file: ${t}`)}async function yt(e={}){d()||gt(),e.aliases===!0?e.addAliases=!0:e.aliases===!1&&(e.addAliases=!1),e.git===!0?e.initGit=!0:e.git===!1&&(e.initGit=!1),e.gitTasks===!0?e.storeTasksInGit=!0:e.gitTasks===!1&&(e.storeTasksInGit=!1);let t=e.yes||e.name&&e.description,n;if(e.rulesExplicitlyProvided?(J(`info`,`Using rule profiles provided via command line: ${e.rules.join(`, `)}`),n=e.rules):t?(J(`info`,`No rules specified in non-interactive mode, defaulting to all profiles.`),n=A):(J(`info`,`No rules specified; interactive setup will be launched to select profiles.`),n=[]),t){d()||console.log(`SKIPPING PROMPTS - Using defaults or provided values`),e.name,e.description,e.version,e.author;let t=e.dryRun||!1,r=e.addAliases===void 0?!0:e.addAliases,i=e.initGit===void 0?!0:e.initGit,a=e.storeTasksInGit===void 0?!0:e.storeTasksInGit;if(t)return J(`info`,`DRY RUN MODE: No files will be modified`),J(`info`,`Would initialize Task Master project`),J(`info`,`Would create/update necessary project files`),J(`info`,`${r?`Would add shell aliases (tm, taskmaster)`:`Would skip shell aliases`}`),J(`info`,`${i?`Would initialize Git repository`:`Would skip Git initialization`}`),J(`info`,`${a?`Would store tasks in Git`:`Would exclude tasks from Git`}`),{dryRun:!0};Q(r,i,a,t,e,n)}else{J(`info`,`Required options not provided, proceeding with prompts.`);try{let t=w.createInterface({input:process.stdin,output:process.stdout}),r=!0;r=e.addAliases===void 0?(await Z(t,g.cyan(`Add shell aliases for task-master? This lets you type "tm" instead of "task-master" (Y/n): `))).trim().toLowerCase()!==`n`:e.addAliases;let i=!0;i=e.initGit===void 0?(await Z(t,g.cyan(`Initialize a Git repository in project root? (Y/n): `))).trim().toLowerCase()!==`n`:e.initGit;let a=!0;if(a=e.storeTasksInGit===void 0?(await Z(t,g.cyan(`Store tasks in Git (tasks.json and tasks/ directory)? (Y/n): `))).trim().toLowerCase()!==`n`:e.storeTasksInGit,console.log(`
Task Master Project settings:`),console.log(g.blue(`Add shell aliases (so you can use "tm" instead of "task-master"):`),g.white(r?`Yes`:`No`)),console.log(g.blue(`Initialize Git repository in project root:`),g.white(i?`Yes`:`No`)),console.log(g.blue(`Store tasks in Git (tasks.json and tasks/ directory):`),g.white(a?`Yes`:`No`)),(await Z(t,g.yellow(`
Do you want to continue with these settings? (Y/n): `))).trim().toLowerCase()===`n`){t.close(),J(`info`,`Project initialization cancelled by user`),process.exit(0);return}e.rulesExplicitlyProvided&&J(`info`,`Using rule profiles provided via command line: ${n.join(`, `)}`);let o=e.dryRun||!1;if(o)return J(`info`,`DRY RUN MODE: No files will be modified`),J(`info`,`Would initialize Task Master project`),J(`info`,`Would create/update necessary project files`),J(`info`,`${r?`Would add shell aliases (tm, taskmaster)`:`Would skip shell aliases`}`),J(`info`,`${i?`Would initialize Git repository`:`Would skip Git initialization`}`),J(`info`,`${a?`Would store tasks in Git`:`Would exclude tasks from Git`}`),{dryRun:!0};Q(r,i,a,o,e,n),t.close()}catch(e){rl&&rl.close(),J(`error`,`Error during initialization process: ${e.message}`),process.exit(1)}}}function Z(e,t){return new Promise(n=>{e.question(t,e=>{n(e)})})}function Q(e,c,f,p,v,y=A){let b=process.cwd();J(`info`,`Initializing project in ${b}`),Y(h.join(b,a)),Y(h.join(b,l)),Y(h.join(b,o)),Y(h.join(b,s)),Y(h.join(b,u)),vt(b);let C={year:new Date().getFullYear()};function w(e){let t=B(e);t?V(b,t):J(`warn`,`Unknown rule profile: ${e}`)}X(`env.example`,h.join(b,t),C),X(`config.json`,h.join(b,i),{...C});let T=h.join(b,i);ft(T)?J(`info`,`Updated config with correct maxTokens values`):J(`warn`,`Could not update maxTokens in config`);try{let e=O(`gitignore`,`utf8`);dt(h.join(b,r),e,f,J)}catch(e){J(`error`,`Failed to create .gitignore: ${e.message}`)}X(`example_prd.txt`,h.join(b,n));try{c===!1?J(`info`,`Git initialization skipped due to --no-git flag.`):c===!0?m()?J(`info`,`Existing Git repository detected â skipping git init despite --git flag.`):(J(`info`,`Initializing Git repository due to --git flag...`),x(`git init`,{cwd:b,stdio:`ignore`}),J(`success`,`Git repository initialized`)):m()?J(`info`,`Existing Git repository detected â skipping git init.`):(J(`info`,`No Git repository detected. Initializing one in project root...`),x(`git init`,{cwd:b,stdio:`ignore`}),J(`success`,`Git repository initialized`))}catch(e){J(`warn`,`Git not available, skipping repository initialization`)}if(v.rulesExplicitlyProvided||v.yes){J(`info`,`Generating profile rules from command-line flags...`);for(let e of y)w(e)}e&&_t();let E={cwd:b,stdio:`inherit`};if(d()?(E.stdio=`ignore`,J(`info`,`Running npm install silently...`)):console.log(_(g.cyan(`Installing dependencies...`),{padding:.5,margin:.5,borderStyle:`round`,borderColor:`blue`})),!d()&&!p&&!v?.yes&&!v.rulesExplicitlyProvided){console.log(_(g.cyan(`Configuring Rule Profiles...`),{padding:.5,margin:{top:1,bottom:.5},borderStyle:`round`,borderColor:`blue`})),J(`info`,`Running interactive rules setup. Please select which rule profiles to include.`);try{x(`npx task-master rules --setup`,{stdio:`inherit`,cwd:b}),J(`success`,`Rule profiles configured.`)}catch(e){J(`error`,`Failed to configure rule profiles:`,e.message),J(`warn`,`You may need to run "task-master rules --setup" manually.`)}}else (d()||p||v?.yes)&&(v.rulesExplicitlyProvided?J(`info`,`Skipping interactive rules setup because --rules flag was used.`):J(`info`,`Skipping interactive rules setup in non-interactive mode.`));if(!d()&&!p&&!v?.yes){console.log(_(g.cyan(`Configuring Response Language...`),{padding:.5,margin:{top:1,bottom:.5},borderStyle:`round`,borderColor:`blue`})),J(`info`,`Running interactive response language setup. Please input your preferred language.`);try{x(`npx task-master lang --setup`,{stdio:`inherit`,cwd:b}),J(`success`,`Response Language configured.`)}catch(e){J(`error`,`Failed to configure response language:`,e.message),J(`warn`,`You may need to run "task-master lang --setup" manually.`)}}else d()&&!p?(J(`info`,`Skipping interactive response language setup in silent (MCP) mode.`),J(`warn`,`Please configure response language using "task-master models --set-response-language" or the "models" MCP tool.`)):p&&J(`info`,`DRY RUN: Skipping interactive response language setup.`);if(!d()&&!p&&!v?.yes){console.log(_(g.cyan(`Configuring AI Models...`),{padding:.5,margin:{top:1,bottom:.5},borderStyle:`round`,borderColor:`blue`})),J(`info`,`Running interactive model setup. Please select your preferred AI models.`);try{x(`npx task-master models --setup`,{stdio:`inherit`,cwd:b}),J(`success`,`AI Models configured.`)}catch(e){J(`error`,`Failed to configure AI models:`,e.message),J(`warn`,`You may need to run "task-master models --setup" manually.`)}}else d()&&!p?(J(`info`,`Skipping interactive model setup in silent (MCP) mode.`),J(`warn`,`Please configure AI models using "task-master models --set-..." or the "models" MCP tool.`)):p?J(`info`,`DRY RUN: Skipping interactive model setup.`):v?.yes&&(J(`info`,`Skipping interactive model setup due to --yes flag.`),J(`info`,`Default AI models will be used. You can configure different models later using "task-master models --setup" or "task-master models --set-..." commands.`));e&&!p?(J(`info`,`Adding shell aliases...`),_t()&&J(`success`,`Shell aliases