UNPKG

task-master-ai

Version:

A task management system for ambitious AI-driven development that doesn't overwhelm and confuse Cursor.

44 lines 245 kB
import{t as e}from"./git-utils-DllbRE35.js";import t,{join as n,resolve as r}from"node:path";import i from"chalk";import{createClient as a,isAuthError as o}from"@supabase/supabase-js";import s from"fs";import c,{join as l}from"path";import u from"fs/promises";import{Writer as d}from"steno";import f from"crypto";import p from"os";import m from"node:fs/promises";import h from"fs-extra";import{simpleGit as ee}from"simple-git";import te,{constants as ne,existsSync as g,readFileSync as re,readdirSync as ie}from"node:fs";import{z as _}from"zod";import{exec as ae,execSync as oe}from"child_process";import{promisify as se}from"util";import ce from"node:os";import"node:crypto";import{format as le,formatDistanceToNow as ue}from"date-fns";import{fileURLToPath as de}from"url";import fe from"dotenv";const pe=600*1e3,me=3,he=[`add-dependency`,`remove-dependency`,`validate-dependencies`,`fix-dependencies`,`clear-subtasks`,`models`,`generate`];function ge(e){return he.includes(e)}function _e(e){let{hasValidSession:t,briefName:n,storageType:r,commandName:i}=e;return!ge(i)||!t||r!==`api`?{isBlocked:!1,commandName:i}:{isBlocked:!0,briefName:n||`remote brief`,commandName:i}}const v={FILE_NOT_FOUND:`FILE_NOT_FOUND`,FILE_READ_ERROR:`FILE_READ_ERROR`,FILE_WRITE_ERROR:`FILE_WRITE_ERROR`,PARSE_ERROR:`PARSE_ERROR`,JSON_PARSE_ERROR:`JSON_PARSE_ERROR`,YAML_PARSE_ERROR:`YAML_PARSE_ERROR`,VALIDATION_ERROR:`VALIDATION_ERROR`,SCHEMA_VALIDATION_ERROR:`SCHEMA_VALIDATION_ERROR`,TYPE_VALIDATION_ERROR:`TYPE_VALIDATION_ERROR`,API_ERROR:`API_ERROR`,NETWORK_ERROR:`NETWORK_ERROR`,AUTHENTICATION_ERROR:`AUTHENTICATION_ERROR`,AUTHORIZATION_ERROR:`AUTHORIZATION_ERROR`,TASK_NOT_FOUND:`TASK_NOT_FOUND`,TASK_DEPENDENCY_ERROR:`TASK_DEPENDENCY_ERROR`,TASK_STATUS_ERROR:`TASK_STATUS_ERROR`,STORAGE_ERROR:`STORAGE_ERROR`,DATABASE_ERROR:`DATABASE_ERROR`,CONFIG_ERROR:`CONFIG_ERROR`,MISSING_CONFIGURATION:`MISSING_CONFIGURATION`,INVALID_CONFIGURATION:`INVALID_CONFIGURATION`,PROVIDER_ERROR:`PROVIDER_ERROR`,PROVIDER_NOT_FOUND:`PROVIDER_NOT_FOUND`,PROVIDER_INITIALIZATION_ERROR:`PROVIDER_INITIALIZATION_ERROR`,INTERNAL_ERROR:`INTERNAL_ERROR`,INVALID_INPUT:`INVALID_INPUT`,NOT_IMPLEMENTED:`NOT_IMPLEMENTED`,UNKNOWN_ERROR:`UNKNOWN_ERROR`,NOT_FOUND:`NOT_FOUND`,NO_BRIEF_SELECTED:`NO_BRIEF_SELECTED`};var y=class e extends Error{code;context;cause;timestamp;constructor(t,n=v.UNKNOWN_ERROR,r={},i){super(t),this.name=`TaskMasterError`,this.code=n,this.cause=i,this.timestamp=new Date,this.context={timestamp:this.timestamp,...r},Object.setPrototypeOf(this,e.prototype),Error.captureStackTrace&&Error.captureStackTrace(this,e),i?.stack&&(this.stack=`${this.stack}\nCaused by: ${i.stack}`)}getUserMessage(){return this.context.userMessage||this.message}getSanitizedDetails(){let{details:e,resource:t,operation:n}=this.context;return{code:this.code,message:this.getUserMessage(),...t&&{resource:t},...n&&{operation:n},...e&&typeof e==`object`&&!this.containsSensitiveInfo(e)&&{details:e}}}containsSensitiveInfo(e){if(typeof e!=`object`||!e)return!1;let t=[`password`,`token`,`key`,`secret`,`auth`,`credential`],n=JSON.stringify(e).toLowerCase();return t.some(e=>n.includes(e))}toJSON(){let t={name:this.name,message:this.message,code:this.code,context:this.context,stack:this.stack};return this.cause&&(this.cause instanceof e?t.cause=this.cause.toJSON():t.cause={name:this.cause.name,message:this.cause.message,code:v.UNKNOWN_ERROR,context:{},stack:this.cause.stack}),t}toString(){let e=`${this.name}[${this.code}]: ${this.message}`;return this.context.operation&&(e+=` (operation: ${this.context.operation})`),this.context.resource&&(e+=` (resource: ${this.context.resource})`),this.cause&&(e+=`\nCaused by: ${this.cause.toString()}`),e}is(e){return this.code===e}hasCode(t){return this.is(t)?!0:this.cause instanceof e?this.cause.hasCode(t):!1}withContext(t){return new e(this.message,this.code,{...this.context,...t},this.cause)}wrap(t,n=v.INTERNAL_ERROR,r={}){return new e(t,n,r,this)}};let b=function(e){return e[e.SILENT=0]=`SILENT`,e[e.ERROR=1]=`ERROR`,e[e.WARN=2]=`WARN`,e[e.INFO=3]=`INFO`,e[e.DEBUG=4]=`DEBUG`,e}({});var ve=class e{config;static DEFAULT_CONFIG={level:b.SILENT,silent:!1,prefix:``,timestamp:!1,colors:!0,mcpMode:!1,logCallback:void 0};constructor(t={}){let n={};if((process.env.MCP_MODE===`true`||process.env.TASK_MASTER_MCP===`true`)&&(n.mcpMode=!0),(process.env.TASK_MASTER_SILENT===`true`||process.env.TM_SILENT===`true`)&&(n.silent=!0),process.env.TASK_MASTER_LOG_LEVEL||process.env.TM_LOG_LEVEL){let e=(process.env.TASK_MASTER_LOG_LEVEL||process.env.TM_LOG_LEVEL||``).toUpperCase();e in b&&(n.level=b[e])}(process.env.NO_COLOR===`true`||process.env.TASK_MASTER_NO_COLOR===`true`)&&(n.colors=!1),this.config={...e.DEFAULT_CONFIG,...t,...n},this.config.mcpMode&&!this.config.logCallback&&(this.config.silent=!0)}shouldLog(e){return this.config.logCallback?e<=this.config.level:this.config.silent||this.config.mcpMode?!1:e<=this.config.level}formatMessage(e,t,...n){let r=``;if(this.config.timestamp){let e=new Date().toISOString();r+=this.config.colors?i.gray(`[${e}] `):`[${e}] `}if(this.config.prefix&&(r+=this.config.colors?i.cyan(`[${this.config.prefix}] `):`[${this.config.prefix}] `),this.config.colors)switch(e){case b.ERROR:t=i.red(t);break;case b.WARN:t=i.yellow(t);break;case b.INFO:break;case b.DEBUG:t=i.gray(t);break}return r+=t,n.length>0&&(r+=` `+n.map(e=>typeof e==`object`?JSON.stringify(e,null,2):String(e)).join(` `)),r}isLogObject(e){return typeof e==`object`&&!!e&&`info`in e&&`warn`in e&&`error`in e&&`debug`in e}output(e,t,n,...r){let i=this.formatMessage(e,n,...r);if(this.config.logCallback){if(this.isLogObject(this.config.logCallback)){let e=t.toLowerCase();e in this.config.logCallback&&this.config.logCallback[e](i)}else this.config.logCallback(t.toLowerCase(),i);return}switch(e){case b.ERROR:console.error(i);break;case b.WARN:console.warn(i);break;default:console.log(i);break}}error(e,...t){this.shouldLog(b.ERROR)&&this.output(b.ERROR,`ERROR`,e,...t)}warn(e,...t){this.shouldLog(b.WARN)&&this.output(b.WARN,`WARN`,e,...t)}info(e,...t){this.shouldLog(b.INFO)&&this.output(b.INFO,`INFO`,e,...t)}debug(e,...t){this.shouldLog(b.DEBUG)&&this.output(b.DEBUG,`DEBUG`,e,...t)}log(e,...t){if(this.config.logCallback){let n=t.length>0?[e,...t].join(` `):e;this.isLogObject(this.config.logCallback)?this.config.logCallback.info(n):this.config.logCallback(`log`,n);return}this.config.silent||this.config.mcpMode||(t.length>0?console.log(e,...t):console.log(e))}setConfig(e){this.config={...this.config,...e},this.config.mcpMode&&!this.config.logCallback&&(this.config.silent=!0)}getConfig(){return{...this.config}}child(t,n){let r=this.config.prefix?`${this.config.prefix}:${t}`:t;return new e({...this.config,...n,prefix:r})}};let ye=null;const be=new Map;function xe(e){return new ve(e)}function x(e,t){return e?(be.has(e)||be.set(e,xe({prefix:e,...t})),be.get(e)):(ye||=xe(t),ye)}const Se=c.join(process.env.HOME||process.env.USERPROFILE||`~`,`.taskmaster`,`session.json`);var Ce=class{storage=new Map;persistPath;logger=x(`SupabaseSessionStorage`);writer;initPromise;constructor(e=Se){this.persistPath=e,this.writer=new d(e),this.initPromise=this.load()}async load(){try{let e=c.dirname(this.persistPath);if(await u.mkdir(e,{recursive:!0,mode:448}),s.existsSync(this.persistPath)){let e=JSON.parse(await u.readFile(this.persistPath,`utf8`));Object.entries(e).forEach(([e,t])=>this.storage.set(e,t)),this.logger.debug(`Loaded session from disk`,{keys:Array.from(this.storage.keys())})}}catch(e){this.logger.error(`Failed to load session:`,e)}}async persist(){try{let e=Object.fromEntries(this.storage),t=JSON.stringify(e,null,2);await this.writer.write(t+` `),this.logger.debug(`Persisted session to disk (steno)`)}catch(e){this.logger.error(`Failed to persist session:`,e)}}async getItem(e){await this.initPromise;let t=this.storage.get(e)??null;return this.logger.debug(`getItem called`,{key:e,hasValue:!!t}),t}async setItem(e,t){await this.initPromise,this.logger.debug(`setItem called`,{key:e}),this.storage.set(e,t),await this.persist()}async removeItem(e){await this.initPromise,this.logger.debug(`removeItem called`,{key:e}),this.storage.delete(e),await this.persist()}async clear(){await this.initPromise,this.logger.debug(`clear called`),this.storage.clear(),await this.persist()}},S=class extends Error{mfaChallenge;constructor(e,t,n,r){super(e),this.code=t,this.cause=n,this.name=`AuthenticationError`,this.mfaChallenge=r,n&&n instanceof Error&&(this.stack=`${this.stack}\nCaused by: ${n.stack}`)}};function C(e){return o(e)}const we={refresh_token_not_found:`Your session has expired. Please log in again with: task-master login`,refresh_token_already_used:`Your session has expired (token was already used). Please log in again with: task-master login`,invalid_refresh_token:`Your session has expired (invalid token). Please log in again with: task-master login`,session_expired:`Your session has expired. Please log in again with: task-master login`,user_not_found:`User account not found. Please log in again with: task-master login`,invalid_credentials:`Invalid credentials. Please log in again with: task-master login`},Te=[`refresh_token_not_found`,`refresh_token_already_used`];function w(e){return C(e)?Te.includes(e.code||``):!1}function Ee(e,t){let n=e.code,r=n&&we[n]||`${t}: ${e.message}`,i=`REFRESH_FAILED`;return n===`refresh_token_not_found`||n===`refresh_token_already_used`||n===`invalid_refresh_token`||n===`session_expired`||n===`user_not_found`?i=`NOT_AUTHENTICATED`:n===`invalid_credentials`&&(i=`INVALID_CREDENTIALS`),new S(r,i,e)}function De(){let{publicKey:e,privateKey:t}=f.generateKeyPairSync(`rsa`,{modulusLength:2048,publicKeyEncoding:{type:`spki`,format:`pem`},privateKeyEncoding:{type:`pkcs8`,format:`pem`}});return{publicKey:e,privateKey:t}}function Oe(e,t){try{let n=Buffer.from(e.encrypted_key,`base64`),r=Buffer.from(e.encrypted_data,`base64`),i=Buffer.from(e.iv,`base64`),a=Buffer.from(e.auth_tag,`base64`),o=f.privateDecrypt({key:t,padding:f.constants.RSA_PKCS1_OAEP_PADDING,oaepHash:`sha256`},n),s=f.createDecipheriv(`aes-256-gcm`,o,i);s.setAuthTag(a);let c=Buffer.concat([s.update(r),s.final()]);return JSON.parse(c.toString(`utf8`))}catch(e){throw new S(`Token decryption failed: ${e instanceof Error?e.message:`Unknown error`}`,`DECRYPTION_FAILED`,e)}}var ke=class e{static instance=null;client=null;sessionStorage;logger=x(`SupabaseAuthClient`);constructor(){this.sessionStorage=new Ce}static getInstance(){return e.instance||=new e,e.instance}static resetInstance(){e.instance&&(e.instance.client=null),e.instance=null}getClient(){if(!this.client){let e=process.env.TM_SUPABASE_URL||`https://tryhamster.com`,t=process.env.TM_SUPABASE_ANON_KEY||`eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJzdXBhYmFzZSIsInJlZiI6Im5zdHhhdGRwbnNmYWxja3hhd3R6Iiwicm9sZSI6ImFub24iLCJpYXQiOjE3NDg3MzU3NTYsImV4cCI6MjA2NDMxMTc1Nn0.GF897_2zXRxl4pkeQ89-7xF4TkJfJuYPWKhv1bTbv9k`;if(!e||!t)throw new S(`Supabase configuration missing. Please set TM_SUPABASE_URL and TM_SUPABASE_ANON_KEY (runtime) or TM_PUBLIC_SUPABASE_URL and TM_PUBLIC_SUPABASE_ANON_KEY (build-time) environment variables.`,`CONFIG_MISSING`);this.client=a(e,t,{auth:{storage:this.sessionStorage,autoRefreshToken:!0,persistSession:!0,detectSessionInUrl:!1}})}return this.client}async initialize(){let e=this.getClient();try{let{data:{session:t},error:n}=await e.auth.getSession();return n?(w(n)||this.logger.warn(`Failed to restore session:`,n),null):(t&&this.logger.info(`Session restored successfully`),t)}catch(e){return w(e)?this.logger.debug(`Session not available (expected during MFA flow)`):C(e)?this.logger.warn(`Session expired or invalid`):this.logger.error(`Error initializing session:`,e),null}}async signInWithPKCE(){let e=this.getClient();try{let{data:t,error:n}=await e.auth.signInWithOAuth({provider:`github`,options:{redirectTo:process.env.TM_AUTH_CALLBACK_URL||`http://localhost:3421/auth/callback`,scopes:`email`}});if(n)throw new S(`Failed to initiate PKCE flow: ${n.message}`,`PKCE_INIT_FAILED`);if(!t?.url)throw new S(`No authorization URL returned`,`INVALID_RESPONSE`);return{url:t.url,codeVerifier:``}}catch(e){throw e instanceof S?e:new S(`Failed to start PKCE flow: ${e.message}`,`PKCE_FAILED`)}}async exchangeCodeForSession(e){let t=this.getClient();try{let{data:n,error:r}=await t.auth.exchangeCodeForSession(e);if(r)throw new S(`Failed to exchange code: ${r.message}`,`CODE_EXCHANGE_FAILED`);if(!n?.session)throw new S(`No session returned from code exchange`,`INVALID_RESPONSE`);return this.logger.info(`Successfully exchanged code for session`),n.session}catch(e){throw e instanceof S?e:new S(`Code exchange failed: ${e.message}`,`CODE_EXCHANGE_FAILED`)}}async getSession(){let e=this.getClient();try{let{data:{session:t},error:n}=await e.auth.getSession();return n?(w(n)||this.logger.warn(`Failed to get session:`,n),null):t}catch(e){return w(e)?this.logger.debug(`Session not available (expected during MFA flow)`):C(e)?this.logger.warn(`Session expired or invalid`):this.logger.error(`Error getting session:`,e),null}}async refreshSession(){let e=this.getClient();try{this.logger.info(`Refreshing session...`);let{data:{session:t},error:n}=await e.auth.refreshSession();if(n)throw this.logger.error(`Failed to refresh session:`,n),Ee(n,`Failed to refresh session`);return t&&this.logger.info(`Successfully refreshed session`),t}catch(e){throw e instanceof S?e:C(e)?Ee(e,`Session refresh failed`):new S(`Failed to refresh session: ${e.message}`,`REFRESH_FAILED`)}}async getUser(){let e=this.getClient();try{let{data:{user:t},error:n}=await e.auth.getUser();return n?(this.logger.warn(`Failed to get user:`,n),null):t}catch(e){return this.logger.error(`Error getting user:`,e),null}}async signOut(){let e=this.getClient();try{let{error:t}=await e.auth.signOut({scope:`local`});t&&this.logger.warn(`Failed to sign out:`,t),this.sessionStorage.clear()}catch(e){this.logger.error(`Error during sign out:`,e)}}async setSession(e){let t=this.getClient();try{let{error:n}=await t.auth.setSession({access_token:e.access_token,refresh_token:e.refresh_token});if(n)throw new S(`Failed to set session: ${n.message}`,`SESSION_SET_FAILED`);this.logger.info(`Session set successfully`)}catch(e){throw e instanceof S?e:new S(`Failed to set session: ${e.message}`,`SESSION_SET_FAILED`)}}async handleRecoverableError(e,t,n){return!t&&w(e)?(this.logger.debug(`MFA-expected error during token verification, clearing stale session and retrying`),await this.sessionStorage.clear(),n()):null}async verifyOneTimeCode(e,t=!1){let n=this.getClient(),r=()=>this.verifyOneTimeCode(e,!0);try{this.logger.info(`Verifying authentication token...`);let{data:i,error:a}=await n.auth.verifyOtp({token_hash:e,type:`magiclink`});if(a){let e=await this.handleRecoverableError(a,t,r);if(e)return e;throw this.logger.error(`Failed to verify token:`,a),Ee(a,`Failed to verify token`)}if(!i?.session)throw new S(`No session returned from token verification`,`INVALID_RESPONSE`);return this.logger.info(`Successfully verified authentication token`),i.session}catch(e){if(e instanceof S)throw e;if(C(e)){let n=await this.handleRecoverableError(e,t,r);if(n)return n;throw Ee(e,`Token verification failed`)}throw new S(`Token verification failed: ${e.message}`,`CODE_AUTH_FAILED`)}}async checkMFARequired(){let e=this.getClient();try{let{data:{session:t},error:n}=await e.auth.getSession();if(n||!t)return this.logger.warn(`No session available to check MFA`),{required:!1};let{data:r,error:i}=await e.auth.mfa.getAuthenticatorAssuranceLevel();if(i)return this.logger.warn(`Failed to get AAL:`,i),{required:!1};if(r?.currentLevel===`aal2`)return this.logger.info(`Session already at AAL2, MFA not required`),{required:!1};let{data:a,error:o}=await e.auth.mfa.listFactors();if(o)return this.logger.warn(`Failed to list MFA factors:`,o),{required:!1};let s=a?.totp?.filter(e=>e.status===`verified`);if(!s||s.length===0)return this.logger.info(`No verified MFA factors found`),{required:!1};let c=s[0];return this.logger.info(`MFA verification required`,{factorId:c.id,factorType:c.factor_type}),{required:!0,factorId:c.id,factorType:c.factor_type}}catch(e){return this.logger.error(`Error checking MFA requirement:`,e),{required:!1}}}async verifyMFA(e,t){let n=this.getClient();try{this.logger.info(`Verifying MFA code...`);let{data:r,error:i}=await n.auth.mfa.challenge({factorId:e});if(i||!r)throw new S(`Failed to create MFA challenge: ${i?.message||`Unknown error`}`,`MFA_VERIFICATION_FAILED`);let{data:a,error:o}=await n.auth.mfa.verify({factorId:e,challengeId:r.id,code:t});if(o)throw this.logger.error(`MFA verification failed:`,o),new S(`Invalid MFA code: ${o.message}`,`INVALID_MFA_CODE`);if(!a)throw new S(`No data returned from MFA verification`,`INVALID_RESPONSE`);let{data:{session:s},error:c}=await n.auth.refreshSession();if(c||!s)throw new S(`Failed to refresh session after MFA: ${c?.message||`No session returned`}`,`REFRESH_FAILED`);return this.logger.info(`Successfully verified MFA, session upgraded to AAL2`),s}catch(e){throw e instanceof S?e:new S(`MFA verification failed: ${e.message}`,`MFA_VERIFICATION_FAILED`)}}};const Ae=c.join(process.env.HOME||process.env.USERPROFILE||`~`,`.taskmaster`,`context.json`);var je=class e{static instance=null;logger=x(`ContextStore`);contextPath;constructor(e=Ae){this.contextPath=e}static getInstance(t){return e.instance||=new e(t),e.instance}static resetInstance(){e.instance=null}getContext(){try{if(!s.existsSync(this.contextPath))return null;let e=JSON.parse(s.readFileSync(this.contextPath,`utf8`));return this.logger.debug(`Loaded context from disk`),e}catch(e){return this.logger.error(`Failed to read context:`,e),null}}saveContext(e){try{let t={...this.getContext()||{},...e,lastUpdated:new Date().toISOString()},n=c.dirname(this.contextPath);s.existsSync(n)||s.mkdirSync(n,{recursive:!0,mode:448});let r=`${this.contextPath}.tmp`;s.writeFileSync(r,JSON.stringify(t,null,2),{mode:384}),s.renameSync(r,this.contextPath),this.logger.debug(`Saved context to disk`)}catch(e){throw new S(`Failed to save context: ${e.message}`,`SAVE_FAILED`,e)}}updateUserContext(e){let t=this.getContext(),n={...t?.selectedContext||{},...e,updatedAt:new Date().toISOString()};this.saveContext({...t,selectedContext:n})}getUserContext(){return this.getContext()?.selectedContext||null}clearUserContext(){let e=this.getContext();if(e){let{selectedContext:t,...n}=e;this.saveContext(n)}}clearContext(){try{s.existsSync(this.contextPath)&&(s.unlinkSync(this.contextPath),this.logger.debug(`Cleared context from disk`))}catch(e){throw new S(`Failed to clear context: ${e.message}`,`CLEAR_FAILED`,e)}}hasContext(){return this.getContext()!==null}getContextPath(){return this.contextPath}},Me=`task-master-ai`,Ne=`0.40.0`;const Pe=[`anthropic`,`openai`,`google`,`zai`,`zai-coding`,`perplexity`,`xai`,`groq`,`mistral`,`azure`,`openrouter`,`bedrock`,`ollama`],T={AZURE:`azure`,VERTEX:`vertex`,BEDROCK:`bedrock`,OPENROUTER:`openrouter`,OLLAMA:`ollama`,LMSTUDIO:`lmstudio`,OPENAI_COMPATIBLE:`openai-compatible`,CLAUDE_CODE:`claude-code`,MCP:`mcp`,GEMINI_CLI:`gemini-cli`,GROK_CLI:`grok-cli`,CODEX_CLI:`codex-cli`},Fe=Object.values(T),Ie=[...new Set([...Pe,...Fe])],Le=`.taskmaster/tasks/tasks.json`,Re=[`.taskmaster`,`.taskmaster/config.json`,Le,`.taskmasterconfig`],ze=`.git,.svn,.hg,.fossil,.github,.gitlab,.circleci,.travis.yml,.jenkins,.buildkite,.vscode,.idea,.project,.devcontainer,package-lock.json,yarn.lock,pnpm-lock.yaml,bun.lockb,bun.lock,deno.lock,deno.json,deno.jsonc,package.json,lerna.json,nx.json,turbo.json,rush.json,pnpm-workspace.yaml,Cargo.toml,Cargo.lock,go.mod,go.sum,go.work,pyproject.toml,setup.py,setup.cfg,poetry.lock,Pipfile,Pipfile.lock,uv.lock,Gemfile,Gemfile.lock,composer.json,composer.lock,build.gradle,build.gradle.kts,settings.gradle,settings.gradle.kts,pom.xml,build.sbt,project.clj,deps.edn,mix.exs,rebar.config,pubspec.yaml,Package.swift,CMakeLists.txt,Makefile,meson.build,BUILD.bazel,WORKSPACE,flake.nix,shell.nix,default.nix,Dockerfile,docker-compose.yml,docker-compose.yaml,Containerfile,kubernetes.yml,kubernetes.yaml,helm/Chart.yaml`.split(`,`),Be=[`tasks/tasks.json`,`tasks.json`,...ze,`requirements.txt`];[...Re,...Be];const Ve=Ne||`unknown`,He=[`pending`,`in-progress`,`done`,`deferred`,`cancelled`,`blocked`,`review`],Ue=[`done`,`completed`,`cancelled`];function We(e){return Ue.includes(e)}const Ge=[`text`,`json`,`compact`],Ke={done:`✓`,completed:`✓`,"in-progress":`►`,blocked:`⭕`,pending:`○`,deferred:`⏸`,cancelled:`✗`,review:`👁`};function qe(){return process.env.TM_BASE_DOMAIN||`https://tryhamster.com`}function Je(){return{baseUrl:qe(),configDir:c.join(p.homedir(),`.taskmaster`),configFile:c.join(p.homedir(),`.taskmaster`,`auth.json`)}}function Ye(e){return{...Je(),...e}}new Proxy({},{get(e,t){return Je()[t]}});var Xe=class{logger=x(`OAuthService`);contextStore;supabaseClient;configOverrides;authorizationUrl=null;keyPair=null;get baseUrl(){return Ye(this.configOverrides).baseUrl}constructor(e,t,n={}){this.contextStore=e,this.supabaseClient=t,this.configOverrides=n}async authenticate(e={}){let{openBrowser:t,timeout:n=3e5,onAuthUrl:r,onWaitingForAuth:i,onSuccess:a,onError:o}=e;try{return await this.authenticateWithBackendPKCE({openBrowser:t,timeout:n,onAuthUrl:r,onWaitingForAuth:i,onSuccess:a})}catch(e){let t=e instanceof S?e:new S(`OAuth authentication failed: ${e.message}`,`OAUTH_FAILED`,e);throw o&&t.code!==`MFA_REQUIRED`&&o(t),t}}async authenticateWithBackendPKCE(e){let{openBrowser:t,timeout:n=3e5,onAuthUrl:r,onWaitingForAuth:i,onSuccess:a}=e;this.keyPair=De(),this.logger.debug(`Generated RSA keypair for E2E encryption`);let o=await this.startBackendFlow();if(!o.success||!o.flow_id)throw new S(o.message||`Failed to start authentication flow`,`START_FLOW_FAILED`);let{flow_id:s,verification_url:c,poll_interval:l=2}=o;if(this.authorizationUrl=c||null,r&&c&&r(c),t&&c)try{await t(c),this.logger.debug(`Browser opened successfully with URL:`,c)}catch(e){this.logger.warn(`Failed to open browser automatically:`,e)}i&&i();let u=await this.pollForCompletion(s,l*1e3,n);u.refreshToken||this.logger.warn(`No refresh token received from server - session refresh will not work`);let d={access_token:u.token,refresh_token:u.refreshToken??``,expires_in:u.expiresAt?Math.floor((new Date(u.expiresAt).getTime()-Date.now())/1e3):3600,token_type:`bearer`,user:{id:u.userId,email:u.email,app_metadata:{},user_metadata:{},aud:`authenticated`,created_at:``}};return await this.supabaseClient.setSession(d),this.contextStore.saveContext({userId:u.userId,email:u.email}),await this.checkAndThrowIfMFARequired(),a&&a(u),u}async startBackendFlow(){let e=`${this.baseUrl}/api/auth/cli/start`;if(!this.keyPair)throw new S(`Keypair not generated before starting flow`,`INTERNAL_ERROR`);try{let t=await fetch(e,{method:`POST`,headers:{"Content-Type":`application/json`,"User-Agent":`TaskMasterCLI/${this.getCliVersion()}`},body:JSON.stringify({name:`Task Master CLI`,version:this.getCliVersion(),device:p.hostname(),user:p.userInfo().username,platform:p.platform(),public_key:this.keyPair.publicKey})});if(!t.ok)throw new S((await t.json().catch(()=>({}))).message||`HTTP ${t.status}`,`START_FLOW_FAILED`);return await t.json()}catch(e){throw e instanceof S?e:(this.logger.warn(`Failed to reach backend for PKCE flow:`,e),new S(`Unable to reach authentication server`,`BACKEND_UNREACHABLE`,e))}}async pollForCompletion(e,t,n){let r=`${this.baseUrl}/api/auth/cli/status?flow_id=${e}`,i=Date.now();if(!this.keyPair)throw new S(`Keypair not available for decryption`,`INTERNAL_ERROR`);for(;Date.now()-i<n;){try{let e=await fetch(r,{method:`GET`,headers:{"User-Agent":`TaskMasterCLI/${this.getCliVersion()}`}});if(!e.ok){let t=await e.json().catch(()=>({}));throw e.status===404?new S(`Authentication flow expired or not found`,`FLOW_NOT_FOUND`):new S(t.message||`HTTP ${e.status}`,`POLL_FAILED`)}let t=await e.json();if(!t.success)throw new S(t.message||`Failed to check status`,`POLL_FAILED`);switch(t.status){case`complete`:{if(!t.encrypted_tokens)throw new S(`Server returned no encrypted tokens`,`MISSING_TOKENS`);let e=Oe(t.encrypted_tokens,this.keyPair.privateKey);return this.logger.debug(`Successfully decrypted authentication tokens`),{token:e.access_token,refreshToken:e.refresh_token,userId:e.user_id,email:e.email,expiresAt:e.expires_in?new Date(Date.now()+e.expires_in*1e3).toISOString():void 0,tokenType:`standard`,savedAt:new Date().toISOString()}}case`failed`:throw new S(t.error_description||t.error||`Authentication failed`,`OAUTH_FAILED`);case`expired`:throw new S(`Authentication flow expired`,`AUTH_TIMEOUT`);case`pending`:case`authenticating`:this.logger.debug(`Flow status: ${t.status}, continuing to poll`);break;default:this.logger.warn(`Unknown flow status: ${t.status}`)}}catch(e){if(e instanceof S)throw e;this.logger.debug(`Poll request failed, will retry:`,e)}await new Promise(e=>setTimeout(e,t))}throw new S(`Authentication timeout`,`AUTH_TIMEOUT`)}getCliVersion(){return Ve}getAuthorizationUrl(){return this.authorizationUrl}async checkAndThrowIfMFARequired(){let e=await this.supabaseClient.checkMFARequired();if(e.required)throw!e.factorId||!e.factorType?(this.logger.error(`MFA required but factor information is incomplete`,{mfaCheck:e}),new S(`MFA is required but the server returned incomplete factor configuration. Please contact support or try re-enrolling MFA.`,`MFA_REQUIRED_INCOMPLETE`)):(this.logger.info(`MFA verification required after OAuth login`,{factorId:e.factorId,factorType:e.factorType}),new S(`MFA verification required. Please provide your authentication code.`,`MFA_REQUIRED`,void 0,{factorId:e.factorId,factorType:e.factorType}))}},Ze=class{logger=x(`OrganizationService`);constructor(e){this.supabaseClient=e}async getOrganizations(){try{let{data:e,error:t}=await this.supabaseClient.from(`user_accounts`).select(` id, name, slug `);if(t)throw new y(`Failed to fetch organizations: ${t.message}`,v.API_ERROR,{operation:`getOrganizations`},t);return!e||e.length===0?(this.logger.debug(`No organizations found for user`),[]):e.map(e=>({id:e.id??``,name:e.name??``,slug:e.slug??e.id??``}))}catch(e){throw e instanceof y?e:new y(`Failed to fetch organizations`,v.API_ERROR,{operation:`getOrganizations`},e)}}async getOrganization(e){try{let{data:t,error:n}=await this.supabaseClient.from(`accounts`).select(` id, name, slug `).eq(`id`,e).single();if(n){if(n.code===`PGRST116`)return null;throw new y(`Failed to fetch organization: ${n.message}`,v.API_ERROR,{operation:`getOrganization`,orgId:e},n)}if(!t)return null;let r=t;return{id:r.id,name:r.name,slug:r.slug||r.id}}catch(t){throw t instanceof y?t:new y(`Failed to fetch organization`,v.API_ERROR,{operation:`getOrganization`,orgId:e},t)}}async getBriefs(e){try{let{data:t,error:n}=await this.supabaseClient.from(`brief`).select(` id, account_id, document_id, status, created_at, updated_at, tasks(count), document:document_id ( id, document_name, title ) `).eq(`account_id`,e).order(`updated_at`,{ascending:!1});if(n)throw new y(`Failed to fetch briefs: ${n.message}`,v.API_ERROR,{operation:`getBriefs`,orgId:e},n);return!t||t.length===0?(this.logger.debug(`No briefs found for organization ${e}`),[]):t.map(e=>({id:e.id,accountId:e.account_id,documentId:e.document_id,status:e.status,createdAt:e.created_at,updatedAt:e.updated_at,taskCount:Array.isArray(e.tasks)?e.tasks[0]?.count??0:0,document:e.document?{id:e.document.id,document_name:e.document.document_name,title:e.document.title}:void 0}))}catch(t){throw t instanceof y?t:new y(`Failed to fetch briefs`,v.API_ERROR,{operation:`getBriefs`,orgId:e},t)}}async getBrief(e){try{let{data:t,error:n}=await this.supabaseClient.from(`brief`).select(` id, account_id, document_id, status, created_at, updated_at, document:document_id ( id, document_name, title, description ) `).eq(`id`,e).single();if(n){if(n.code===`PGRST116`)return null;throw new y(`Failed to fetch brief: ${n.message}`,v.API_ERROR,{operation:`getBrief`,briefId:e},n)}if(!t)return null;let r=t;return{id:r.id,accountId:r.account_id,documentId:r.document_id,status:r.status,createdAt:r.created_at,updatedAt:r.updated_at,document:r.document?{id:r.document.id,document_name:r.document.document_name,title:r.document.title,description:r.document.description}:void 0}}catch(t){throw t instanceof y?t:new y(`Failed to fetch brief`,v.API_ERROR,{operation:`getBrief`,briefId:e},t)}}async validateOrgAccess(e){try{return await this.getOrganization(e)!==null}catch(e){return this.logger.error(`Failed to validate org access: ${e}`),!1}}async validateBriefAccess(e){try{return await this.getBrief(e)!==null}catch(e){return this.logger.error(`Failed to validate brief access: ${e}`),!1}}async getTasks(e){try{let{data:t,error:n}=await this.supabaseClient.from(`tasks`).select(` *, document:document_id ( id, document_name, title, description ) `).eq(`brief_id`,e).order(`position`,{ascending:!0}).order(`subtask_position`,{ascending:!0}).order(`created_at`,{ascending:!0});if(n)throw new y(`Failed to fetch tasks: ${n.message}`,v.API_ERROR,{operation:`getTasks`,briefId:e},n);return!t||t.length===0?(this.logger.debug(`No tasks found for brief ${e}`),[]):t.map(e=>({id:e.id,briefId:e.brief_id,documentId:e.document_id,position:e.position,subtaskPosition:e.subtask_position,status:e.status,createdAt:e.created_at,updatedAt:e.updated_at,document:e.document?{id:e.document.id,document_name:e.document.document_name,title:e.document.title,description:e.document.description}:void 0}))}catch(t){throw t instanceof y?t:new y(`Failed to fetch tasks`,v.API_ERROR,{operation:`getTasks`,briefId:e},t)}}},Qe=class{logger=x(`SessionManager`);LEGACY_AUTH_FILE=c.join(p.homedir(),`.taskmaster`,`auth.json`);initializationPromise;constructor(e,t){this.supabaseClient=e,this.contextStore=t,this.initializationPromise=this.initialize()}async initialize(){try{await this.initializeSupabaseSession(),await this.migrateLegacyAuth()}catch(e){this.logger.debug(`Session initialization completed with warnings`,e)}}async waitForInitialization(){await this.initializationPromise}async initializeSupabaseSession(){try{await this.supabaseClient.initialize()}catch{this.logger.debug(`No existing session to restore`)}}async migrateLegacyAuth(){if(s.existsSync(this.LEGACY_AUTH_FILE))try{if(await this.supabaseClient.getSession()){s.unlinkSync(this.LEGACY_AUTH_FILE),this.logger.info(`Migrated to Supabase auth, removed legacy auth.json`);return}this.logger.warn(`Legacy auth.json found but no valid Supabase session.`),this.logger.warn(`Please run: task-master auth login`)}catch(e){this.logger.debug(`Error during legacy auth migration:`,e)}}async hasValidSession(){await this.waitForInitialization();try{return await this.supabaseClient.getSession()!=null}catch{return!1}}async getSession(){return await this.waitForInitialization(),this.supabaseClient.getSession()}getStoredContext(){return this.contextStore.getContext()}async getAccessToken(){return await this.waitForInitialization(),(await this.supabaseClient.getSession())?.access_token||null}async getAuthCredentials(){await this.waitForInitialization();let e=await this.supabaseClient.getSession();if(!e)return null;let t=e.user,n=this.contextStore.getUserContext();return{token:e.access_token,refreshToken:e.refresh_token,userId:t.id,email:t.email,expiresAt:e.expires_at?new Date(e.expires_at*1e3).toISOString():void 0,tokenType:`standard`,savedAt:new Date().toISOString(),selectedContext:n||void 0}}async refreshToken(){await this.waitForInitialization();try{let e=await this.supabaseClient.refreshSession();if(!e)throw new S(`Failed to refresh session`,`REFRESH_FAILED`);this.contextStore.saveContext({userId:e.user.id,email:e.user.email});let t=this.contextStore.getContext();return{token:e.access_token,refreshToken:e.refresh_token,userId:e.user.id,email:e.user.email,expiresAt:e.expires_at?new Date(e.expires_at*1e3).toISOString():void 0,savedAt:new Date().toISOString(),selectedContext:t?.selectedContext}}catch(e){throw e instanceof S?e:new S(`Token refresh failed: ${e.message}`,`REFRESH_FAILED`)}}async authenticateWithCode(e){await this.waitForInitialization();try{this.logger.info(`Authenticating with one-time token...`);let t=await this.supabaseClient.verifyOneTimeCode(e);if(!t||!t.access_token)throw new S(`Failed to obtain access token from token`,`NO_TOKEN`);let n=await this.supabaseClient.getUser();if(!n)throw new S(`Failed to get user information`,`INVALID_RESPONSE`);let r=await this.supabaseClient.checkMFARequired();if(r.required&&r.factorId&&r.factorType)throw new S(`MFA verification required. Please provide your authentication code.`,`MFA_REQUIRED`,void 0,{factorId:r.factorId,factorType:r.factorType});this.contextStore.saveContext({userId:n.id,email:n.email});let i=this.contextStore.getUserContext(),a={token:t.access_token,refreshToken:t.refresh_token,userId:n.id,email:n.email,expiresAt:t.expires_at?new Date(t.expires_at*1e3).toISOString():void 0,tokenType:`standard`,savedAt:new Date().toISOString(),selectedContext:i||void 0};return this.logger.info(`Successfully authenticated with token`),a}catch(e){throw e instanceof S?e:new S(`Token authentication failed: ${e.message}`,`CODE_AUTH_FAILED`)}}async verifyMFA(e,t){await this.waitForInitialization();try{this.logger.info(`Verifying MFA code...`);let n=await this.supabaseClient.verifyMFA(e,t);if(!n||!n.access_token)throw new S(`Failed to obtain access token after MFA verification`,`NO_TOKEN`);let r=await this.supabaseClient.getUser();if(!r)throw new S(`Failed to get user information`,`INVALID_RESPONSE`);this.contextStore.saveContext({userId:r.id,email:r.email});let i=this.contextStore.getUserContext(),a={token:n.access_token,refreshToken:n.refresh_token,userId:r.id,email:r.email,expiresAt:n.expires_at?new Date(n.expires_at*1e3).toISOString():void 0,tokenType:`standard`,savedAt:new Date().toISOString(),selectedContext:i||void 0};return this.logger.info(`Successfully verified MFA and authenticated`),a}catch(e){throw e instanceof S?e:new S(`MFA verification failed: ${e.message}`,`MFA_VERIFICATION_FAILED`)}}async logout(){await this.waitForInitialization();try{await this.supabaseClient.signOut()}catch(e){this.logger.warn(`Failed to sign out from Supabase:`,e)}this.contextStore.clearContext();try{s.existsSync(this.LEGACY_AUTH_FILE)&&(s.unlinkSync(this.LEGACY_AUTH_FILE),this.logger.debug(`Cleared legacy auth.json`))}catch{this.logger.debug(`No legacy credentials to clear`)}}},E=class e{static instance=null;static staticLogger=x(`AuthManager`);contextStore;oauthService;sessionManager;supabaseClient;organizationService;constructor(e){this.contextStore=je.getInstance(),this.supabaseClient=ke.getInstance(),this.sessionManager=new Qe(this.supabaseClient,this.contextStore),this.oauthService=new Xe(this.contextStore,this.supabaseClient,e)}static getInstance(t){return e.instance?t&&e.staticLogger.warn(`getInstance called with config after initialization; config is ignored.`):e.instance=new e(t),e.instance}static resetInstance(){e.instance=null,je.resetInstance(),ke.resetInstance()}async getAccessToken(){return this.sessionManager.getAccessToken()}async getAuthCredentials(){return this.sessionManager.getAuthCredentials()}async authenticateWithOAuth(e={}){return this.oauthService.authenticate(e)}async authenticateWithCode(e){return this.sessionManager.authenticateWithCode(e)}async verifyMFA(e,t){return this.sessionManager.verifyMFA(e,t)}async verifyMFAWithRetry(e,t,n){let r=n?.maxAttempts??3,i=n?.onInvalidCode;if(!Number.isFinite(r)||!Number.isInteger(r)||r<1)throw TypeError(`Invalid maxAttempts value: ${r}. Must be a positive integer.`);for(let n=1;n<=r;n++)try{let r=await t(),i=await this.verifyMFA(e,r);return{success:!0,attemptsUsed:n,credentials:i}}catch(e){if(e instanceof S&&e.code===`INVALID_MFA_CODE`){let e=r-n;if(i&&i(n,e),n>=r)return{success:!1,attemptsUsed:n,errorCode:`INVALID_MFA_CODE`};continue}throw e}return{success:!1,attemptsUsed:r,errorCode:`MFA_VERIFICATION_FAILED`}}getAuthorizationUrl(){return this.oauthService.getAuthorizationUrl()}async refreshToken(){return this.sessionManager.refreshToken()}async logout(){return this.sessionManager.logout()}async hasValidSession(){return this.sessionManager.hasValidSession()}async getSession(){return this.sessionManager.getSession()}getStoredContext(){return this.sessionManager.getStoredContext()}getContext(){return this.contextStore.getUserContext()}async updateContext(e){if(!await this.hasValidSession())throw new S(`Not authenticated`,`NOT_AUTHENTICATED`);this.contextStore.updateUserContext(e)}async clearContext(){if(!await this.hasValidSession())throw new S(`Not authenticated`,`NOT_AUTHENTICATED`);this.contextStore.clearUserContext()}async getOrganizationService(){if(!this.organizationService){if(!await this.sessionManager.getSession())throw new S(`Not authenticated`,`NOT_AUTHENTICATED`);this.organizationService=new Ze(this.supabaseClient.getClient())}return this.organizationService}async getOrganizations(){return(await this.getOrganizationService()).getOrganizations()}async getBriefs(e){return(await this.getOrganizationService()).getBriefs(e)}async getOrganization(e){return(await this.getOrganizationService()).getOrganization(e)}async getBrief(e){return(await this.getOrganizationService()).getBrief(e)}async getTasks(e){return(await this.getOrganizationService()).getTasks(e)}ensureBriefSelected(e){let t=this.getContext();if(!t?.briefId)throw new y(`No brief selected`,v.NO_BRIEF_SELECTED,{operation:e,userMessage:`No brief selected. Please select a brief first using: tm context brief <brief-id> or tm context brief <brief-url>`});return t}},D=class{authManager;constructor(){this.authManager=E.getInstance()}async hasValidSession(){return this.authManager.hasValidSession()}async getSession(){return this.authManager.getSession()}getStoredContext(){return this.authManager.getStoredContext()}async getCredentials(){return this.authManager.getAuthCredentials()}async getAccessToken(){return this.authManager.getAccessToken()}async authenticateWithOAuth(e){return this.authManager.authenticateWithOAuth(e)}async authenticateWithCode(e){return this.authManager.authenticateWithCode(e)}async verifyMFA(e,t){return this.authManager.verifyMFA(e,t)}async verifyMFAWithRetry(e,t,n){return this.authManager.verifyMFAWithRetry(e,t,n)}getAuthorizationUrl(){return this.authManager.getAuthorizationUrl()}async refreshToken(){return this.authManager.refreshToken()}async logout(){return this.authManager.logout()}getContext(){return this.authManager.getContext()}async updateContext(e){return this.authManager.updateContext(e)}async clearContext(){return this.authManager.clearContext()}async getOrganizations(){return this.authManager.getOrganizations()}async getOrganization(e){return this.authManager.getOrganization(e)}async getBriefs(e){return this.authManager.getBriefs(e)}async getBrief(e){return this.authManager.getBrief(e)}async getTasks(e){return this.authManager.getTasks(e)}getStorageDisplayInfo(e){if(e===`api`){let e=this.getContext();if(e?.briefId&&e?.briefName)return{storageType:`api`,briefInfo:{briefId:e.briefId,briefName:e.briefName,orgSlug:e.orgSlug,webAppUrl:this.getWebAppUrl()}}}return{storageType:`file`,filePath:t.join(`.taskmaster`,`tasks`,`tasks.json`)}}getBriefCreationUrl(){let e=this.getContext(),t=this.getWebAppUrl();return!t||!e?.orgSlug?null:`${t}/home/${e.orgSlug}/briefs/create`}async guardCommand(e,t){return _e({hasValidSession:await this.hasValidSession(),briefName:this.getContext()?.briefName,storageType:t,commandName:e})}getApiBaseUrl(){let e=process.env.TM_BASE_DOMAIN||`https://tryhamster.com`;if(e)return e.startsWith(`http://`)||e.startsWith(`https://`)?e:e.includes(`localhost`)||e.includes(`127.0.0.1`)?`http://${e}`:`https://${e}`}getWebAppUrl(){return this.getApiBaseUrl()}},$e=class{constructor(e){this.configManager=e}getConfig(){return this.configManager.getConfig()}getStorageConfig(){return this.configManager.getStorageConfig()}getModelConfig(){return this.configManager.getModelConfig()}getResponseLanguage(){return this.configManager.getResponseLanguage()}getProjectRoot(){return this.configManager.getProjectRoot()}isApiExplicitlyConfigured(){return this.configManager.isApiExplicitlyConfigured()}getActiveTag(){return this.configManager.getActiveTag()}async setActiveTag(e){return this.configManager.setActiveTag(e)}async updateConfig(e){return this.configManager.updateConfig(e)}async setResponseLanguage(e){return this.configManager.setResponseLanguage(e)}async saveConfig(){return this.configManager.saveConfig()}async reset(){return this.configManager.reset()}getConfigSources(){return this.configManager.getConfigSources()}};const O={MODELS:{MAIN:`claude-sonnet-4-20250514`,FALLBACK:`claude-3-7-sonnet-20250219`},TASKS:{DEFAULT_PRIORITY:`medium`,DEFAULT_COMPLEXITY:`moderate`,MAX_SUBTASKS:20,MAX_CONCURRENT:5,TASK_ID_PREFIX:`TASK-`},TAGS:{DEFAULT_TAG:`master`,MAX_TAGS_PER_TASK:10,NAMING_CONVENTION:`kebab-case`},WORKFLOW:{ENABLE_AUTOPILOT:!0,MAX_PHASE_ATTEMPTS:3,BRANCH_PATTERN:`task-{taskId}`,REQUIRE_CLEAN_WORKING_TREE:!0,AUTO_STAGE_CHANGES:!0,INCLUDE_CO_AUTHOR:!0,CO_AUTHOR_NAME:`TaskMaster AI`,CO_AUTHOR_EMAIL:`taskmaster@tryhamster.com`,MIN_TESTS:1,MAX_FAILURES_IN_GREEN:0,COMMIT_MESSAGE_TEMPLATE:`{type}({scope}): {description} (Task {taskId}.{subtaskIndex})`,ALLOWED_COMMIT_TYPES:[`feat`,`fix`,`refactor`,`test`,`docs`,`chore`],DEFAULT_COMMIT_TYPE:`feat`,OPERATION_TIMEOUT:6e4,ENABLE_ACTIVITY_LOGGING:!0,ACTIVITY_LOG_PATH:`.taskmaster/logs/workflow-activity.log`,ENABLE_STATE_BACKUP:!0,MAX_STATE_BACKUPS:5,ABORT_ON_MAX_ATTEMPTS:!1},STORAGE:{TYPE:`auto`,ENCODING:`utf8`,MAX_BACKUPS:5},RETRY:{ATTEMPTS:3,DELAY:1e3,MAX_DELAY:3e4,BACKOFF_MULTIPLIER:2,TIMEOUT:3e4},LOGGING:{LEVEL:`info`,MAX_FILE_SIZE:10,MAX_FILES:5},SECURITY:{MAX_REQUESTS_PER_MINUTE:60,MAX_PROMPT_LENGTH:1e5,ALLOWED_EXTENSIONS:[`.txt`,`.md`,`.json`]},VERSION:`1.0.0`};var et=class{localConfigPath;globalConfigPath;logger=x(`ConfigLoader`);constructor(e){this.localConfigPath=t.join(e,`.taskmaster`,`config.json`),this.globalConfigPath=t.join(process.env.HOME||``,`.taskmaster`,`config.json`)}getDefaultConfig(){return{models:{main:O.MODELS.MAIN,fallback:O.MODELS.FALLBACK},workflow:{enableAutopilot:O.WORKFLOW.ENABLE_AUTOPILOT,maxPhaseAttempts:O.WORKFLOW.MAX_PHASE_ATTEMPTS,branchPattern:O.WORKFLOW.BRANCH_PATTERN,requireCleanWorkingTree:O.WORKFLOW.REQUIRE_CLEAN_WORKING_TREE,autoStageChanges:O.WORKFLOW.AUTO_STAGE_CHANGES,includeCoAuthor:O.WORKFLOW.INCLUDE_CO_AUTHOR,coAuthorName:O.WORKFLOW.CO_AUTHOR_NAME,coAuthorEmail:O.WORKFLOW.CO_AUTHOR_EMAIL,testThresholds:{minTests:O.WORKFLOW.MIN_TESTS,maxFailuresInGreen:O.WORKFLOW.MAX_FAILURES_IN_GREEN},commitMessageTemplate:O.WORKFLOW.COMMIT_MESSAGE_TEMPLATE,allowedCommitTypes:[...O.WORKFLOW.ALLOWED_COMMIT_TYPES],defaultCommitType:O.WORKFLOW.DEFAULT_COMMIT_TYPE,operationTimeout:O.WORKFLOW.OPERATION_TIMEOUT,enableActivityLogging:O.WORKFLOW.ENABLE_ACTIVITY_LOGGING,activityLogPath:O.WORKFLOW.ACTIVITY_LOG_PATH,enableStateBackup:O.WORKFLOW.ENABLE_STATE_BACKUP,maxStateBackups:O.WORKFLOW.MAX_STATE_BACKUPS,abortOnMaxAttempts:O.WORKFLOW.ABORT_ON_MAX_ATTEMPTS},storage:{type:O.STORAGE.TYPE,encoding:O.STORAGE.ENCODING,enableBackup:!1,maxBackups:O.STORAGE.MAX_BACKUPS,enableCompression:!1,atomicOperations:!0},version:O.VERSION}}async loadLocalConfig(){try{let e=await m.readFile(this.localConfigPath,`utf-8`);return JSON.parse(e)}catch(e){if(e.code===`ENOENT`)return this.logger.debug(`No local config.json found, using defaults`),null;throw new y(`Failed to load local configuration`,v.CONFIG_ERROR,{configPath:this.localConfigPath},e)}}async loadGlobalConfig(){return null}async hasLocalConfig(){try{return await m.access(this.localConfigPath),!0}catch{return!1}}async hasGlobalConfig(){try{return await m.access(this.globalConfigPath),!0}catch{return!1}}};const k={DEFAULTS:0,GLOBAL:1,LOCAL:2,ENVIRONMENT:3};var tt=class{configSources=[];addSource(e){this.configSources.push(e)}clearSources(){this.configSources=[]}merge(){let e=[...this.configSources].sort((e,t)=>e.precedence-t.precedence),t={};for(let n of e)t=this.deepMerge(t,n.config);return t}deepMerge(e,t){if(!t)return e;if(!e)return t;let n={...e};for(let e in t)t[e]===null||t[e]===void 0||(typeof t[e]==`object`&&!Array.isArray(t[e])?n[e]=this.deepMerge(n[e]||{},t[e]):n[e]=t[e]);return n}getSources(){return[...this.configSources].sort((e,t)=>t.precedence-e.precedence)}hasSource(e){return this.configSources.some(t=>t.name===e)}removeSource(e){let t=this.configSources.length;return this.configSources=this.configSources.filter(t=>t.name!==e),this.configSources.length<t}},nt=class{localConfigPath;backupDir;logger=x(`ConfigPersistence`);constructor(e){this.localConfigPath=t.join(e,`.taskmaster`,`config.json`),this.backupDir=t.join(e,`.taskmaster`,`backups`)}async saveConfig(e,n={}){let{createBackup:r=!1,atomic:i=!0}=n;try{r&&await this.configExists()&&await this.createBackup();let n=t.dirname(this.localConfigPath);await m.mkdir(n,{recursive:!0});let a=JSON.stringify(e,null,2);if(i){let e=`${this.localConfigPath}.tmp`;await m.writeFile(e,a,`utf-8`),await m.rename(e,this.localConfigPath)}else await m.writeFile(this.localConfigPath,a,`utf-8`)}catch(e){throw new y(`Failed to save configuration`,v.CONFIG_ERROR,{configPath:this.localConfigPath},e)}}async createBackup(){try{await m.mkdir(this.backupDir,{recursive:!0});let e=new Date().toISOString().replace(/[:.]/g,`-`),n=t.join(this.backupDir,`config-${e}.json`),r=await m.readFile(this.localConfigPath,`utf-8`);return await m.writeFile(n,r,`utf-8`),await this.cleanOldBackups(),n}catch(e){throw this.logger.warn(`Failed to create backup:`,e),e}}async cleanOldBackups(e=5){try{let n=(await m.readdir(this.backupDir)).filter(e=>e.startsWith(`config-`)&&e.endsWith(`.json`)).sort().reverse().slice(e);for(let e of n)await m.unlink(t.join(this.backupDir,e))}catch(e){this.logger.warn(`Failed to clean old backups:`,e)}}async configExists(){try{return await m.access(this.localConfigPath),!0}catch{return!1}}async deleteConfig(){try{await m.unlink(this.localConfigPath)}catch(e){if(e.code!==`ENOENT`)throw new y(`Failed to delete configuration`,v.CONFIG_ERROR,{configPath:this.localConfigPath},e)}}async getBackups(){try{return(await m.readdir(this.backupDir)).filter(e=>e.startsWith(`config-`)&&e.endsWith(`.json`)).sort().reverse()}catch{return[]}}async restoreFromBackup(e){let n=t.join(this.backupDir,e);try{let e=await m.readFile(n,`utf-8`);await m.writeFile(this.localConfigPath,e,`utf-8`)}catch(e){throw new y(`Failed to restore from backup`,v.CONFIG_ERROR,{backupPath:n},e)}}},rt=class e{logger=x(`EnvironmentConfigProvider`);static DEFAULT_MAPPINGS=[{env:`TASKMASTER_STORAGE_TYPE`,path:[`storage`,`type`],validate:e=>[`file`,`api`].includes(e)},{env:`TASKMASTER_API_ENDPOINT`,path:[`storage`,`apiEndpoint`]},{env:`TASKMASTER_API_TOKEN`,path:[`storage`,`apiAccessToken`]},{env:`TASKMASTER_MODEL_MAIN`,path:[`models`,`main`]},{env:`TASKMASTER_MODEL_RESEARCH`,path:[`models`,`research`]},{env:`TASKMASTER_MODEL_FALLBACK`,path:[`models`,`fallback`]},{env:`TASKMASTER_RESPONSE_LANGUAGE`,path:[`custom`,`responseLanguage`]}];static RUNTIME_STATE_MAPPINGS=[{env:`TASKMASTER_TAG`,path:[`activeTag`],isRuntimeState:!0}];mappings;constructor(t){this.mappings=t||[...e.DEFAULT_MAPPINGS,...e.RUNTIME_STATE_MAPPINGS]}loadConfig(){let e={};for(let t of this.mappings){if(t.isRuntimeState)continue;let n=process.env[t.env];if(n){if(t.validate&&!t.validate(n)){this.logger.warn(`Invalid value for ${t.env}: ${n}`);continue}this.setNestedProperty(e,t.path,n)}}return e}getRuntimeState(){let e={};for(let t of this.mappings){if(!t.isRuntimeState)continue;let n=process.env[t.env];if(n){let r=t.path[t.path.length-1];e[r]=n}}return e}setNestedProperty(e,t,n){let r=t[t.length-1],i=t.slice(0,-1),a=e;for(let e of i)a[e]||(a[e]={}),a=a[e];a[r]=n}hasEnvVar(e){return e in process.env&&process.env[e]!==void 0}getAllTaskmasterEnvVars(){let e={};for(let[t,n]of Object.entries(process.env))t.startsWith(`TASKMASTER_`)&&n!==void 0&&(e[t]=n);return e}addMapping(e){this.mappings.push(e)}getMappings(){return[...this.mappings]}},it=class{stateFilePath;currentState;logger=x(`RuntimeStateManager`);constructor(e){this.stateFilePath=t.join(e,`.taskmaster`,`state.json`),this.currentState={currentTag:O.TAGS.DEFAULT_TAG}}async loadState(){try{let e=await m.readFile(this.stateFilePath,`utf-8`),t=JSON.parse(e),n={currentTag:t.currentTag||t.activeTag||O.TAGS.DEFAULT_TAG,lastUpdated:t.lastUpdated,metadata:t.metadata};return process.env.TASKMASTER_TAG&&(n.currentTag=process.env.TASKMASTER_TAG),this.currentState=n,n}catch(e){return e.code===`ENOENT`?(this.logger.debug(`No state.json found, using default state`),process.env.TASKMASTER_TAG&&(this.currentState.currentTag=process.env.TASKMASTER_TAG),this.currentState):(this.logger.warn(`Failed to load state file:`,e.message),this.currentState)}}async saveState(){let e=t.dirname(this.stateFilePath);try{await m.mkdir(e,{recursive:!0});let t={...this.currentState,lastUpdated:new Date().toISOString()};await m.writeFile(this.stateFilePath,JSON.stringify(t,null,2),`utf-8`)}catch(e){throw new y(`Failed to save runtime state`,v.CONFIG_ERROR,{statePath:this.stateFilePath},e)}}getCurrentTag(){return this.currentState.currentTag}async setCurrentTag(e){this.currentState.currentTag=e,await this.saveState()}getState(){return{...this.currentState}}async updateMetadata(e){this.currentState.metadata={...this.currentState.metadata,...e},await this.saveState()}async clearState(){try{await m.unlink(this.stateFilePath)}catch(e){if(e.code!==`ENOENT`)throw e}this.currentState={currentTag:O.TAGS.DEFAULT_TAG}}},at=class e{projectRoot;config={};initialized=!1;loader;merger;stateManager;persistence;envProvider;static async create(t){let n=new e(t);return await n.initialize(),n}constructor(e){this.projectRoot=e,this.l