task-master-ai
Version:
A task management system for ambitious AI-driven development that doesn't overwhelm and confuse Cursor.
46 lines (44 loc) âĸ 54 kB
JavaScript
import{s as e}from"./ai-services-unified-reUH-Ugx.js";import{At as t,Bt as n,Ft as r,Ht as i,It as a,Lt as o,Rt as s,_ as c,bt as l,jt as u,kt as d,v as f,zt as p}from"./utils-FW_Ayk60.js";import{r as m}from"./git-utils-BFrSdLEz.js";import{Ct as h,et as g}from"./task-manager-DJeoFhWf.js";import _ from"chalk";import v from"fs";import y from"path";import{fileURLToPath as b}from"url";import{execSync as x}from"child_process";import S from"boxen";import C from"readline";import w from"figlet";import T from"inquirer";const E=`# Task files`,D=`tasks.json`,O=`tasks/`;function ee(e){return e.trim().replace(/^#/,``).trim()}function k(e){let t=ee(e);return t===D||t===O}function te(e,t){return e.map(e=>{if(k(e)){let n=ee(e),r=e.match(/\s*$/)[0];return t?`# ${n}${r}`:`${n}${r}`}return e})}function ne(e){let t=[],n=!1;for(let r of e){if(r.trim()===E){n=!0;continue}k(r)||n&&!r.trim()||(n&&r.trim()&&!k(r)&&(n=!1),n||t.push(r))}return t}function re(e,t){return e.filter(e=>{let n=e.trim();return!n||k(e)||n===E?!1:!t.has(n)})}function ie(e){let t=[E];return e?t.push(`# ${D}`,`# ${O} `):t.push(D,`${O} `),t}function ae(e){if(e.some(e=>e.trim())){let t=e[e.length-1];t&&t.trim()&&e.push(``)}}function oe(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 se(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 ce(e,t,n,r){try{let i=ne(v.readFileSync(e,`utf8`).split(`
`)),a=re(t,new Set(i.map(e=>e.trim()).filter(e=>e))),o=[...i];a.length>0&&(ae(o),o.push(...a)),ae(o),o.push(...ie(n)),v.writeFileSync(e,o.join(`
`)+`
`),typeof r==`function`&&r(`success`,`Updated ${e} according to user preference${a.length>0?` and merged new content`:``}`)}catch(t){throw typeof r==`function`&&r(`error`,`Failed to merge content with ${e}: ${t.message}`),t}}function le(e,t,n=!0,r=null){oe(e,t,n);let i=te(t.split(`
`),n);v.existsSync(e)?ce(e,i,n,r):se(e,i,r)}const A=[`amp`,`claude`,`cline`,`codex`,`cursor`,`gemini`,`kiro`,`opencode`,`kilo`,`roo`,`trae`,`vscode`,`windsurf`,`zed`],ue=[`architect`,`ask`,`orchestrator`,`code`,`debug`,`test`],de=b(import.meta.url),j=y.dirname(de);function M(){let e=[y.join(j,`assets`),y.join(j,`..`,`assets`),y.join(j,`..`,`..`,`public`,`assets`),y.join(process.cwd(),`assets`),y.join(process.cwd(),`node_modules`,`task-master-ai`,`dist`,`assets`),y.join(process.cwd(),`node_modules`,`task-master-ai`,`assets`)];for(let t of e)if(v.existsSync(t)){let e=y.join(t,`rules`,`taskmaster.mdc`);if(v.existsSync(e))return t}throw Error(`Assets directory not found. This is likely a packaging issue.`)}function N(e){let t=M();return y.join(t,e)}function P(e){try{let t=N(e);return v.existsSync(t)}catch{return!1}}function F(e,t=`utf8`){let n=N(e);return v.readFileSync(n,t)}function I(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 fe(e,t){if(!t){f(`debug`,`[MCP Config] No mcpConfigPath provided, skipping MCP configuration setup`);return}let n=y.join(e,t),r=y.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||={},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,I(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,I(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,I(e)+`
`),f(`success`,`Created MCP configuration file at ${n}`)}f(`info`,`MCP server will use the installed task-master-ai package`)}function pe(e,t){if(!t)return{success:!0,removed:!1,deleted:!1,error:null,hasOtherServers:!1};let n=y.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,I(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}function L(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:h=!0,onAdd:g,onRemove:_,onPostConvert:v}=e,b=c?y.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}`,"rules/hamster.mdc":`${x}hamster${u}`},C=h?{...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=y.basename(r,`.mdc`),a=C[`rules/${i}.mdc`]||`${i}${u}`,s=y.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:h,fileMap:C,globalReplacements:w,conversionConfig:E,getTargetRuleFilename:D,targetExtension:u,...g&&{onAddRulesProfile:g},..._&&{onRemoveRulesProfile:_},...v&&{onPostConvertRulesProfile:v}}}const R={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 me(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 z(e,t){let n=y.join(t,`AGENTS.md`),r=y.join(e,`AGENT.md`),i=y.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=y.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 he(e){let t=y.join(e,`AGENT.md`),n=y.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=y.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=y.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 ge(e,t){z(e,t);let n=y.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=me(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 _e=L({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:z,onRemove:he,onPostConvert:ge});function B(e,t){f(`info`,`[Claude] Commands and agents are now available via the Task Master plugin`),f(`info`,`[Claude] Install with: /plugin marketplace add taskmaster`),f(`info`,`[Claude] Then: /plugin install taskmaster@taskmaster`);let n=y.join(t,`AGENTS.md`),r=y.join(e,`CLAUDE.md`),i=y.join(e,`.taskmaster`,`CLAUDE.md`),a=`@./.taskmaster/CLAUDE.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 CLAUDE.md file.**\n${a}`;if(v.existsSync(n))try{let t=y.join(e,`.taskmaster`);if(v.existsSync(t)||v.mkdirSync(t,{recursive:!0}),v.copyFileSync(n,i),f(`debug`,`[Claude] Created Task Master instructions at ${i}`),v.existsSync(r)){let e=v.readFileSync(r,`utf8`);if(e.includes(a))f(`info`,`[Claude] Task Master import already present in ${r}`);else{let t=e.trim()+`
`+o+`
`;v.writeFileSync(r,t),f(`info`,`[Claude] Added Task Master import to existing ${r}`)}}else{let e=`# Claude Code Instructions\n${o}\n`;v.writeFileSync(r,e),f(`info`,`[Claude] Created ${r} with Task Master import`)}}catch(e){f(`error`,`[Claude] Failed to set up Claude instructions: ${e.message}`)}}function ve(e){f(`info`,`[Claude] To remove Task Master commands/agents, uninstall the plugin with: /plugin uninstall taskmaster`);let t=y.join(e,`CLAUDE.md`),n=y.join(e,`.taskmaster`,`CLAUDE.md`);try{if(v.existsSync(n)&&(v.rmSync(n,{force:!0}),f(`debug`,`[Claude] 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/CLAUDE.md`&&n.push(e[t])}let i=n.join(`
`).replace(/\n{3,}/g,`
`).trim();i===`# Claude Code Instructions`||i===``?(v.rmSync(t,{force:!0}),f(`debug`,`[Claude] Removed empty ${t}`)):(v.writeFileSync(t,i+`
`),f(`debug`,`[Claude] Removed Task Master import from ${t}`))}}catch(e){f(`error`,`[Claude] Failed to remove Claude instructions: ${e.message}`)}}function ye(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 be(e,t){B(e,t);let n=y.join(e,`.mcp.json`);if(v.existsSync(n))try{let e=ye(JSON.parse(v.readFileSync(n,`utf8`)));v.writeFileSync(n,JSON.stringify(e,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 xe=L({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:B,onRemove:ve,onPostConvert:be}),Se=L({name:`cline`,displayName:`Cline`,url:`cline.bot`,docsUrl:`docs.cline.bot`,profileDir:`.clinerules`,rulesDir:`.clinerules`,mcpConfig:!1}),Ce=L({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`}});function V(e,t){if(v.cpSync)try{v.cpSync(e,t,{recursive:!0,force:!0});return}catch(n){throw Error(`Failed to copy ${e} to ${t}: ${n.message}`)}let n=v.existsSync(e),r=null,i=!1;if(n)try{r=v.statSync(e),i=r.isDirectory()}catch{i=!1}if(i)try{v.existsSync(t)||v.mkdirSync(t,{recursive:!0});for(let n of v.readdirSync(e))V(y.join(e,n),y.join(t,n))}catch(n){throw Error(`Failed to copy directory ${e} to ${t}: ${n.message}`)}else try{v.mkdirSync(y.dirname(t),{recursive:!0}),v.copyFileSync(e,t)}catch(n){throw Error(`Failed to copy file ${e} to ${t}: ${n.message}`)}}function we(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 H(e){let t=y.basename(e);return t===`rules`&&y.basename(y.dirname(e))===`.cursor`?y.dirname(e):t===`.cursor`?e:y.join(e,`.cursor`)}function Te(e,t){let n=y.join(t,`claude`,`commands`),r=H(e),i=y.join(r,`commands`);if(!v.existsSync(n)){f(`warn`,`[Cursor] Source commands directory does not exist: ${n}`);return}try{try{v.rmSync(i,{recursive:!0,force:!0}),f(`debug`,`[Cursor] Removed existing commands directory: ${i}`)}catch(e){f(`debug`,`[Cursor] Commands directory did not exist or could not be removed: ${e.message}`)}V(n,i),f(`debug`,`[Cursor] Copied commands directory to ${i}`)}catch(e){f(`error`,`[Cursor] An error occurred during commands copy: ${e.message}`)}}function Ee(e){let t=H(e),n=y.join(t,`commands`);we(n)&&f(`debug`,`[Cursor] Ensured commands directory removed at ${n}`)}const De=L({name:`cursor`,displayName:`Cursor`,url:`cursor.so`,docsUrl:`docs.cursor.com`,targetExtension:`.mdc`,supportsRulesSubdirectories:!0,onAdd:Te,onRemove:Ee}),Oe=L({name:`gemini`,displayName:`Gemini`,url:`codeassist.google`,docsUrl:`github.com/google-gemini/gemini-cli`,profileDir:`.gemini`,rulesDir:`.`,mcpConfigName:`settings.json`,includeDefaultRules:!1,fileMap:{"AGENT.md":`AGENTS.md`,"GEMINI.md":`GEMINI.md`}});function U(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 W(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=>{W(y.join(e,n),y.join(t,n))})):v.copyFileSync(e,t)}function G(e,t){let n=y.join(t,`roocode`);if(!v.existsSync(n)){f(`error`,`[Kilo] Source directory does not exist: ${n}`);return}W(n,e),f(`debug`,`[Kilo] Copied roocode directory to ${e}`);let r=y.join(n,`.roomodes`),i=y.join(e,`.kilocodemodes`);if(v.existsSync(r))try{let t=U(v.readFileSync(r,`utf8`));v.writeFileSync(i,t),f(`debug`,`[Kilo] Created .kilocodemodes at ${i}`),v.unlinkSync(y.join(e,`.roomodes`))}catch(e){f(`error`,`[Kilo] Failed to transform .roomodes: ${e.message}`)}let a=y.join(n,`.roo`),o=y.join(e,`.kilo`);v.existsSync(y.join(e,`.roo`))&&v.rmSync(y.join(e,`.roo`),{recursive:!0,force:!0});for(let e of ue){let t=y.join(a,`rules-${e}`,`${e}-rules`),n=y.join(o,`rules-${e}`,`${e}-rules`);if(v.existsSync(t))try{let r=y.dirname(n);v.existsSync(r)||v.mkdirSync(r,{recursive:!0});let i=U(v.readFileSync(t,`utf8`));v.writeFileSync(n,i),f(`debug`,`[Kilo] Transformed and copied ${e}-rules to ${n}`)}catch(e){f(`error`,`[Kilo] Failed to transform ${t} to ${n}: ${e.message}`)}}}function ke(e){let t=y.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=y.join(e,`.kilo`);if(v.existsSync(n)&&(v.readdirSync(n).forEach(e=>{if(e.startsWith(`rules-`)){let t=y.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 Ae(e,t){G(e,t)}const je=L({name:`kilo`,displayName:`Kilo Code`,url:`kilocode.com`,docsUrl:`docs.kilocode.com`,profileDir:`.kilo`,rulesDir:`.kilo/rules`,toolMappings:R.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:G,onRemove:ke,onPostConvert:Ae}),Me=L({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=y.join(t,`kiro-hooks`),r=y.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=y.join(n,e),i=y.join(r,e);v.copyFileSync(t,i)}),e.length>0&&f(`info`,`[Kiro] Installed ${e.length} Taskmaster hooks in .kiro/hooks/`)}}});function Ne(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 Pe(e,t){let n=y.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=Ne(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 Fe(e){let t=y.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 Ie=L({name:`opencode`,displayName:`OpenCode`,url:`opencode.ai`,docsUrl:`opencode.ai/docs/`,profileDir:`.`,rulesDir:`.`,mcpConfigName:`opencode.json`,includeDefaultRules:!1,fileMap:{"AGENTS.md":`AGENTS.md`},onPostConvert:Pe,onRemove:Fe});function Le(e){if(!v.existsSync(e)){f(`warn`,`[Roo] MCP configuration file not found at ${e}`);return}try{let t=JSON.parse(v.readFileSync(e,`utf8`));if(t.mcpServers&&t.mcpServers[`task-master-ai`]){let n=t.mcpServers[`task-master-ai`];n.timeout=300,v.writeFileSync(e,I(t)+`
`),f(`debug`,`[Roo] Enhanced MCP configuration with timeout at ${e}`)}else f(`warn`,`[Roo] task-master-ai server not found in MCP configuration`)}catch(e){f(`error`,`[Roo] Failed to enhance MCP configuration: ${e.message}`)}}function Re(e,t){let n=y.join(t,`roocode`);if(!v.existsSync(n)){f(`error`,`[Roo] Source directory does not exist: ${n}`);return}K(n,e),f(`debug`,`[Roo] Copied roocode directory to ${e}`);let r=y.join(n,`.roo`),i=y.join(n,`.roomodes`),a=y.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 ue){let n=y.join(r,`rules-${t}`,`${t}-rules`),i=y.join(e,`.roo`,`rules-${t}`,`${t}-rules`);if(v.existsSync(n))try{let e=y.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 K(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=>{K(y.join(e,n),y.join(t,n))})):v.copyFileSync(e,t)}function ze(e){let t=y.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=y.join(e,`.roo`);if(v.existsSync(n)){let e=y.join(n,`mcp.json`);try{v.rmSync(e,{force:!0}),f(`debug`,`[Roo] Removed MCP configuration from ${e}`)}catch(e){f(`error`,`[Roo] Failed to remove MCP configuration: ${e.message}`)}if(v.readdirSync(n).forEach(e=>{if(e.startsWith(`rules-`)){let t=y.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 Be(e,t){let n=y.join(e,`.roo`,`mcp.json`);try{Le(n)}catch(e){f(`error`,`[Roo] Failed to enhance MCP configuration: ${e.message}`)}}const Ve=L({name:`roo`,displayName:`Roo Code`,url:`roocode.com`,docsUrl:`docs.roocode.com`,toolMappings:R.ROO_STYLE,mcpConfig:!0,onAdd:Re,onRemove:ze,onPostConvert:Be}),He=L({name:`trae`,displayName:`Trae`,url:`trae.ai`,docsUrl:`docs.trae.ai`,mcpConfig:!1});function Ue(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 We(e,t){let n=y.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=Ue(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 Ge(e){let t=y.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=y.dirname(t);try{v.readdirSync(e).length===0&&(v.rmSync(e,{recursive:!0,force:!0}),f(`debug`,`[VS Code] Removed empty .vscode directory`))}catch{}}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 Ke=L({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:We,onRemove:Ge}),qe=L({name:`windsurf`,displayName:`Windsurf`,url:`windsurf.com`,docsUrl:`docs.windsurf.com`});function Je(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 Ye(e,t){}function Xe(e){let t=y.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=y.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=y.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 Ze(e,t){let n=y.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=Je(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 Qe=L({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:Ye,onRemove:Xe,onPostConvert:Ze});var $e=e({ampProfile:()=>_e,claudeProfile:()=>xe,clineProfile:()=>Se,codexProfile:()=>Ce,cursorProfile:()=>De,geminiProfile:()=>Oe,kiloProfile:()=>je,kiroProfile:()=>Me,opencodeProfile:()=>Ie,rooProfile:()=>Ve,traeProfile:()=>He,vscodeProfile:()=>Ke,windsurfProfile:()=>qe,zedProfile:()=>Qe});function et(e){return A.includes(e)}function q(e){if(!et(e))return null;let t=$e[`${e}Profile`];if(!t)throw Error(`Profile not found: static import missing for '${e}'. Valid profiles: ${A.join(`, `)}`);return t}function tt(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 nt(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 rt(e,t){let n=e;return t.docUrls.forEach(e=>{n=(e.to,n.replace(e.from,e.to))}),n}function it(e,t){let{pathPattern:n,replacement:r}=t.fileReferences;return e.replace(n,r)}function at(e,t,n){let r=e;return r=it(r,t),r=tt(r,t),r=nt(r,t),r=rt(r,t),n.forEach(e=>{r=(e.to,r.replace(e.from,e.to))}),r}function ot(e,t){let n=y.join(e,t.rulesDir),r=0,i=0;if(typeof t.onAddRulesProfile==`function`)try{let e=M();t.onAddRulesProfile(n,e),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(!P(e)){f(`warn`,`[Rule Transformer] Source file not found: ${e}, skipping`);continue}let i=t.fileMap[e],o=y.join(n,i),s=y.dirname(o);v.existsSync(s)||v.mkdirSync(s,{recursive:!0});let c=F(e,`utf8`);a||(c=at(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{fe(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 e=M();t.onPostConvertRulesProfile(n,e),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 st(e,t){let n=y.join(e,t.rulesDir),r=y.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(n),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=y.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(y.join(t,e.toString()))})}catch{}}}else s=v.readdirSync(n,{recursive:!0});let c=s.filter(e=>{let t=y.join(n,e);try{return v.statSync(t).isFile()}catch{return!1}}).map(e=>e.toString());for(let e of r){let t=y.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=pe(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 ct(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(l[n]){let i=l[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 J={debug:0,info:1,warn:2,error:3,success:4},lt=process.env.TASKMASTER_LOG_LEVEL?J[process.env.TASKMASTER_LOG_LEVEL.toLowerCase()]:J.info;function ut(){c()||h()}function Y(e,...t){let n={debug:_.gray(`đ`),info:_.blue(`âšī¸`),warn:_.yellow(`â ī¸`),error:_.red(`â`),success:_.green(`â
`)};if(J[e]>=lt){let r=n[e]||``;c()||(e===`error`?console.error(r,_.red(...t)):e===`warn`?console.warn(r,_.yellow(...t)):e===`success`?console.log(r,_.green(...t)):e===`info`?console.log(r,_.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 X(e){v.existsSync(e)||(v.mkdirSync(e,{recursive:!0}),Y(`info`,`Created directory: ${e}`))}function dt(){let e=process.env.HOME||process.env.USERPROFILE,t;if(process.env.SHELL?.includes(`zsh`))t=y.join(e,`.zshrc`);else if(process.env.SHELL?.includes(`bash`))t=y.join(e,`.bashrc`);else return Y(`warn`,`Could not determine shell type. Aliases not added.`),!1;try{if(!v.existsSync(t))return Y(`warn`,`Shell config file ${t} not found. Aliases not added.`),!1;if(v.readFileSync(t,`utf8`).includes(`alias tm='task-master'`))return Y(`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),Y(`success`,`Added Task Master aliases to ${t}`),Y(`info`,`To use the aliases in your current terminal, run: source ${t}`),!0}catch(e){return Y(`error`,`Failed to add aliases: ${e.message}`),!1}}function ft(e){let t=y.join(e,p);if(v.existsSync(t)){Y(`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)),Y(`success`,`Created initial state file: ${t}`),Y(`info`,`Default tag set to "master" for task organization`)}catch(e){Y(`error`,`Failed to create state file: ${e.message}`)}}function Z(e,t,n={}){if(!P(e)){Y(`error`,`Source file not found: ${e}`);return}let r=F(e,`utf8`);if(Object.entries(n).forEach(([e,t])=>{let n=RegExp(`\\{\\{${e}\\}\\}`,`g`);r=r.replace(n,t)}),v.existsSync(t)){let e=y.basename(t);if(e===`.gitignore`){Y(`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),Y(`success`,`Updated ${t} with additional entries`)}else Y(`info`,`No new content to add to ${t}`);return}if(e===`README-task-master.md`){Y(`info`,`${t} already exists`);let e=y.join(y.dirname(t),`README-task-master.md`);v.writeFileSync(e,r),Y(`success`,`Created ${e} (preserved original README-task-master.md)`);return}Y(`warn`,`${t} already exists, skipping.`);return}v.writeFileSync(t,r),Y(`info`,`Created file: ${t}`)}async function pt(e={}){c()||ut(),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?(Y(`info`,`Using rule profiles provided via command line: ${e.rules.join(`, `)}`),n=e.rules):t?(Y(`info`,`No rules specified in non-interactive mode, defaulting to all profiles.`),n=A):(Y(`info`,`No rules specified; interactive setup will be launched to select profiles.`),n=[]),t){c()||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 Y(`info`,`DRY RUN MODE: No files will be modified`),Y(`info`,`Would initialize Task Master project`),Y(`info`,`Would create/update necessary project files`),Y(`info`,`${r?`Would add shell aliases (tm, taskmaster)`:`Would skip shell aliases`}`),Y(`info`,`${i?`Would initialize Git repository`:`Would skip Git initialization`}`),Y(`info`,`${a?`Would store tasks in Git`:`Would exclude tasks from Git`}`),{dryRun:!0};mt(r,i,a,t,e,n)}else{Y(`info`,`Required options not provided, proceeding with prompts.`);try{let t=C.createInterface({input:process.stdin,output:process.stdout}),r=!0;r=e.addAliases===void 0?(await Q(t,_.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 Q(t,_.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 Q(t,_.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(_.blue(`Add shell aliases (so you can use "tm" instead of "task-master"):`),_.white(r?`Yes`:`No`)),console.log(_.blue(`Initialize Git repository in project root:`),_.white(i?`Yes`:`No`)),console.log(_.blue(`Store tasks in Git (tasks.json and tasks/ directory):`),_.white(a?`Yes`:`No`)),(await Q(t,_.yellow(`
Do you want to continue with these settings? (Y/n): `))).trim().toLowerCase()===`n`){t.close(),Y(`info`,`Project initialization cancelled by user`),process.exit(0);return}e.rulesExplicitlyProvided&&Y(`info`,`Using rule profiles provided via command line: ${n.join(`, `)}`);let o=e.dryRun||!1;if(o)return Y(`info`,`DRY RUN MODE: No files will be modified`),Y(`info`,`Would initialize Task Master project`),Y(`info`,`Would create/update necessary project files`),Y(`info`,`${r?`Would add shell aliases (tm, taskmaster)`:`Would skip shell aliases`}`),Y(`info`,`${i?`Would initialize Git repository`:`Would skip Git initialization`}`),Y(`info`,`${a?`Would store tasks in Git`:`Would exclude tasks from Git`}`),{dryRun:!0};mt(r,i,a,o,e,n),t.close()}catch(e){rl&&rl.close(),Y(`error`,`Error during initialization process: ${e.message}`),process.exit(1)}}}function Q(e,t){return new Promise(n=>{e.question(t,e=>{n(e)})})}function mt(e,l,f,p,h,v=A){let b=process.cwd();Y(`info`,`Initializing project in ${b}`),X(y.join(b,a)),X(y.join(b,n)),X(y.join(b,o)),X(y.join(b,s)),X(y.join(b,i)),ft(b);let C={year:new Date().getFullYear()};function T(e){let t=q(e);t?ot(b,t):Y(`warn`,`Unknown rule profile: ${e}`)}Z(`env.example`,y.join(b,d),C),Z(`config.json`,y.join(b,r),{...C}),ct(y.join(b,r))?Y(`info`,`Updated config with correct maxTokens values`):Y(`warn`,`Could not update maxTokens in config`);try{let e=F(`gitignore`,`utf8`);le(y.join(b,u),e,f,Y)}catch(e){Y(`error`,`Failed to create .gitignore: ${e.message}`)}Z(`example_prd.txt`,y.join(b,t)),Z(`example_prd_rpg.txt`,y.join(b,i,`example_prd_rpg.txt`));try{l===!1?Y(`info`,`Git initialization skipped due to --no-git flag.`):l===!0?m()?Y(`info`,`Existing Git repository detected â skipping git init despite --git flag.`):(Y(`info`,`Initializing Git repository due to --git flag...`),x(`git init`,{cwd:b,stdio:`ignore`}),Y(`success`,`Git repository initialized`)):m()?Y(`info`,`Existing Git repository detected â skipping git init.`):(Y(`info`,`No Git repository detected. Initializing one in project root...`),x(`git init`,{cwd:b,stdio:`ignore`}),Y(`success`,`Git repository initialized`))}catch{Y(`warn`,`Git not available, skipping repository initialization`)}if(h.rulesExplicitlyProvided||h.yes){Y(`info`,`Generating profile rules from command-line flags...`);for(let e of v)T(e)}e&&dt();let E={cwd:b,stdio:`inherit`};if(c()?(E.stdio=`ignore`,Y(`info`,`Running npm install silently...`)):console.log(S(_.cyan(`Installing dependencies...`),{padding:.5,margin:.5,borderStyle:`round`,borderColor:`blue`})),!c()&&!p&&!h?.yes&&!h.rulesExplicitlyProvided){console.log(S(_.cyan(`Configuring Rule Profiles...`),{padding:.5,margin:{top:1,bottom:.5},borderStyle:`round`,borderColor:`blue`})),Y(`info`,`Running interactive rules setup. Please select which rule profiles to include.`);try{x(`npx task-master rules --setup`,{stdio:`inherit`,cwd:b}),Y(`success`,`Rule profiles configured.`)}catch(e){Y(`error`,`Failed to configure rule profiles:`,e.message),Y(`warn`,`You may need to run "task-master rules --setup" manually.`)}}else (c()||p||h?.yes)&&(h.rulesExplicitlyProvided?Y(`info`,`Skipping interactive rules setup because --rules flag was used.`):Y(`info`,`Skipping interactive rules setup in non-interactive mode.`));if(!c()&&!p&&!h?.yes){console.log(S(_.cyan(`Configuring Response Language...`),{padding:.5,margin:{top:1,bottom:.5},borderStyle:`round`,borderColor:`blue`})),Y(`info`,`Running interactive response language setup. Please input your preferred language.`);try{x(`npx task-master lang --setup`,{stdio:`inherit`,cwd:b}),Y(`success`,`Response Language configured.`)}catch(e){Y(`error`,`Failed to configure response language:`,e.message),Y(`warn`,`You may need to run "task-master lang --setup" manually.`)}}else c()&&!p?(Y(`info`,`Skipping interactive response language setup in silent (MCP) mode.`),Y(`warn`,`Please configure response language using "task-master models --set-response-language" or the "models" MCP tool.`)):p&&Y(`info`,`DRY RUN: Skipping interactive response language setup.`);if(!c()&&!p&&!h?.yes){console.log(S(_.cyan(`Configuring AI Models...`),{padding:.5,margin:{top:1,bottom:.5},borderStyle:`round`,borderColor:`blue`})),Y(`info`,`Running interactive model setup. Please select your preferred AI models.`);try{x(`npx task-master models --setup`,{stdio:`inherit`,cwd:b}),Y(`success`,`AI Models configured.`)}catch(e){Y(`error`,`Failed to configure AI models:`,e.message),Y(`warn`,`You may need to run "task-master models --setup" manually.`)}}else c()&&!p?(Y(`info`,`Skipping interactive model setup in silent (MCP) mode.`),Y(`warn`,`Please configure AI models using "task-master models --set-..." or the "models" MCP tool.`)):p?Y(`info`,`DRY RUN: Skipping interactive model setup.`):h?.yes&&(Y(`info`,`Skipping interactive model setup due to --yes flag.`),Y(`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?(Y(`info`,`Adding shell aliases...`),dt()&&Y(`success`,`Shell aliases added successfully`)):e&&p&&Y(`info`,`DRY RUN: Would add shell aliases (tm, taskmaster)`),c()||console.log(S(`${g.multiline(w.textSync(`Success!`,{font:`Standard`}))}\n${_.green(`Project initialized successfully!`)}`,{padding:1,margin:1,borderStyle:`double`,borderColor:`green`})),c()||console.log(S(`${_.cyan.bold(`Things you should do next:`)}\n\n${_.white(`1. `)}${_.yellow("Configure AI models (if needed) and add API keys to `.env`")}\n${_.white(` ââ `)}${_.dim("Models: Use `task-master models` commands")}\n${_.white(` ââ `)}${_.dim(`Keys: Add provider API keys to .env (or inside the MCP config file i.e. .cursor/mcp.json)`)}\n${_.white(`2. `)}${_.yellow(`Discuss your idea with AI and ask for a PRD, and save it to .taskmaster/docs/prd.txt`)}\n${_.white(` ââ `)}${_.dim(`Simple projects: Use `)}${_.cyan(`example_prd.txt`)}${_.dim(` template`)}\n${_.white(` ââ `)}${_.dim(`Complex systems: Use `)}${_.cyan(`example_prd_rpg.txt`)}${_.dim(` template (for dependency-aware task graphs)`)}\n${_.white(`3. `)}${_.yellow(`Ask Cursor Agent (or run CLI) to parse your PRD and generate initial tasks:`)}\n${_.white(` ââ `)}${_.dim(`MCP Tool: `)}${_.cyan(`parse_prd`)}${_.dim(` | CLI: `)}${_.cyan(`task-master parse-prd .taskmaster/docs/prd.txt`)}\n${_.white(`4. `)}${_.yellow(`Ask Cursor to analyze the complexity of the tasks in your PRD using research`)}\n