@hhsw2015/task-master-ai 0.43.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +4072 -0
- package/LICENSE +25 -0
- package/README-task-master.md +648 -0
- package/README.md +415 -0
- package/dist/ai-services-unified-BgdcS4fE.js +7 -0
- package/dist/ai-services-unified-DVAKOPK0.js +1 -0
- package/dist/assets/.windsurfrules +524 -0
- package/dist/assets/AGENTS.md +435 -0
- package/dist/assets/GEMINI.md +110 -0
- package/dist/assets/claude/TM_COMMANDS_GUIDE.md +147 -0
- package/dist/assets/config.json +34 -0
- package/dist/assets/env.example +12 -0
- package/dist/assets/example_prd.txt +47 -0
- package/dist/assets/example_prd_rpg.txt +511 -0
- package/dist/assets/gitignore +25 -0
- package/dist/assets/hamster-art.txt +49 -0
- package/dist/assets/kiro-hooks/tm-code-change-task-tracker.kiro.hook +23 -0
- package/dist/assets/kiro-hooks/tm-complexity-analyzer.kiro.hook +16 -0
- package/dist/assets/kiro-hooks/tm-daily-standup-assistant.kiro.hook +13 -0
- package/dist/assets/kiro-hooks/tm-git-commit-task-linker.kiro.hook +13 -0
- package/dist/assets/kiro-hooks/tm-pr-readiness-checker.kiro.hook +13 -0
- package/dist/assets/kiro-hooks/tm-task-dependency-auto-progression.kiro.hook +17 -0
- package/dist/assets/kiro-hooks/tm-test-success-task-completer.kiro.hook +23 -0
- package/dist/assets/roocode/.roo/rules-architect/architect-rules +93 -0
- package/dist/assets/roocode/.roo/rules-ask/ask-rules +89 -0
- package/dist/assets/roocode/.roo/rules-code/code-rules +61 -0
- package/dist/assets/roocode/.roo/rules-debug/debug-rules +68 -0
- package/dist/assets/roocode/.roo/rules-orchestrator/orchestrator-rules +181 -0
- package/dist/assets/roocode/.roo/rules-test/test-rules +61 -0
- package/dist/assets/roocode/.roomodes +63 -0
- package/dist/assets/rules/cursor_rules.mdc +53 -0
- package/dist/assets/rules/dev_workflow.mdc +424 -0
- package/dist/assets/rules/hamster.mdc +173 -0
- package/dist/assets/rules/self_improve.mdc +72 -0
- package/dist/assets/rules/taskmaster.mdc +573 -0
- package/dist/assets/rules/taskmaster_hooks_workflow.mdc +59 -0
- package/dist/assets/scripts_README.md +445 -0
- package/dist/commands-D7m4KWx1.js +329 -0
- package/dist/config-manager-CvbfYtIR.js +1 -0
- package/dist/config-manager-cjltSxIS.js +270 -0
- package/dist/dependency-manager-CyOxi5uo.js +1078 -0
- package/dist/git-utils-DllbRE35.js +1 -0
- package/dist/git-utils-PBP1PRVP.js +1 -0
- package/dist/mcp-server.js +44 -0
- package/dist/profiles-DcD-JxPM.js +3528 -0
- package/dist/research-DN4RyyJY.js +1 -0
- package/dist/response-language-C5AwQSfD.js +1 -0
- package/dist/response-language-LzM2RD6-.js +1 -0
- package/dist/sentry-CBAZ4LSk.js +1 -0
- package/dist/tag-management-6HOtYZMj.js +1 -0
- package/dist/task-manager-BtFURFe0.js +1 -0
- package/dist/task-master.js +2 -0
- package/dist/update-subtask-by-id-DiWMqGfw.js +1 -0
- package/dist/update-task-by-id-eyL-PNVX.js +1 -0
- package/dist/utils-CGk8TL6x.js +1 -0
- package/index.js +160 -0
- package/package.json +183 -0
|
@@ -0,0 +1,270 @@
|
|
|
1
|
+
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,{appendFile as h,mkdir as ee,readFile as te}from"node:fs/promises";import ne from"fs-extra";import{simpleGit as re}from"simple-git";import ie,{constants as ae,existsSync as g,readFileSync as oe,readdirSync as se}from"node:fs";import ce from"proper-lockfile";import{spawn as le,spawnSync as ue}from"node:child_process";import{z as _}from"zod";import{exec as de,execSync as fe}from"child_process";import{promisify as pe}from"util";import me from"node:os";import"node:crypto";import{format as he,formatDistanceToNow as ge}from"date-fns";import{fileURLToPath as _e}from"url";import ve from"dotenv";const ye=600*1e3,be=3,xe=[`add-dependency`,`remove-dependency`,`validate-dependencies`,`fix-dependencies`,`clear-subtasks`,`models`,`generate`];function Se(e){return xe.includes(e)}function Ce(e){let{hasValidSession:t,briefName:n,storageType:r,commandName:i}=e;return!Se(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 we=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 Te=null;const Ee=new Map;function De(e){return new we(e)}function x(e,t){return e?(Ee.has(e)||Ee.set(e,De({prefix:e,...t})),Ee.get(e)):(Te||=De(t),Te)}const Oe=c.join(process.env.HOME||process.env.USERPROFILE||`~`,`.taskmaster`,`session.json`);var ke=class{storage=new Map;persistPath;logger=x(`SupabaseSessionStorage`);writer;initPromise;constructor(e=Oe){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+`
|
|
2
|
+
`),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 Ae={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`},je=[`refresh_token_not_found`,`refresh_token_already_used`];function w(e){return C(e)?je.includes(e.code||``):!1}function Me(e,t){let n=e.code,r=n&&Ae[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 Ne(){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 Pe(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 Fe=class e{static instance=null;client=null;sessionStorage;logger=x(`SupabaseAuthClient`);constructor(){this.sessionStorage=new ke}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||process.env.TM_PUBLIC_SUPABASE_URL,t=process.env.TM_SUPABASE_ANON_KEY||process.env.TM_PUBLIC_SUPABASE_ANON_KEY;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),Me(n,`Failed to refresh session`);return t&&this.logger.info(`Successfully refreshed session`),t}catch(e){throw e instanceof S?e:C(e)?Me(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),Me(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 Me(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 Ie=c.join(process.env.HOME||process.env.USERPROFILE||`~`,`.taskmaster`,`context.json`);var Le=class e{static instance=null;logger=x(`ContextStore`);contextPath;constructor(e=Ie){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}},Re=`@hhsw2015/task-master-ai`,ze=`0.43.0`;const Be=[`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`},Ve=Object.values(T),He=[...new Set([...Be,...Ve])],Ue=`.taskmaster/tasks/tasks.json`,We=[`.taskmaster`,`.taskmaster/config.json`,Ue,`.taskmasterconfig`],Ge=`.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(`,`),Ke=[`tasks/tasks.json`,`tasks.json`,...Ge,`requirements.txt`];[...We,...Ke];const qe=ze||`unknown`,Je=[`pending`,`in-progress`,`done`,`deferred`,`cancelled`,`blocked`,`review`],Ye=[`done`,`completed`,`cancelled`];function Xe(e){return Ye.includes(e)}const Ze=[`text`,`json`,`compact`],Qe={done:`✓`,completed:`✓`,"in-progress":`►`,blocked:`⭕`,pending:`○`,deferred:`⏸`,cancelled:`✗`,review:`👁`};function $e(){return process.env.TM_BASE_DOMAIN||process.env.TM_PUBLIC_BASE_DOMAIN||`https://tryhamster.com`}function et(){return{baseUrl:$e(),configDir:c.join(p.homedir(),`.taskmaster`),configFile:c.join(p.homedir(),`.taskmaster`,`auth.json`)}}function tt(e){return{...et(),...e}}new Proxy({},{get(e,t){return et()[t]}});var nt=class{logger=x(`OAuthService`);contextStore;supabaseClient;configOverrides;authorizationUrl=null;keyPair=null;get baseUrl(){return tt(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=Ne(),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=Pe(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 qe}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}))}},rt=class{logger=x(`OrganizationService`);constructor(e){this.supabaseClient=e}async getOrganizations(){try{let{data:e,error:t}=await this.supabaseClient.from(`user_accounts`).select(`
|
|
3
|
+
id,
|
|
4
|
+
name,
|
|
5
|
+
slug
|
|
6
|
+
`);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(`
|
|
7
|
+
id,
|
|
8
|
+
name,
|
|
9
|
+
slug
|
|
10
|
+
`).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(`
|
|
11
|
+
id,
|
|
12
|
+
account_id,
|
|
13
|
+
document_id,
|
|
14
|
+
status,
|
|
15
|
+
created_at,
|
|
16
|
+
updated_at,
|
|
17
|
+
tasks(count),
|
|
18
|
+
document:document_id (
|
|
19
|
+
id,
|
|
20
|
+
document_name,
|
|
21
|
+
title
|
|
22
|
+
)
|
|
23
|
+
`).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(`
|
|
24
|
+
id,
|
|
25
|
+
account_id,
|
|
26
|
+
document_id,
|
|
27
|
+
status,
|
|
28
|
+
created_at,
|
|
29
|
+
updated_at,
|
|
30
|
+
document:document_id (
|
|
31
|
+
id,
|
|
32
|
+
document_name,
|
|
33
|
+
title,
|
|
34
|
+
description
|
|
35
|
+
)
|
|
36
|
+
`).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(`
|
|
37
|
+
*,
|
|
38
|
+
document:document_id (
|
|
39
|
+
id,
|
|
40
|
+
document_name,
|
|
41
|
+
title,
|
|
42
|
+
description
|
|
43
|
+
)
|
|
44
|
+
`).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)}}},it=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=Le.getInstance(),this.supabaseClient=Fe.getInstance(),this.sessionManager=new it(this.supabaseClient,this.contextStore),this.oauthService=new nt(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,Le.resetInstance(),Fe.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 rt(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 Ce({hasValidSession:await this.hasValidSession(),briefName:this.getContext()?.briefName,storageType:t,commandName:e})}getApiBaseUrl(){let e=process.env.TM_BASE_DOMAIN||process.env.TM_PUBLIC_BASE_DOMAIN;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()}},at=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 ot=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 st=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}},ct=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)}}},lt=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]}},ut=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}}},dt=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.loader=new ot(e),this.merger=new st,this.stateManager=new ut(e),this.persistence=new ct(e),this.envProvider=new lt}async initialize(){if(this.initialized)return;this.merger.clearSources(),this.merger.addSource({name:`defaults`,config:this.loader.getDefaultConfig(),precedence:k.DEFAULTS});let e=await this.loader.loadGlobalConfig();e&&this.merger.addSource({name:`global`,config:e,precedence:k.GLOBAL});let t=await this.loader.loadLocalConfig();t&&this.merger.addSource({name:`local`,config:t,precedence:k.LOCAL});let n=this.envProvider.loadConfig();Object.keys(n).length>0&&this.merger.addSource({name:`environment`,config:n,precedence:k.ENVIRONMENT}),this.config=this.merger.merge(),await this.stateManager.loadState(),this.initialized=!0}getConfig(){return this.config}getStorageConfig(){let e=this.config.storage,t=e?.type||`auto`,n=e?.basePath??this.projectRoot;return t===`api`||t===`auto`?{type:t,basePath:n,apiEndpoint:e?.apiEndpoint,apiAccessToken:e?.apiAccessToken,apiConfigured:!!(e?.apiEndpoint||e?.apiAccessToken)}:{type:t,basePath:n,apiConfigured:!1}}getModelConfig(){return this.config.models||{main:O.MODELS.MAIN,fallback:O.MODELS.FALLBACK}}getResponseLanguage(){return this.config.custom?.responseLanguage||`English`}getProjectRoot(){return this.projectRoot}isApiExplicitlyConfigured(){return this.getStorageConfig().type===`api`}getActiveTag(){return this.stateManager.getCurrentTag()}async setActiveTag(e){await this.stateManager.setCurrentTag(e)}async updateConfig(e){Object.assign(this.config,e),await this.persistence.saveConfig(this.config),this.initialized=!1,await this.initialize()}async setResponseLanguage(e){this.config.custom||(this.config.custom={}),this.config.custom.responseLanguage=e,await this.persistence.saveConfig(this.config)}async saveConfig(){await this.persistence.saveConfig(this.config,{createBackup:!0,atomic:!0})}async reset(){await this.persistence.deleteConfig(),await this.stateManager.clearState(),this.initialized=!1,this.config={},await this.initialize()}getConfigSources(){return this.merger.getSources()}},A=class{projectPath;git;constructor(e){if(!e)throw Error(`Project path is required`);if(!c.isAbsolute(e))throw Error(`Project path must be an absolute path`);this.projectPath=c.normalize(e),this.git=re(this.projectPath)}async isGitRepository(){try{let e=c.join(this.projectPath,`.git`);if(await ne.pathExists(e))return!0;try{return await this.git.revparse([`--git-dir`]),!0}catch{return!1}}catch{return!1}}async validateGitInstallation(){try{await this.git.version()}catch(e){let t=e instanceof Error?e.message:String(e);throw Error(`Git is not installed or not accessible: ${t}`)}}async getGitVersion(){let e=await this.git.version();return{major:e.major,minor:e.minor,patch:typeof e.patch==`string`?parseInt(e.patch):e.patch||0,agent:e.agent}}async getRepositoryRoot(){try{let e=await this.git.revparse([`--show-toplevel`]);return c.normalize(e.trim())}catch{throw Error(`not a git repository: ${this.projectPath}`)}}async validateRepository(){if(!await this.isGitRepository())throw Error(`not a git repository: ${this.projectPath}`);try{await this.git.status()}catch(e){let t=e instanceof Error?e.message:String(e);throw Error(`Repository validation failed: ${t}`)}}async ensureGitRepository(){if(!await this.isGitRepository())throw Error(`not a git repository: ${this.projectPath}\nPlease run this command from within a git repository, or initialize one with 'git init'.`)}async isWorkingTreeClean(){return(await this.git.status()).isClean()}async getStatus(){return await this.git.status()}async hasUncommittedChanges(){return!(await this.git.status()).isClean()}async hasStagedChanges(){return(await this.git.status()).staged.length>0}async hasUntrackedFiles(){return(await this.git.status()).not_added.length>0}async getStatusSummary(){let e=await this.git.status(),t=e.staged.length,n=e.modified.length,r=e.deleted.length,i=e.not_added.length,a=t+n+r+i;return{isClean:e.isClean(),staged:t,modified:n,deleted:r,untracked:i,totalChanges:a}}async ensureCleanWorkingTree(){if(!(await this.git.status()).isClean()){let e=await this.getStatusSummary();throw Error(`working tree is not clean: ${this.projectPath}\nStaged: ${e.staged}, Modified: ${e.modified}, Deleted: ${e.deleted}, Untracked: ${e.untracked}\nPlease commit or stash your changes before proceeding.`)}}async getCurrentBranch(){return(await this.git.status()).current||`HEAD`}async listBranches(){let e=await this.git.branchLocal();return Object.keys(e.branches)}async branchExists(e){return(await this.listBranches()).includes(e)}async createBranch(e,t={}){if(await this.branchExists(e))throw Error(`branch already exists: ${e}`);t.checkout&&await this.ensureCleanWorkingTree(),await this.git.branch([e]),t.checkout&&await this.git.checkout(e)}async checkoutBranch(e,t={}){if(!await this.branchExists(e))throw Error(`branch does not exist: ${e}`);t.force||await this.ensureCleanWorkingTree();let n=t.force?[`-f`,e]:[e];await this.git.checkout(n)}async createAndCheckoutBranch(e){if(await this.ensureCleanWorkingTree(),await this.branchExists(e))throw Error(`branch already exists: ${e}`);await this.git.checkoutLocalBranch(e)}async deleteBranch(e,t={}){if(!await this.branchExists(e))throw Error(`branch does not exist: ${e}`);if(await this.getCurrentBranch()===e)throw Error(`cannot delete current branch: ${e}`);let n=t.force?[`-D`,e]:[`-d`,e];await this.git.branch(n)}async stageFiles(e){await this.git.add(e)}async unstageFiles(e){await this.git.reset([`HEAD`,`--`,...e])}async createCommit(e,t={}){if(t.enforceNonDefaultBranch&&!t.force){let e=await this.getCurrentBranch();if([`main`,`master`,`develop`].includes(e))throw Error(`cannot commit to default branch: ${e}\nPlease create a feature branch or use force option.`)}if(!t.allowEmpty&&!await this.hasStagedChanges())throw Error(`no staged changes to commit`);let n=[`commit`];if(n.push(`-m`,e),t.metadata){n.push(`-m`,``);for(let[e,r]of Object.entries(t.metadata))n.push(`-m`,`[${e}:${r}]`)}n.push(`--no-gpg-sign`),t.allowEmpty&&n.push(`--allow-empty`),await this.git.raw(n)}async getCommitLog(e={}){let t={format:{hash:`%H`,date:`%ai`,message:`%B`,author_name:`%an`,author_email:`%ae`}};return e.maxCount&&(t.maxCount=e.maxCount),[...(await this.git.log(t)).all]}async getLastCommit(){return(await this.git.log({maxCount:1,format:{hash:`%H`,date:`%ai`,message:`%B`,author_name:`%an`,author_email:`%ae`}})).latest}async getDefaultBranch(){let e=await this.getCurrentBranch(),t=[`main`,`master`,`develop`];if(t.includes(e))return e;let n=await this.listBranches();for(let e of t)if(n.includes(e))return e;return`main`}async isDefaultBranch(e){return[`main`,`master`,`develop`].includes(e)}async isOnDefaultBranch(){let e=await this.getCurrentBranch();return await this.isDefaultBranch(e)}async ensureNotOnDefaultBranch(){if(await this.isOnDefaultBranch()){let e=await this.getCurrentBranch();throw Error(`currently on default branch: ${e}\nPlease create a feature branch before proceeding.`)}}async hasRemote(){return(await this.git.getRemotes()).length>0}async getRemotes(){return await this.git.getRemotes(!0)}};const ft=[[`**/*.test.*`,`test`],[`**/*.spec.*`,`test`],[`**/test/**`,`test`],[`**/tests/**`,`test`],[`**/__tests__/**`,`test`],[`**/package-lock.json`,`deps`],[`package-lock.json`,`deps`],[`**/pnpm-lock.yaml`,`deps`],[`pnpm-lock.yaml`,`deps`],[`**/yarn.lock`,`deps`],[`yarn.lock`,`deps`],[`**/package.json`,`config`],[`package.json`,`config`],[`**/tsconfig*.json`,`config`],[`tsconfig*.json`,`config`],[`**/.eslintrc*`,`config`],[`.eslintrc*`,`config`],[`**/vite.config.*`,`config`],[`vite.config.*`,`config`],[`**/vitest.config.*`,`config`],[`vitest.config.*`,`config`],[`packages/cli/**`,`cli`],[`packages/tm-core/**`,`core`],[`packages/mcp-server/**`,`mcp`],[`**/workflow/**`,`workflow`],[`**/git/**`,`git`],[`**/storage/**`,`storage`],[`**/auth/**`,`auth`],[`**/config/**`,`config`],[`**/*.md`,`docs`],[`**/docs/**`,`docs`],[`README*`,`docs`],[`CHANGELOG*`,`docs`]],pt={core:100,cli:90,mcp:85,workflow:80,git:75,storage:70,auth:65,config:60,test:50,docs:30,deps:20,repo:10};var mt=class{scopeMappings;scopePriorities;constructor(e,t){this.scopeMappings=[...ft],e&&(this.scopeMappings=[...Object.entries(e),...this.scopeMappings]),this.scopePriorities={...pt,...t}}detectScope(e){if(e.length===0)return`repo`;let t=new Map;for(let n of e){let e=this.getMatchingScope(n);e&&t.set(e,(t.get(e)||0)+1)}if(t.size===0)return`repo`;let n=`repo`,r=0;for(let[e,i]of t){let t=this.getScopePriority(e)*i;t>r&&(r=t,n=e)}return n}getAllMatchingScopes(e){let t=new Set;for(let n of e){let e=this.getMatchingScope(n);e&&t.add(e)}return Array.from(t)}getMatchingScope(e){let t=e.replace(/\\/g,`/`);for(let[e,n]of this.scopeMappings)if(this.matchesPattern(t,e))return n;return null}getScopePriority(e){return this.scopePriorities[e]||0}matchesPattern(e,t){let n=t.replace(/\*\*/g,`§GLOBSTAR§`);return n=n.replace(/[.+^${}()|[\]\\]/g,`\\$&`),n=n.replace(/\*/g,`[^/]*`),n=n.replace(/§GLOBSTAR§/g,`.*`),RegExp(`^${n}$`).test(e)}};const ht={commitMessage:`{{type}}{{#scope}}({{scope}}){{/scope}}{{#breaking}}!{{/breaking}}: {{description}}
|
|
45
|
+
|
|
46
|
+
{{#body}}{{body}}
|
|
47
|
+
|
|
48
|
+
{{/body}}{{#taskId}}Task: {{taskId}}{{/taskId}}{{#phase}}
|
|
49
|
+
Phase: {{phase}}{{/phase}}{{#testsPassing}}
|
|
50
|
+
Tests: {{testsPassing}} passing{{#testsFailing}}, {{testsFailing}} failing{{/testsFailing}}{{/testsPassing}}`};var gt=class{templates;preservePlaceholders;constructor(e={}){let t=`customTemplates`in e||`preservePlaceholders`in e?e:{customTemplates:e};this.templates={...ht,...t.customTemplates||{}},this.preservePlaceholders=t.preservePlaceholders??!1}render(e,t,n){let r=n===void 0?this.templates[e]:n;if(r===void 0)throw Error(`Template "${e}" not found`);return this.substituteVariables(r,t)}setTemplate(e,t){this.templates[e]=t}getTemplate(e){return this.templates[e]}hasTemplate(e){return e in this.templates}validateTemplate(e,t){let n=this.extractVariables(e),r=t.filter(e=>!n.includes(e));return{isValid:r.length===0,missingVars:r}}extractVariables(e){let t=e.matchAll(/\{\{\s*([^}#/\s]+)\s*\}\}/g),n=new Set;for(let e of t)n.add(e[1]);return Array.from(n)}substituteVariables(e,t){let n=e;return n=this.processConditionalBlocks(n,t),n=n.replace(/\{\{\s*([^}#/\s]+)\s*\}\}/g,(e,n)=>{let r=t[n];return r==null?this.preservePlaceholders?`{{${n}}}`:``:String(r)}),n}processConditionalBlocks(e,t){let n=e,r=!0;for(;r;){let e=n;n=n.replace(/\{\{#([^}]+)\}\}((?:(?!\{\{#).)*?)\{\{\/\1\}\}/gs,(e,n,r)=>{let i=t[n.trim()];return i!=null&&i!==!1&&i!==``?r:``}),r=n!==e}return n}};const _t=[`feat`,`fix`,`docs`,`style`,`refactor`,`perf`,`test`,`build`,`ci`,`chore`,`revert`];var vt=class{templateEngine;scopeDetector;constructor(e,t,n){this.templateEngine=new gt(e),this.scopeDetector=new mt(t,n)}generateMessage(e){let{type:t,description:n,changedFiles:r,scope:i,body:a,breaking:o=!1,taskId:s,phase:c,tag:l,testsPassing:u,testsFailing:d,coveragePercent:f}=e,p={type:t,scope:i??this.scopeDetector.detectScope(r),breaking:o?`!`:``,description:n,body:a,taskId:s,phase:c,tag:l,testsPassing:u,testsFailing:d,coveragePercent:f};return this.templateEngine.render(`commitMessage`,p)}validateConventionalCommit(e){let t=[],n=e.split(`
|
|
51
|
+
`)[0];if(!n)return t.push(`Missing commit message`),{isValid:!1,errors:t};let r=n.match(/^(\w+)(?:\(([^)]+)\))?(!)?:\s*(.+)$/);if(!r)return t.push(`Invalid conventional commit format. Expected: type(scope): description`),{isValid:!1,errors:t};let[,i,,,a]=r;return _t.includes(i)||t.push(`Invalid commit type "${i}". Must be one of: ${_t.join(`, `)}`),(!a||a.trim().length===0)&&t.push(`Missing description`),{isValid:t.length===0,errors:t}}parseCommitMessage(e){let t=e.split(`
|
|
52
|
+
`),n=t[0].match(/^(\w+)(?:\(([^)]+)\))?(!)?:\s*(.+)$/);if(!n)throw Error(`Invalid conventional commit format`);let[,r,i,a,o]=n,s=t.findIndex((e,t)=>t>0&&e===``),c=s===-1?void 0:t.slice(s+1).join(`
|
|
53
|
+
`).trim();return{type:r,scope:i,breaking:a===`!`,description:o,body:c}}getScopeDetector(){return this.scopeDetector}getTemplateEngine(){return this.templateEngine}},yt=class{gitAdapter;commitGenerator;constructor(e){this.gitAdapter=new A(e),this.commitGenerator=new vt}async isGitRepository(){return this.gitAdapter.isGitRepository()}async ensureGitRepository(){return this.gitAdapter.ensureGitRepository()}async getRepositoryRoot(){return this.gitAdapter.getRepositoryRoot()}async isWorkingTreeClean(){return this.gitAdapter.isWorkingTreeClean()}async getStatus(){return this.gitAdapter.getStatus()}async getStatusSummary(){return this.gitAdapter.getStatusSummary()}async hasUncommittedChanges(){return this.gitAdapter.hasUncommittedChanges()}async hasStagedChanges(){return this.gitAdapter.hasStagedChanges()}async getCurrentBranch(){return this.gitAdapter.getCurrentBranch()}async listBranches(){return this.gitAdapter.listBranches()}async branchExists(e){return this.gitAdapter.branchExists(e)}async createBranch(e,t){return this.gitAdapter.createBranch(e,t)}async checkoutBranch(e,t){return this.gitAdapter.checkoutBranch(e,t)}async createAndCheckoutBranch(e){return this.gitAdapter.createAndCheckoutBranch(e)}async deleteBranch(e,t){return this.gitAdapter.deleteBranch(e,t)}async getDefaultBranch(){return this.gitAdapter.getDefaultBranch()}async isOnDefaultBranch(){return this.gitAdapter.isOnDefaultBranch()}async stageFiles(e){return this.gitAdapter.stageFiles(e)}async unstageFiles(e){return this.gitAdapter.unstageFiles(e)}async createCommit(e,t){return this.gitAdapter.createCommit(e,t)}async getCommitLog(e){return this.gitAdapter.getCommitLog(e)}async getLastCommit(){return this.gitAdapter.getLastCommit()}async hasRemote(){return this.gitAdapter.hasRemote()}async getRemotes(){return this.gitAdapter.getRemotes()}generateCommitMessage(e){return this.commitGenerator.generateMessage(e)}validateCommitMessage(e){return this.commitGenerator.validateConventionalCommit(e)}parseCommitMessage(e){return this.commitGenerator.parseCommitMessage(e)}},bt=class{detectFormat(e){return!e||typeof e!=`object`?`standard`:Object.keys(e).some(e=>e!==`tasks`&&e!==`metadata`)?`legacy`:`standard`}extractTasks(e,t){return e?this.detectFormat(e)===`legacy`?this.extractTasksFromLegacy(e,t):this.extractTasksFromStandard(e):[]}extractTasksFromLegacy(e,t){if(t in e)return e[t]?.tasks||[];let n=Object.keys(e).filter(e=>e!==`tasks`&&e!==`metadata`);return t===`master`&&n.length>0&&e[n[0]]?.tasks||[]}extractTasksFromStandard(e){return e?.tasks||[]}extractMetadata(e,t){return e?this.detectFormat(e)===`legacy`?this.extractMetadataFromLegacy(e,t):this.extractMetadataFromStandard(e):null}extractMetadataFromLegacy(e,t){if(t in e){let n=e[t];return!n?.metadata&&n?.tasks?this.generateMetadataFromTasks(n.tasks,t):n?.metadata||null}let n=Object.keys(e).filter(e=>e!==`tasks`&&e!==`metadata`);if(t===`master`&&n.length>0){let t=n[0],r=e[t];return!r?.metadata&&r?.tasks?this.generateMetadataFromTasks(r.tasks,t):r?.metadata||null}return null}extractMetadataFromStandard(e){return e?.metadata||null}extractTags(e){return e?this.detectFormat(e)===`legacy`?Object.keys(e).filter(e=>e!==`tasks`&&e!==`metadata`):[`master`]:[]}convertToSaveFormat(e,t,n,r){let i=r||`master`,a=this.normalizeTasks(e);return n&&this.detectFormat(n)===`legacy`?this.convertToLegacyFormat(a,t,i):this.convertToStandardFormat(a,t,r)}convertToLegacyFormat(e,t,n){return{[n]:{tasks:e,metadata:{...t,tags:[n]}}}}convertToStandardFormat(e,t,n){return{tasks:e,metadata:{...t,tags:n?[n]:[]}}}normalizeTasks(e){return e.map(e=>({...e,id:String(e.id),dependencies:e.dependencies?.map(e=>String(e))||[],subtasks:e.subtasks?.map(e=>({...e,id:Number(e.id),parentId:String(e.parentId)}))||[]}))}generateMetadataFromTasks(e,t){return{version:`1.0.0`,lastModified:new Date().toISOString(),taskCount:e.length,completedCount:e.filter(e=>e.status===`done`).length,tags:[t]}}};const xt={stale:1e4,retries:{retries:5,factor:2,minTimeout:100,maxTimeout:1e3},realpath:!1};var St=class{writers=new Map;getWriter(e){let t=this.writers.get(e);return t||(t=new d(e),this.writers.set(e,t)),t}async readJson(e){try{let t=await m.readFile(e,`utf-8`);return JSON.parse(t)}catch(t){throw t.code===`ENOENT`?t:t instanceof SyntaxError?Error(`Invalid JSON in file ${e}: ${t.message}`):Error(`Failed to read file ${e}: ${t.message}`)}}async writeJson(e,t){await this.ensureFileExists(e);let n=null;try{n=await ce.lock(e,xt);let r=JSON.stringify(t,null,2);await this.getWriter(e).write(r)}finally{if(n)try{await n()}catch(t){(process.env.DEBUG||process.env.TASKMASTER_DEBUG===`true`)&&console.warn(`[WARN] Lock release warning for ${e}: ${t.message}`)}}}async modifyJson(e,t){await this.ensureFileExists(e);let n=null;try{n=await ce.lock(e,xt);let r;try{let t=await m.readFile(e,`utf-8`);r=JSON.parse(t)}catch(t){if(t.code===`ENOENT`)r={};else if(t instanceof SyntaxError){let n=await m.readFile(e,`utf-8`).catch(()=>``);if(n.trim()===``||n.trim()===`{}`)r={};else throw Error(`Corrupted JSON in ${e}: ${t.message}. File contains: ${n.substring(0,100)}...`)}else throw Error(`Failed to read ${e} for modification: ${t.message}`)}let i=await t(r),a=JSON.stringify(i,null,2);await this.getWriter(e).write(a)}finally{if(n)try{await n()}catch(t){(process.env.DEBUG||process.env.TASKMASTER_DEBUG===`true`)&&console.warn(`[WARN] Lock release warning for ${e}: ${t.message}`)}}}async ensureFileExists(e){let n=t.dirname(e);await m.mkdir(n,{recursive:!0});try{await m.writeFile(e,`{}`,{flag:`wx`})}catch(e){if(e.code!==`EEXIST`)throw e}}async exists(e){try{return await m.access(e,ae.F_OK),!0}catch{return!1}}async getStats(e){return m.stat(e)}async readDir(e){return m.readdir(e)}async ensureDir(e){try{await m.mkdir(e,{recursive:!0})}catch(t){throw Error(`Failed to create directory ${e}: ${t.message}`)}}async deleteFile(e){try{await m.unlink(e)}catch(t){if(t.code!==`ENOENT`)throw Error(`Failed to delete file ${e}: ${t.message}`)}}async moveFile(e,t){try{await m.rename(e,t)}catch(n){throw Error(`Failed to move file from ${e} to ${t}: ${n.message}`)}}async copyFile(e,t){try{await m.copyFile(e,t)}catch(n){throw Error(`Failed to copy file from ${e} to ${t}: ${n.message}`)}}async cleanup(){this.writers.clear()}},Ct=class{basePath;tasksDir;tasksFilePath;constructor(e){this.basePath=t.join(e,`.taskmaster`),this.tasksDir=t.join(this.basePath,`tasks`),this.tasksFilePath=t.join(this.tasksDir,`tasks.json`)}getBasePath(){return this.basePath}getTasksDir(){return this.tasksDir}getTasksPath(){return this.tasksFilePath}};const j=x(`ComplexityReportManager`);var wt=class{projectRoot;reportCache=new Map;constructor(e){this.projectRoot=e}getReportPath(e){let t=c.join(this.projectRoot,`.taskmaster`,`reports`),n=e&&e!==`master`?`_${e}`:``;return c.join(t,`task-complexity-report${n}.json`)}async loadReport(e){let t=e||`master`,n=t;if(this.reportCache.has(n))return this.reportCache.get(n);let r=this.getReportPath(e);try{await m.access(r);let e=await m.readFile(r,`utf-8`),i=JSON.parse(e);return!i.meta||!Array.isArray(i.complexityAnalysis)?(j.warn(`Invalid complexity report structure at ${r}, ignoring`),null):(this.reportCache.set(n,i),j.debug(`Loaded complexity report for tag '${t}' with ${i.complexityAnalysis.length} analyses`),i)}catch(e){return e.code===`ENOENT`?(j.debug(`No complexity report found for tag '${t}'`),null):(j.warn(`Failed to load complexity report for tag '${t}': ${e.message}`),null)}}async getComplexityForTask(e,t){let n=await this.loadReport(t);if(!n)return null;let r=n.complexityAnalysis.find(t=>String(t.taskId)===String(e));return r?{complexityScore:r.complexityScore,recommendedSubtasks:r.recommendedSubtasks,expansionPrompt:r.expansionPrompt,complexityReasoning:r.complexityReasoning}:null}async getComplexityForTasks(e,t){let n=new Map,r=await this.loadReport(t);if(!r)return n;let i=new Map;return r.complexityAnalysis.forEach(e=>{i.set(String(e.taskId),e)}),e.forEach(e=>{let t=i.get(String(e));t&&n.set(String(e),{complexityScore:t.complexityScore,recommendedSubtasks:t.recommendedSubtasks,expansionPrompt:t.expansionPrompt,complexityReasoning:t.complexityReasoning})}),n}clearCache(e){e?this.reportCache.delete(e):this.reportCache.clear()}async hasReport(e){let t=this.getReportPath(e);try{return await m.access(t),!0}catch{return!1}}},M=class{formatHandler;fileOps;pathResolver;complexityManager;constructor(e){this.formatHandler=new bt,this.fileOps=new St,this.pathResolver=new Ct(e),this.complexityManager=new wt(e)}async initialize(){await this.fileOps.ensureDir(this.pathResolver.getTasksDir())}async close(){await this.fileOps.cleanup()}getStorageType(){return`file`}getCurrentBriefName(){return null}async getStats(){let e=this.pathResolver.getTasksPath();try{let t=await this.fileOps.getStats(e),n=await this.fileOps.readJson(e),r=this.formatHandler.extractTags(n),i=0,a=r.map(e=>{let r=this.formatHandler.extractTasks(n,e).length;return i+=r,{tag:e,taskCount:r,lastModified:t.mtime.toISOString()}});return{totalTasks:i,totalTags:r.length,lastModified:t.mtime.toISOString(),storageSize:0,tagStats:a}}catch(e){if(e.code===`ENOENT`)return{totalTasks:0,totalTags:0,lastModified:new Date().toISOString(),storageSize:0,tagStats:[]};throw Error(`Failed to get storage stats: ${e.message}`)}}async loadTasks(e,t){let n=this.pathResolver.getTasksPath(),r=e||`master`;try{let e=await this.fileOps.readJson(n),i=this.formatHandler.extractTasks(e,r);return t&&(t.status&&(i=i.filter(e=>e.status===t.status)),t.excludeSubtasks&&(i=i.map(e=>({...e,subtasks:[]})))),await this.enrichTasksWithComplexity(i,r)}catch(e){if(e.code===`ENOENT`)return[];throw Error(`Failed to load tasks: ${e.message}`)}}async loadTask(e,t){let n=await this.loadTasks(t);if(e.includes(`.`)){let[t,r]=e.split(`.`),i=n.find(e=>String(e.id)===t);if(!i||!i.subtasks)return null;let a=i.subtasks.find(e=>String(e.id)===r);if(!a)return null;let o=e=>{let t=String(e);return t.includes(`.`)?t:`${i.id}.${t}`},s=a.dependencies?.map(e=>o(e))??[];return{...a,id:e,title:a.title||`Subtask ${r}`,description:a.description||``,status:a.status||`pending`,priority:a.priority||i.priority||`medium`,dependencies:s,details:a.details||``,testStrategy:a.testStrategy||``,subtasks:[],tags:i.tags||[],assignee:a.assignee||i.assignee,complexity:a.complexity||i.complexity,createdAt:a.createdAt||i.createdAt,updatedAt:a.updatedAt||i.updatedAt,parentTask:{id:i.id,title:i.title,status:i.status},isSubtask:!0}}return n.find(t=>String(t.id)===String(e))||null}async saveTasks(e,t){let n=this.pathResolver.getTasksPath(),r=t||`master`;await this.fileOps.ensureDir(this.pathResolver.getTasksDir());let i={version:`1.0.0`,lastModified:new Date().toISOString(),taskCount:e.length,completedCount:e.filter(e=>e.status===`done`).length,tags:[r]},a=this.normalizeTaskIds(e);await this.fileOps.modifyJson(n,e=>this.formatHandler.detectFormat(e)===`legacy`||Object.keys(e).some(e=>e!==`tasks`&&e!==`metadata`)?(e[r]={tasks:a,metadata:i},e):r===`master`?{tasks:a,metadata:i}:{master:{tasks:e.tasks||[],metadata:e.metadata||i},[r]:{tasks:a,metadata:i}})}normalizeTaskIds(e){return e.map(e=>({...e,id:String(e.id),dependencies:e.dependencies?.map(e=>String(e))||[],subtasks:e.subtasks?.map(e=>({...e,id:Number(e.id),parentId:String(e.parentId)}))||[]}))}async exists(e){let t=this.pathResolver.getTasksPath();return this.fileOps.exists(t)}async getAllTags(){try{let e=this.pathResolver.getTasksPath(),t=await this.fileOps.readJson(e);return this.formatHandler.extractTags(t)}catch(e){if(e.code===`ENOENT`)return[];throw Error(`Failed to get tags: ${e.message}`)}}async loadMetadata(e){let t=this.pathResolver.getTasksPath(),n=e||`master`;try{let e=await this.fileOps.readJson(t);return this.formatHandler.extractMetadata(e,n)}catch(e){if(e.code===`ENOENT`)return null;throw Error(`Failed to load metadata: ${e.message}`)}}async saveMetadata(e,t){let n=await this.loadTasks(t);await this.saveTasks(n,t)}async appendTasks(e,t){let n=[...await this.loadTasks(t),...e];await this.saveTasks(n,t)}async updateTask(e,t,n){let r=await this.loadTasks(n),i=r.findIndex(t=>String(t.id)===String(e));if(i===-1)throw Error(`Task ${e} not found`);let a=r[i],o=t.subtasks;t.subtasks&&a.subtasks&&(o=t.subtasks.map(e=>{let t=a.subtasks?.find(t=>String(t.id)===String(e.id)||e.title&&t.title===e.title);return t?.metadata||e.metadata?{...e,metadata:{...t?.metadata||{},...e.metadata||{}}}:e})),r[i]={...a,...t,...o&&{subtasks:o},id:String(e)},await this.saveTasks(r,n)}async updateTaskWithPrompt(e,t,n,r){throw Error(`File storage does not support updateTaskWithPrompt. Client-side AI logic must process the prompt before calling updateTask().`)}async expandTaskWithPrompt(e,t,n){throw Error(`File storage does not support expandTaskWithPrompt. Client-side AI logic must process the expansion before calling updateTask().`)}async updateTaskStatus(e,t,n){let r=await this.loadTasks(n);if(e.includes(`.`))return this.updateSubtaskStatusInFile(r,e,t,n);let i=r.findIndex(t=>String(t.id)===String(e));if(i===-1)throw Error(`Task ${e} not found`);let a=r[i].status;return a===t?{success:!0,oldStatus:a,newStatus:t,taskId:String(e)}:(r[i]={...r[i],status:t,updatedAt:new Date().toISOString()},await this.saveTasks(r,n),{success:!0,oldStatus:a,newStatus:t,taskId:String(e)})}async updateSubtaskStatusInFile(e,t,n,r){let i=t.split(`.`);if(i.length!==2)throw Error(`Invalid subtask ID format: ${t}. Expected format: parentId.subtaskId`);let[a,o]=i,s=o.trim();if(!/^\d+$/.test(s))throw Error(`Invalid subtask ID: ${s}. Subtask ID must be a positive integer.`);let c=Number(s),l=e.findIndex(e=>String(e.id)===String(a));if(l===-1)throw Error(`Parent task ${a} not found`);let u=e[l],d=u.subtasks.findIndex(e=>e.id===c||String(e.id)===s);if(d===-1)throw Error(`Subtask ${t} not found in parent task ${a}`);let f=u.subtasks[d].status||`pending`;if(f===n)return{success:!0,oldStatus:f,newStatus:n,taskId:t};let p=new Date().toISOString();u.subtasks[d]={...u.subtasks[d],status:n,updatedAt:p};let m=u.subtasks,h=u.status;if(m.length>0){let e=e=>e.status||`pending`,t=t=>{let n=e(t);return n===`done`||n===`completed`},n=m.every(t),r=m.some(t=>e(t)===`in-progress`),i=m.some(t),a=m.every(t=>e(t)===`pending`);n?h=`done`:r||i?h=`in-progress`:a&&(h=`pending`)}return e[l]={...u,...h===u.status?{}:{status:h},updatedAt:p},await this.saveTasks(e,r),{success:!0,oldStatus:f,newStatus:n,taskId:t}}async deleteTask(e,t){let n=await this.loadTasks(t),r=n.filter(t=>String(t.id)!==String(e));if(r.length===n.length)throw Error(`Task ${e} not found`);await this.saveTasks(r,t)}async createTag(e,t){let n=this.pathResolver.getTasksPath();try{await this.fileOps.modifyJson(n,n=>{if(this.formatHandler.detectFormat(n)===`legacy`){if(e in n)throw new y(`Tag ${e} already exists`,v.VALIDATION_ERROR);let r=[];return t?.copyFrom&&t.copyFrom in n&&n[t.copyFrom].tasks&&(r=JSON.parse(JSON.stringify(n[t.copyFrom].tasks))),n[e]={tasks:r,metadata:{created:new Date().toISOString(),updatedAt:new Date().toISOString(),description:t?.description||`Tag created on ${new Date().toLocaleDateString()}`,tags:[e]}},n}else{let r=n.tasks||[],i=n.metadata||{},a=[];return(t?.copyFrom===`master`||!t?.copyFrom)&&(a=JSON.parse(JSON.stringify(r))),{master:{tasks:r,metadata:{...i,tags:[`master`]}},[e]:{tasks:a,metadata:{created:new Date().toISOString(),updatedAt:new Date().toISOString(),description:t?.description||`Tag created on ${new Date().toLocaleDateString()}`,tags:[e]}}}}})}catch(e){throw e.code===`ENOENT`?Error(`Tasks file not found - initialize project first`):e}}async deleteTag(e){let t=this.pathResolver.getTasksPath();try{let n=!1;await this.fileOps.modifyJson(t,t=>{if(this.formatHandler.detectFormat(t)!==`legacy`&&e===`master`)return n=!0,t;if(this.formatHandler.detectFormat(t)===`legacy`){if(e in t)return delete t[e],t;throw Error(`Tag ${e} not found`)}else throw Error(`Tag ${e} not found in standard format`)}),n&&await this.fileOps.deleteFile(t)}catch(t){throw t.code===`ENOENT`?Error(`Tag ${e} not found - file doesn't exist`):t}}async renameTag(e,t){let n=this.pathResolver.getTasksPath();try{await this.fileOps.modifyJson(n,n=>{if(this.formatHandler.detectFormat(n)===`legacy`){if(e in n)return n[t]=n[e],delete n[e],n[t].metadata&&(n[t].metadata.tags=[t]),n;throw Error(`Tag ${e} not found`)}else if(e===`master`){let e=n.tasks||[],r=n.metadata||{};return{[t]:{tasks:e,metadata:{...r,tags:[t]}}}}else throw Error(`Tag ${e} not found in standard format`)})}catch(t){throw t.code===`ENOENT`?Error(`Tag ${e} not found - file doesn't exist`):t}}async copyTag(e,t){let n=await this.loadTasks(e);if(n.length===0)throw Error(`Source tag ${e} not found or has no tasks`);await this.saveTasks(n,t)}async getTagsWithStats(){let e=await this.getAllTags(),t=await this.getActiveTagFromState(),n=await Promise.all(e.map(async e=>{try{let n=await this.loadTasks(e),r={},i=0,a={totalSubtasks:0,subtasksByStatus:{}};n.forEach(e=>{let t=e.status||`pending`;r[t]=(r[t]||0)+1,t===`done`&&i++,e.subtasks&&e.subtasks.length>0&&(a.totalSubtasks+=e.subtasks.length,e.subtasks.forEach(e=>{let t=e.status||`pending`;a.subtasksByStatus[t]=(a.subtasksByStatus[t]||0)+1}))});let o=await this.loadMetadata(e);return{name:e,isCurrent:e===t,taskCount:n.length,completedTasks:i,statusBreakdown:r,subtaskCounts:a.totalSubtasks>0?a:void 0,created:o?.created,description:o?.description}}catch{return{name:e,isCurrent:e===t,taskCount:0,completedTasks:0,statusBreakdown:{}}}}));return{tags:n,currentTag:t,totalTags:n.length}}async getActiveTagFromState(){try{let e=t.join(this.pathResolver.getBasePath(),`state.json`);return(await this.fileOps.readJson(e))?.currentTag||`master`}catch{return`master`}}async watch(e,t){let n=this.pathResolver.getTasksPath(),r=t?.debounceMs??100;if(!await this.fileOps.exists(n))throw new y(`Tasks file not found. Initialize the project first.`,v.NOT_FOUND,{path:n});let i,a=!1,o=ie.watch(n,(t,n)=>{a||n&&t===`change`&&(i&&clearTimeout(i),i=setTimeout(()=>{a||e({type:`change`,timestamp:new Date})},r))});return o.on(`error`,t=>{a||e({type:`error`,timestamp:new Date,error:t})}),{unsubscribe:()=>{a=!0,i&&clearTimeout(i),o.close()}}}async enrichTasksWithComplexity(e,t){let n=e.map(e=>e.id),r=await this.complexityManager.getComplexityForTasks(n,t);return r.size===0?e:e.map(e=>{let t=r.get(String(e.id));return t?{...e,complexity:t.complexityScore,recommendedSubtasks:t.recommendedSubtasks,expansionPrompt:t.expansionPrompt,complexityReasoning:t.complexityReasoning}:e})}},Tt=class{configManager;authManager;constructor(e,t){this.configManager=e,this.authManager=t}async exportTasks(e){if(!await this.authManager.hasValidSession())throw new y(`Authentication required for export`,v.AUTHENTICATION_ERROR);let t=await this.authManager.getContext(),n=e.orgId||t?.orgId,r=e.briefId||t?.briefId;if(!n)throw new y(`Organization ID is required for export. Use "tm context org" to select one.`,v.MISSING_CONFIGURATION);if(!r)throw new y(`Brief ID is required for export. Use "tm context brief" or provide --brief flag.`,v.MISSING_CONFIGURATION);let i=this.configManager.getActiveTag(),a=e.tag||i,o=new M(this.configManager.getProjectRoot());await o.initialize();let s=await o.loadTasks(a,{status:e.status,excludeSubtasks:e.excludeSubtasks}),c={tasks:s,total:(await o.loadTasks(a)).length,filtered:s.length,tag:a,storageType:`file`};if(c.tasks.length===0)return{success:!1,taskCount:0,briefId:r,orgId:n,message:`No tasks found to export`,error:{code:`NO_TASKS`,message:`No tasks match the specified criteria`}};try{return await this.performExport(n,r,c.tasks),{success:!0,taskCount:c.tasks.length,briefId:r,orgId:n,message:`Successfully exported ${c.tasks.length} task(s) to brief`}}catch(e){return{success:!1,taskCount:0,briefId:r,orgId:n,error:{code:`EXPORT_FAILED`,message:e instanceof Error?e.message:String(e)}}}}async exportFromBriefInput(e){let t=this.extractBriefId(e);if(!t)throw new y(`Invalid brief ID or URL provided`,v.VALIDATION_ERROR);let n=await this.authManager.getBrief(t);if(!n)throw new y(`Brief not found or you do not have access`,v.NOT_FOUND);return this.exportTasks({orgId:n.accountId,briefId:n.id})}async validateContext(){let e=await this.authManager.getContext();return{hasOrg:!!e?.orgId,hasBrief:!!e?.briefId,context:e}}transformTasksForBulkImport(e){let t=[],n=new Set;for(let t of e)if(n.add(String(t.id)),t.subtasks)for(let e of t.subtasks)n.add(`${t.id}.${e.id}`);return e.forEach(e=>{let r=(e.dependencies||[]).map(String).filter(e=>n.has(e));t.push({externalId:String(e.id),title:e.title,description:this.enrichDescription(e),status:this.mapStatusForAPI(e.status),priority:e.priority||`medium`,dependencies:r,details:e.details,testStrategy:e.testStrategy,complexity:e.complexity,metadata:{complexity:e.complexity,originalId:e.id,originalDescription:e.description,originalDetails:e.details,originalTestStrategy:e.testStrategy}}),e.subtasks&&e.subtasks.length>0&&e.subtasks.forEach(r=>{let i=(r.dependencies||[]).map(t=>String(t).includes(`.`)?String(t):`${e.id}.${t}`).filter(e=>n.has(e));t.push({externalId:`${e.id}.${r.id}`,parentExternalId:String(e.id),title:r.title,description:this.enrichDescription(r),status:this.mapStatusForAPI(r.status),priority:r.priority||`medium`,dependencies:i,details:r.details,testStrategy:r.testStrategy,complexity:r.complexity,metadata:{complexity:r.complexity,originalId:r.id,originalDescription:r.description,originalDetails:r.details,originalTestStrategy:r.testStrategy}})})}),t}enrichDescription(e){let t=[];return e.description&&t.push(e.description),e.details&&(t.push(`## Implementation Details
|
|
54
|
+
`),t.push(e.details)),e.testStrategy&&(t.push(`## Test Strategy
|
|
55
|
+
`),t.push(e.testStrategy)),t.join(`
|
|
56
|
+
|
|
57
|
+
`).trim()||`No description provided`}mapStatusForAPI(e){switch(e){case`pending`:return`todo`;case`in-progress`:return`in_progress`;case`done`:return`done`;default:return`todo`}}async performExport(e,t,n){let r=new D().getApiBaseUrl();if(r){let i=`${r}/ai/api/v1/briefs/${t}/tasks`,a={source:`task-master-cli`,options:{dryRun:!1,stopOnError:!1},accountId:e,tasks:this.transformTasksForBulkImport(n)},o=await this.authManager.getAccessToken();if(!o)throw Error(`Not authenticated`);let s=await fetch(i,{method:`POST`,headers:{"Content-Type":`application/json`,Authorization:`Bearer ${o}`},body:JSON.stringify(a)});if(!s.ok){let e=await s.text();throw Error(`API request failed: ${s.status} - ${e}`)}let c=await s.json();if(c.failedCount>0){let e=c.results.filter(e=>!e.success).map(e=>`${e.externalId}: ${e.error}`).join(`, `);console.warn(`Warning: ${c.failedCount} tasks failed to import: ${e}`)}console.log(`Successfully exported ${c.successCount} of ${c.totalTasks} tasks to brief ${t}`)}else throw Error(`Export API endpoint not configured. Please set TM_PUBLIC_BASE_DOMAIN environment variable to enable task export.`)}extractBriefId(e){let t=e?.trim()??``;if(!t)return null;let n=e=>{try{return new URL(e)}catch{}try{return new URL(`https://${e}`)}catch{}return null},r=e=>{let t=e.split(`/`).filter(Boolean),n=t.lastIndexOf(`briefs`);return(n>=0&&t.length>n+1?t[n+1]:t[t.length-1])?.trim()||null},i=n(t);if(i){let e=(i.searchParams.get(`id`)||i.searchParams.get(`briefId`)||r(i.pathname))??null;if(e&&(this.isLikelyId(e)||e.length>=8))return e}if(t.includes(`/`)){let e=r(t);if(e&&(this.isLikelyId(e)||e.length>=8))return e}return this.isLikelyId(t)||t.length>=8?t:null}isLikelyId(e){return/^[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}$/.test(e)||/^[0-9A-HJKMNP-TV-Z]{26}$/i.test(e)||/^[A-Za-z0-9_-]{16,}$/.test(e)}async generateBriefFromTasks(e={}){if(!await this.authManager.hasValidSession())throw new y(`Authentication required for export`,v.AUTHENTICATION_ERROR);let t=await this.authManager.getContext(),n=e.orgId||t?.orgId;if(!n){let e=await this.authManager.getOrganizations();if(e.length===0)return{success:!1,error:{code:`NO_ORGANIZATIONS`,message:`No organizations available. Please create an organization in Hamster first.`}};n=e[0].id}let r=this.configManager.getActiveTag(),i=e.tag||r,a=new M(this.configManager.getProjectRoot());await a.initialize();let o=await a.loadTasks(i,{status:e.status,excludeSubtasks:e.excludeSubtasks});if(o.length===0)return{success:!1,error:{code:`NO_TASKS`,message:`No tasks found to export`}};let s=this.transformTasksForImport(o),c=this.getProjectName();return this.callGenerateBriefEndpoint({tasks:s,source:{tool:`task-master`,version:this.getVersion(),tag:i,projectName:c},orgId:n,options:e.options})}transformTasksForImport(e){let t=[],n=new Set;for(let t of e)if(n.add(String(t.id)),t.subtasks)for(let e of t.subtasks)n.add(`${t.id}.${e.id}`);for(let r of e){let e=(r.dependencies||[]).map(String).filter(e=>n.has(e));if(t.push({externalId:String(r.id),title:r.title,description:this.enrichDescription(r),details:r.details,status:this.mapStatusForImport(r.status),priority:this.mapPriorityForImport(r.priority),dependencies:e,metadata:{originalStatus:r.status,originalPriority:r.priority,testStrategy:r.testStrategy,complexity:r.complexity}}),r.subtasks&&r.subtasks.length>0)for(let e of r.subtasks){let i=(e.dependencies||[]).map(e=>String(e).includes(`.`)?String(e):`${r.id}.${e}`).filter(e=>n.has(e));t.push({externalId:`${r.id}.${e.id}`,parentId:String(r.id),title:e.title,description:this.enrichDescription(e),details:e.details,status:this.mapStatusForImport(e.status),priority:this.mapPriorityForImport(e.priority),dependencies:i,metadata:{originalStatus:e.status,originalPriority:e.priority,testStrategy:e.testStrategy,complexity:e.complexity}})}}return t}mapStatusForImport(e){switch(e){case`pending`:return`todo`;case`in-progress`:case`in_progress`:return`in_progress`;case`done`:case`completed`:return`done`;case`blocked`:return`blocked`;default:return`todo`}}mapPriorityForImport(e){switch(e?.toLowerCase()){case`low`:return`low`;case`medium`:return`medium`;case`high`:return`high`;case`critical`:case`urgent`:return`urgent`;default:return`medium`}}getVersion(){try{return process.env.npm_package_version||`1.0.0`}catch{return`1.0.0`}}getProjectName(){try{return this.configManager.getProjectRoot().split(/[/\\]/).pop()||void 0}catch{return}}async callGenerateBriefEndpoint(e){let t=new D().getApiBaseUrl();if(!t)throw new y(`Export API endpoint not configured. Please set TM_PUBLIC_BASE_DOMAIN environment variable.`,v.MISSING_CONFIGURATION,{operation:`generateBriefFromTasks`});let n=`${t}/ai/api/v1/briefs/generate-from-tasks`,r=await this.authManager.getAccessToken();if(!r)throw new y(`Not authenticated`,v.AUTHENTICATION_ERROR);let i=e.orgId;if(!i)return{success:!1,error:{code:`MISSING_ACCOUNT`,message:`No organization selected. Please run "tm auth" and select an organization first.`}};let a={tasks:e.tasks,source:e.source,accountId:i,options:{generateTitle:e.options?.generateTitle??!0,generateDescription:e.options?.generateDescription??!0,preserveHierarchy:e.options?.preserveHierarchy??!0,preserveDependencies:e.options?.preserveDependencies??!0,title:e.options?.title,description:e.options?.description}};try{let e=await fetch(n,{method:`POST`,headers:{"Content-Type":`application/json`,Authorization:`Bearer ${r}`,"x-account-id":i},body:JSON.stringify(a)});if(!(e.headers.get(`content-type`)||``).includes(`application/json`)){let t=await e.text();return{success:!1,error:{code:`API_ERROR`,message:`API returned non-JSON response (${e.status}): ${t.substring(0,100)}...`}}}let t=await e.json(),o=t;if(!e.ok||!o.success){let n=o.error?.message||t?.message||t?.error||`API request failed: ${e.status} - ${e.statusText}`,r=o.error?.code||t?.code||t?.statusCode||`API_ERROR`;return{success:!1,warnings:o.warnings,error:{code:String(r),message:String(n)}}}return{success:!0,brief:o.brief,taskMapping:o.taskMapping,invitations:o.invitations,warnings:o.warnings}}catch(e){return{success:!1,error:{code:`NETWORK_ERROR`,message:`Failed to connect to API: ${e instanceof Error?e.message:String(e)}`}}}}async generateBriefFromPrd(e){if(!e.prdContent||e.prdContent.trim().length===0)return{success:!1,error:{code:`INVALID_INPUT`,message:`PRD content is required`}};if(!await this.authManager.hasValidSession())throw new y(`Authentication required for PRD import`,v.AUTHENTICATION_ERROR);let t=await this.authManager.getContext(),n=e.orgId||t?.orgId;if(!n){let e=await this.authManager.getOrganizations();if(e.length===0)return{success:!1,error:{code:`NO_ORGANIZATIONS`,message:`No organizations available. Please create an organization in Hamster first.`}};n=e[0].id}return this.callGenerateBriefFromPrdEndpoint({prdContent:e.prdContent,orgId:n,options:e.options})}async callGenerateBriefFromPrdEndpoint(e){let t=new D().getApiBaseUrl();if(!t)throw new y(`API endpoint not configured. Please set TM_PUBLIC_BASE_DOMAIN environment variable.`,v.MISSING_CONFIGURATION,{operation:`generateBriefFromPrd`});let n=`${t}/ai/api/v1/briefs/generate-from-prd`,r=await this.authManager.getAccessToken();if(!r)throw new y(`Not authenticated`,v.AUTHENTICATION_ERROR);let i=e.orgId;if(!i)return{success:!1,error:{code:`MISSING_ACCOUNT`,message:`No organization selected. Please run "tm auth" and select an organization first.`}};let a={prdContent:e.prdContent,accountId:i,options:{generateTitle:e.options?.generateTitle??!0,generateDescription:e.options?.generateDescription??!0,title:e.options?.title,description:e.options?.description}};try{let e=await fetch(n,{method:`POST`,headers:{"Content-Type":`application/json`,Authorization:`Bearer ${r}`,"x-account-id":i},body:JSON.stringify(a)});if(!(e.headers.get(`content-type`)||``).includes(`application/json`)){let t=await e.text();return{success:!1,error:{code:`API_ERROR`,message:`API returned non-JSON response (${e.status}): ${t.substring(0,100)}...`}}}let t=await e.json(),o=t;if(!e.ok||!o.success){let n=o.error?.message||t?.message||t?.error||`API request failed: ${e.status} - ${e.statusText}`,r=o.error?.code||t?.code||t?.statusCode||`API_ERROR`;return{success:!1,error:{code:String(r),message:String(n)}}}return{success:!0,brief:o.brief,orgId:i,jobId:o.jobId,invitations:o.invitations}}catch(e){return{success:!1,error:{code:`NETWORK_ERROR`,message:`Failed to connect to API: ${e instanceof Error?e.message:String(e)}`}}}}async getBriefStatus(e){if(!await this.authManager.hasValidSession())return{success:!1,error:{code:`AUTH_REQUIRED`,message:`Authentication required`}};let t=new D().getApiBaseUrl();if(!t)return{success:!1,error:{code:`MISSING_CONFIGURATION`,message:`API endpoint not configured`}};let n=`${t}/ai/api/v1/briefs/${e}/status`,r=await this.authManager.getAccessToken();if(!r)return{success:!1,error:{code:`AUTH_REQUIRED`,message:`Not authenticated`}};let i=(await this.authManager.getContext())?.orgId;if(!i){let e=await this.authManager.getOrganizations();e.length>0&&(i=e[0].id)}if(!i)return{success:!1,error:{code:`MISSING_ACCOUNT`,message:`No organization available`}};try{let e=await fetch(n,{method:`GET`,headers:{Authorization:`Bearer ${r}`,"x-account-id":i}});if(!(e.headers.get(`content-type`)||``).includes(`application/json`))return{success:!1,error:{code:`API_ERROR`,message:`API returned non-JSON response (${e.status})`}};let t=await e.json();return e.ok?{success:!0,status:t}:{success:!1,error:{code:`API_ERROR`,message:t?.message||`Failed to get status: ${e.status}`}}}catch(e){return{success:!1,error:{code:`NETWORK_ERROR`,message:`Failed to get brief status: ${e instanceof Error?e.message:String(e)}`}}}}async sendTeamInvitations(e,t,n=`member`){if(!await this.authManager.hasValidSession())return{success:!1,error:{code:`AUTH_REQUIRED`,message:`Authentication required`}};let r=new D().getApiBaseUrl();if(!r)return{success:!1,error:{code:`MISSING_CONFIGURATION`,message:`API endpoint not configured`}};let i=`${r}/api/teams/${e}/invitations`,a=await this.authManager.getAccessToken();if(!a)return{success:!1,error:{code:`AUTH_REQUIRED`,message:`Not authenticated`}};try{let e=await fetch(i,{method:`POST`,headers:{"Content-Type":`application/json`,Authorization:`Bearer ${a}`},body:JSON.stringify({emails:t.slice(0,10),role:n})});if(!(e.headers.get(`content-type`)||``).includes(`application/json`))return{success:!1,error:{code:`API_ERROR`,message:`API returned non-JSON response (${e.status})`}};let r=await e.json(),o=r.data,s=r.invitations||o?.invitations||o||(Array.isArray(r)?r:null),c=r.error;if(e.ok&&s&&Array.isArray(s))return{success:!0,invitations:s.map(e=>({email:e.email||``,status:e.status||`sent`}))};if(!e.ok||c){let n=typeof c==`object`&&c?c:null;return s&&Array.isArray(s)&&s.length>0&&s.every(e=>e.status===`already_member`)||n?.code===`invitation_failed`&&n?.message?.toLowerCase().includes(`already member`)?{success:!0,invitations:Array.isArray(s)?s:t.map(e=>({email:e,status:`already_member`}))}:{success:!1,error:{code:`API_ERROR`,message:r.message||(typeof c==`string`?c:n?.message||JSON.stringify(c))||`Failed to send invitations: ${e.status}`}}}return{success:!1,error:{code:`INVALID_RESPONSE`,message:`No invitations in response`}}}catch(e){return{success:!1,error:{code:`NETWORK_ERROR`,message:`Failed to send invitations: ${e instanceof Error?e.message:String(e)}`}}}}},Et=class{exportService;constructor(e){this.exportService=new Tt(e,E.getInstance())}async generateBriefFromTasks(e){return this.exportService.generateBriefFromTasks(e)}async exportTasks(e){return this.exportService.exportTasks(e)}async generateBriefFromPrd(e){return this.exportService.generateBriefFromPrd(e)}async getBriefStatus(e){return this.exportService.getBriefStatus(e)}async sendTeamInvitations(e,t,n=`member`){return this.exportService.sendTeamInvitations(e,t,n)}};const N={default:`SETUP: If task-master command not found, run: npm i -g task-master-ai
|
|
58
|
+
|
|
59
|
+
TASK: Implement ONE task/subtask from the Taskmaster backlog.
|
|
60
|
+
|
|
61
|
+
PROCESS:
|
|
62
|
+
1. Run task-master next (or use MCP) to get the next available task/subtask.
|
|
63
|
+
2. Read task details with task-master show <id>.
|
|
64
|
+
3. Implement following codebase patterns.
|
|
65
|
+
4. Write tests alongside implementation.
|
|
66
|
+
5. Run type check (e.g., \`npm run typecheck\`, \`tsc --noEmit\`).
|
|
67
|
+
6. Run tests (e.g., \`npm test\`, \`npm run test\`).
|
|
68
|
+
7. Mark complete: task-master set-status --id=<id> --status=done
|
|
69
|
+
8. Commit with message: feat(<scope>): <what was implemented>
|
|
70
|
+
9. Append super-concise notes to progress file: task ID, what was done, any learnings.
|
|
71
|
+
|
|
72
|
+
IMPORTANT:
|
|
73
|
+
- Complete ONLY ONE task per iteration.
|
|
74
|
+
- Keep changes small and focused.
|
|
75
|
+
- Do NOT start another task after completing one.
|
|
76
|
+
- If all tasks are done, output <loop-complete>ALL_DONE</loop-complete>.
|
|
77
|
+
- If blocked, output <loop-blocked>REASON</loop-blocked>.
|
|
78
|
+
`,"test-coverage":`# Taskmaster Loop - Test Coverage
|
|
79
|
+
|
|
80
|
+
Find uncovered code and write meaningful tests. ONE test per session.
|
|
81
|
+
|
|
82
|
+
## Files Available
|
|
83
|
+
|
|
84
|
+
- @.taskmaster/loop-progress.txt - Progress log (coverage %, what was tested)
|
|
85
|
+
|
|
86
|
+
## What Makes a Great Test
|
|
87
|
+
|
|
88
|
+
A great test covers behavior users depend on. It tests a feature that, if broken,
|
|
89
|
+
would frustrate or block users. It validates real workflows - not implementation details.
|
|
90
|
+
|
|
91
|
+
Do NOT write tests just to increase coverage. Use coverage as a guide to find
|
|
92
|
+
UNTESTED USER-FACING BEHAVIOR. If code is not worth testing (boilerplate, unreachable
|
|
93
|
+
branches, internal plumbing), add ignore comments instead of low-value tests.
|
|
94
|
+
|
|
95
|
+
## Process
|
|
96
|
+
|
|
97
|
+
1. Run coverage command (\`pnpm coverage\`, \`npm run coverage\`, etc.)
|
|
98
|
+
2. Identify the most important USER-FACING FEATURE that lacks tests
|
|
99
|
+
- Prioritize: error handling users hit, CLI commands, API endpoints, file parsing
|
|
100
|
+
- Deprioritize: internal utilities, edge cases users won't encounter, boilerplate
|
|
101
|
+
3. Write ONE meaningful test that validates the feature works correctly
|
|
102
|
+
4. Run coverage again - it should increase as a side effect of testing real behavior
|
|
103
|
+
5. Commit with message: \`test(<file>): <describe the user behavior being tested>\`
|
|
104
|
+
6. Append to progress file: what you tested, new coverage %, learnings
|
|
105
|
+
|
|
106
|
+
## Important
|
|
107
|
+
|
|
108
|
+
- Complete ONLY ONE test per session
|
|
109
|
+
- Keep tests focused on user-facing behavior
|
|
110
|
+
- Do NOT start another test after completing one
|
|
111
|
+
|
|
112
|
+
## Completion Criteria
|
|
113
|
+
|
|
114
|
+
- If coverage reaches target (or 100%), output: <loop-complete>COVERAGE_TARGET</loop-complete>
|
|
115
|
+
`,linting:`# Taskmaster Loop - Linting
|
|
116
|
+
|
|
117
|
+
Fix lint errors and type errors one by one. ONE fix per session.
|
|
118
|
+
|
|
119
|
+
## Files Available
|
|
120
|
+
|
|
121
|
+
- @.taskmaster/loop-progress.txt - Progress log (errors fixed, remaining count)
|
|
122
|
+
|
|
123
|
+
## Process
|
|
124
|
+
|
|
125
|
+
1. Run lint command (\`pnpm lint\`, \`npm run lint\`, \`eslint .\`, etc.)
|
|
126
|
+
2. Run type check (\`pnpm typecheck\`, \`tsc --noEmit\`, etc.)
|
|
127
|
+
3. Pick ONE error to fix - prioritize:
|
|
128
|
+
- Type errors (breaks builds)
|
|
129
|
+
- Security-related lint errors
|
|
130
|
+
- Errors in frequently-changed files
|
|
131
|
+
4. Fix the error with minimal changes - don't refactor surrounding code
|
|
132
|
+
5. Run lint/typecheck again to verify the fix doesn't introduce new errors
|
|
133
|
+
6. Commit with message: \`fix(<file>): <describe the lint/type error fixed>\`
|
|
134
|
+
7. Append to progress file: error fixed, remaining error count
|
|
135
|
+
|
|
136
|
+
## Important
|
|
137
|
+
|
|
138
|
+
- Complete ONLY ONE fix per session
|
|
139
|
+
- Keep changes minimal and focused
|
|
140
|
+
- Do NOT start another fix after completing one
|
|
141
|
+
|
|
142
|
+
## Completion Criteria
|
|
143
|
+
|
|
144
|
+
- If zero lint errors and zero type errors, output: <loop-complete>ZERO_ERRORS</loop-complete>
|
|
145
|
+
`,duplication:`# Taskmaster Loop - Duplication
|
|
146
|
+
|
|
147
|
+
Find duplicated code and refactor into shared utilities. ONE refactor per session.
|
|
148
|
+
|
|
149
|
+
## Files Available
|
|
150
|
+
|
|
151
|
+
- @.taskmaster/loop-progress.txt - Progress log (clones refactored, duplication %)
|
|
152
|
+
|
|
153
|
+
## Process
|
|
154
|
+
|
|
155
|
+
1. Run duplication detection (\`npx jscpd .\`, or similar tool)
|
|
156
|
+
2. Review the report and pick ONE clone to refactor - prioritize:
|
|
157
|
+
- Larger clones (more lines = more maintenance burden)
|
|
158
|
+
- Clones in frequently-changed files
|
|
159
|
+
- Clones with slight variations (consolidate logic)
|
|
160
|
+
3. Extract the duplicated code into a shared utility/function
|
|
161
|
+
4. Update all clone locations to use the shared utility
|
|
162
|
+
5. Run tests to ensure behavior is preserved
|
|
163
|
+
6. Commit with message: \`refactor(<file>): extract <utility> to reduce duplication\`
|
|
164
|
+
7. Append to progress file: what was refactored, new duplication %
|
|
165
|
+
|
|
166
|
+
## Important
|
|
167
|
+
|
|
168
|
+
- Complete ONLY ONE refactor per session
|
|
169
|
+
- Keep changes focused on the specific duplication
|
|
170
|
+
- Do NOT start another refactor after completing one
|
|
171
|
+
|
|
172
|
+
## Completion Criteria
|
|
173
|
+
|
|
174
|
+
- If duplication below threshold (e.g., <3%), output: <loop-complete>LOW_DUPLICATION</loop-complete>
|
|
175
|
+
`,entropy:`# Taskmaster Loop - Entropy (Code Smells)
|
|
176
|
+
|
|
177
|
+
Find code smells and clean them up. ONE cleanup per session.
|
|
178
|
+
|
|
179
|
+
## Files Available
|
|
180
|
+
|
|
181
|
+
- @.taskmaster/loop-progress.txt - Progress log (smells fixed, areas cleaned)
|
|
182
|
+
|
|
183
|
+
## Code Smells to Target
|
|
184
|
+
|
|
185
|
+
- Long functions (>60 lines) - extract into smaller functions
|
|
186
|
+
- Deep nesting (>3 levels) - use early returns, extract conditions
|
|
187
|
+
- Large files (>500 lines) - split into focused modules
|
|
188
|
+
- Magic numbers - extract into named constants
|
|
189
|
+
- Complex conditionals - extract into well-named functions
|
|
190
|
+
- God classes - split responsibilities
|
|
191
|
+
|
|
192
|
+
## Process
|
|
193
|
+
|
|
194
|
+
1. Scan the codebase for code smells (use your judgment or tools like \`complexity-report\`)
|
|
195
|
+
2. Pick ONE smell to fix - prioritize:
|
|
196
|
+
- Smells in frequently-changed files
|
|
197
|
+
- Smells that hurt readability the most
|
|
198
|
+
- Smells in critical paths (authentication, payments, etc.)
|
|
199
|
+
3. Refactor with minimal changes - don't over-engineer
|
|
200
|
+
4. Run tests to ensure behavior is preserved
|
|
201
|
+
5. Commit with message: \`refactor(<file>): <describe the cleanup>\`
|
|
202
|
+
6. Append to progress file: what was cleaned, smell type
|
|
203
|
+
|
|
204
|
+
## Important
|
|
205
|
+
|
|
206
|
+
- Complete ONLY ONE cleanup per session
|
|
207
|
+
- Keep refactoring focused and minimal
|
|
208
|
+
- Do NOT start another cleanup after completing one
|
|
209
|
+
|
|
210
|
+
## Completion Criteria
|
|
211
|
+
|
|
212
|
+
- If no significant smells remain, output: <loop-complete>LOW_ENTROPY</loop-complete>
|
|
213
|
+
`},Dt=Object.keys(N);function Ot(e){return N[e]}function kt(e){return e in N}var At=class{projectRoot;logger=x(`LoopService`);_isRunning=!1;constructor(e){this.projectRoot=e.projectRoot}getProjectRoot(){return this.projectRoot}get isRunning(){return this._isRunning}checkSandboxAuth(e=`claude`){if(e!==`claude`)return{ready:!1,error:`Sandbox auth check is currently only supported for the Claude executor.`};let t=ue(`docker`,[`sandbox`,`run`,`claude`,`-p`,`Say OK`],{cwd:this.projectRoot,timeout:3e4,encoding:`utf-8`,stdio:[`inherit`,`pipe`,`pipe`]});return t.error?t.error.code===`ENOENT`?{ready:!1,error:`Docker is not installed. Install Docker Desktop to use --sandbox mode.`}:{ready:!1,error:`Docker error: ${t.error.message}`}:{ready:((t.stdout||``)+(t.stderr||``)).toLowerCase().includes(`ok`)}}runInteractiveAuth(e=`claude`){if(e!==`claude`)return{success:!1,error:`Interactive sandbox auth is currently only supported for the Claude executor.`};let t=ue(`docker`,[`sandbox`,`run`,`claude`,`You're authenticated! Press Ctrl+C to continue.`],{cwd:this.projectRoot,stdio:`inherit`});return t.error?t.error.code===`ENOENT`?{success:!1,error:`Docker is not installed. Install Docker Desktop to use --sandbox mode.`}:{success:!1,error:`Docker error: ${t.error.message}`}:t.status===null?{success:!1,error:`Docker terminated abnormally (no exit code)`}:t.status===0?{success:!0}:{success:!1,error:`Docker exited with code ${t.status}`}}async run(e){let t=e.executor??`claude`;if(e.verbose&&e.sandbox&&t===`claude`){let t=`Verbose mode is not supported with sandbox mode. Use --verbose without --sandbox, or remove --verbose.`;return this.reportError(e.callbacks,t),{iterations:[],totalIterations:0,tasksCompleted:0,finalStatus:`error`,errorMessage:t}}this._isRunning=!0;let n=[],r=0;await this.initProgressFile(e);for(let i=1;i<=e.iterations&&this._isRunning;i++){e.callbacks?.onIterationStart?.(i,e.iterations);let a=await this.buildPrompt(e,i),o=await this.executeIteration(a,i,t,e.sandbox??!1,e.includeOutput??!1,e.verbose??!1,e.callbacks);if(n.push(o),e.callbacks?.onIterationEnd?.(o),o.status===`complete`)return this.finalize(e,n,r+1,`all_complete`);if(o.status===`blocked`)return this.finalize(e,n,r,`blocked`);o.status===`success`&&r++,i<e.iterations&&e.sleepSeconds>0&&await new Promise(t=>setTimeout(t,e.sleepSeconds*1e3))}return this.finalize(e,n,r,`max_iterations`)}stop(){this._isRunning=!1}async finalize(e,t,n,r){this._isRunning=!1;let i={iterations:t,totalIterations:t.length,tasksCompleted:n,finalStatus:r};return await this.appendFinalSummary(e.progressFile,i),i}reportError(e,t,n=`error`){e?.onError?e.onError(t,n):n===`warning`?this.logger.warn(t):this.logger.error(t)}async initProgressFile(e){await ee(t.dirname(e.progressFile),{recursive:!0});let n=[`# Taskmaster Loop Progress`,`# Started: ${new Date().toISOString()}`,...e.brief?[`# Brief: ${e.brief}`]:[],`# Preset: ${e.prompt}`,`# Max Iterations: ${e.iterations}`,...e.tag?[`# Tag: ${e.tag}`]:[],``,`---`,``];await h(e.progressFile,`
|
|
214
|
+
`+n.join(`
|
|
215
|
+
`)+`
|
|
216
|
+
`,`utf-8`)}async appendFinalSummary(e,t){await h(e,`
|
|
217
|
+
---
|
|
218
|
+
# Loop Complete: ${new Date().toISOString()}
|
|
219
|
+
- Total iterations: ${t.totalIterations}
|
|
220
|
+
- Tasks completed: ${t.tasksCompleted}
|
|
221
|
+
- Final status: ${t.finalStatus}
|
|
222
|
+
`,`utf-8`)}isPreset(e){return kt(e)}async resolvePrompt(e){if(this.isPreset(e))return N[e];let t=await te(e,`utf-8`);if(!t.trim())throw Error(`Custom prompt file '${e}' is empty`);return t}buildContextHeader(e,t){let n=e.tag?` (tag: ${e.tag})`:``,r=e.executor===`codex`?`AGENTS.md`:`CLAUDE.md`;return`@${e.progressFile} @${r}
|
|
223
|
+
|
|
224
|
+
Loop iteration ${t} of ${e.iterations}${n}`}async buildPrompt(e,t){let n=await this.resolvePrompt(e.prompt);return`${this.buildContextHeader(e,t)}\n\n${n}`}parseCompletion(e,t){let n=e.match(/<loop-complete>([^<]*)<\/loop-complete>/i);if(n)return{status:`complete`,message:n[1].trim()};let r=e.match(/<loop-blocked>([^<]*)<\/loop-blocked>/i);return r?{status:`blocked`,message:r[1].trim()}:t===0?{status:`success`}:{status:`error`,message:`Exit code ${t}`}}async executeIteration(e,t,n,r,i=!1,a=!1,o){let s=Date.now(),c=this.getCommand(n,r);if(a)return n===`claude`?this.executeVerboseIteration(e,t,c,r,i,s,o):this.executeGenericVerboseIteration(e,t,c,n,r,i,s,o);let l=ue(c,this.buildCommandArgs(e,n,r,!1),{cwd:this.projectRoot,encoding:`utf-8`,maxBuffer:50*1024*1024,stdio:[`inherit`,`pipe`,`pipe`]});if(l.error){let e=this.formatCommandError(l.error,c,r,n);return this.reportError(o,e),this.createErrorIteration(t,s,e)}let u=(l.stdout||``)+(l.stderr||``);if(u&&o?.onOutput?.(u),l.status===null){let e=`Command terminated abnormally (no exit code)`;return this.reportError(o,e),this.createErrorIteration(t,s,e)}let{status:d,message:f}=this.parseCompletion(u,l.status);return{iteration:t,status:d,duration:Date.now()-s,message:f,...i&&{output:u}}}executeVerboseIteration(e,t,n,r,i,a,o){let s=this.buildCommandArgs(e,`claude`,r,!0);return new Promise(e=>{let c=!1,l=t=>{c||(c=!0,e(t))},u=le(n,s,{cwd:this.projectRoot,stdio:[`inherit`,`pipe`,`pipe`]}),d=!1,f=``,p=``,m=e=>{if(e.startsWith(`{`))try{let t=JSON.parse(e);if(!this.isValidStreamEvent(t))return;this.handleStreamEvent(t,o),t.type===`result`&&(f=typeof t.result==`string`?t.result:``)}catch(t){if(e.trim().startsWith(`{`)){let n=`Failed to parse JSON event: ${t instanceof Error?t.message:`Unknown error`}. Line: ${e.substring(0,100)}...`;this.reportError(o,n,`warning`)}}};if(!u.stdout){l(this.createErrorIteration(t,a,`Failed to capture stdout from child process`));return}u.stdout.on(`data`,e=>{try{let t=this.processBufferedLines(p,e.toString(`utf-8`));p=t.remaining;for(let e of t.complete)m(e)}catch(e){this.reportError(o,`Failed to process stdout data: ${e instanceof Error?e.message:`Unknown error`}`,`warning`)}}),u.stdout.on(`end`,()=>{d=!0,p&&=(m(p),``)}),u.stderr?.on(`data`,e=>{let n=e.toString(`utf-8`);o?.onStderr?.(t,n)}),u.on(`error`,e=>{let i=this.formatCommandError(e,n,r,`claude`);if(this.reportError(o,i),u.stdout?.removeAllListeners(),u.stderr?.removeAllListeners(),!u.killed)try{u.kill(`SIGTERM`)}catch{}l(this.createErrorIteration(t,a,i))}),u.on(`close`,e=>{if(!d&&p&&m(p),e===null){let e=`Command terminated abnormally (no exit code)`;this.reportError(o,e),l(this.createErrorIteration(t,a,e));return}let{status:n,message:r}=this.parseCompletion(f,e);l({iteration:t,status:n,duration:Date.now()-a,message:r,...i&&{output:f}})})})}executeGenericVerboseIteration(e,t,n,r,i,a,o,s){let c=this.buildCommandArgs(e,r,i,!0);return new Promise(e=>{let l=!1,u=``,d=t=>{l||(l=!0,e(t))},f=le(n,c,{cwd:this.projectRoot,stdio:[`inherit`,`pipe`,`pipe`]});f.stdout?.on(`data`,e=>{let t=e.toString(`utf-8`);u+=t,s?.onText?.(t)}),f.stderr?.on(`data`,e=>{let n=e.toString(`utf-8`);u+=n,s?.onStderr?.(t,n)}),f.on(`error`,e=>{let a=this.formatCommandError(e,n,i,r);this.reportError(s,a),d(this.createErrorIteration(t,o,a))}),f.on(`close`,e=>{if(e===null){let e=`Command terminated abnormally (no exit code)`;this.reportError(s,e),d(this.createErrorIteration(t,o,e));return}let{status:n,message:r}=this.parseCompletion(u,e);d({iteration:t,status:n,duration:Date.now()-o,message:r,...a&&{output:u}})})})}isValidStreamEvent(e){if(!e||typeof e!=`object`)return!1;let t=e;if(!(`type`in t)||typeof t.type!=`string`)return!1;if(`message`in t&&t.message!==void 0){if(typeof t.message!=`object`||t.message===null)return!1;let e=t.message;if(`content`in e&&!Array.isArray(e.content))return!1}return!0}getCommand(e,t){return t&&e===`claude`?`docker`:e}buildCommandArgs(e,t,n,r){if(n&&t===`claude`)return[`sandbox`,`run`,`claude`,`-p`,e];if(t===`codex`){let t=[`exec`];return n&&t.push(`--sandbox`,`workspace-write`),t.push(e),t}let i=[`-p`,e,`--dangerously-skip-permissions`];return r&&i.push(`--output-format`,`stream-json`,`--verbose`),i}formatCommandError(e,t,n,r){return e.code===`ENOENT`?n&&r===`claude`?`Docker is not installed. Install Docker Desktop to use --sandbox mode.`:r===`codex`?`Codex CLI is not installed. Install with: npm install -g @openai/codex`:`Claude CLI is not installed. Install with: npm install -g @anthropic-ai/claude-code`:e.code===`EACCES`?`Permission denied executing '${t}'`:`Failed to execute '${t}': ${e.message}`}createErrorIteration(e,t,n){return{iteration:e,status:`error`,duration:Date.now()-t,message:n}}handleStreamEvent(e,t){if(!(e.type!==`assistant`||!e.message?.content))for(let n of e.message.content)n.type===`text`&&n.text?t?.onText?.(n.text):n.type===`tool_use`&&n.name&&t?.onToolUse?.(n.name)}processBufferedLines(e,t){let n=(e+t).split(`
|
|
225
|
+
`);return{complete:n.slice(0,-1),remaining:n[n.length-1]}}},jt=class{logger=x(`LoopDomain`);loopService=null;projectRoot;constructor(e){this.projectRoot=e.getProjectRoot()}checkSandboxAuth(e=`claude`){return new At({projectRoot:this.projectRoot}).checkSandboxAuth(e)}runInteractiveAuth(e=`claude`){return new At({projectRoot:this.projectRoot}).runInteractiveAuth(e)}async run(e){if(this.loopService?.isRunning)try{this.loopService.stop()}catch(e){this.logger.warn(`Failed to stop previous loop service:`,e)}let t=this.buildConfig(e);return this.loopService=new At({projectRoot:this.projectRoot}),this.loopService.run(t)}stop(){this.loopService&&=(this.loopService.stop(),null)}getIsRunning(){return this.loopService?.isRunning??!1}isPreset(e){return kt(e)}async resolvePrompt(e,t){if(kt(e))return Ot(e);if(!t)throw Error(`Custom prompt file requires readFile callback: ${e}`);return t(e)}getAvailablePresets(){return[...Dt]}resolveIterations(e){let{userIterations:t,preset:n,pendingTaskCount:r}=e;return t===void 0?n===`default`&&r!==void 0&&r>0?r:10:t}buildConfig(e){return{iterations:e.iterations??10,prompt:e.prompt??`default`,progressFile:e.progressFile??t.join(this.projectRoot,`.taskmaster`,`progress.txt`),sleepSeconds:e.sleepSeconds??5,tag:e.tag,executor:e.executor??`claude`,sandbox:e.sandbox??!1,includeOutput:e.includeOutput??!1,verbose:e.verbose??!1,brief:e.brief,callbacks:e.callbacks}}},Mt=class{async findBrief(e,t){return e.find(e=>this.matches(e,t))}matches(e,t){let n=e.document?.title||``;return!!(n.toLowerCase()===t.toLowerCase()||n.toLowerCase().includes(t.toLowerCase())||e.id===t||e.id.toLowerCase()===t.toLowerCase()||e.id.slice(-8).toLowerCase()===t.toLowerCase())}async getTagsWithStats(e,t,n,r){let i=await Promise.all(e.map(async e=>{try{let r=await n.getTasks(e.id,{}),i={},a=0,o={totalSubtasks:0,subtasksByStatus:{}};return r.forEach(e=>{let t=e.status||`pending`;i[t]=(i[t]||0)+1,t===`done`&&a++,e.subtasks&&e.subtasks.length>0&&(o.totalSubtasks+=e.subtasks.length,e.subtasks.forEach(e=>{let t=e.status||`pending`;o.subtasksByStatus[t]=(o.subtasksByStatus[t]||0)+1}))}),{name:e.document?.title||e.document?.document_name||e.id,isCurrent:t===e.id,taskCount:r.length,completedTasks:a,statusBreakdown:i,subtaskCounts:o.totalSubtasks>0?o:void 0,created:e.createdAt,description:e.document?.description,status:e.status,briefId:e.id,updatedAt:e.updatedAt}}catch(n){return console.warn(`Failed to get tasks for brief ${e.id}:`,n),{name:e.document?.title||e.document?.document_name||e.id,isCurrent:t===e.id,taskCount:0,completedTasks:0,statusBreakdown:{},created:e.createdAt,description:e.document?.description,status:e.status,briefId:e.id,updatedAt:e.updatedAt}}})),a={delivering:1,aligned:2,refining:3,draft:4,delivered:5,done:6,archived:7},o=i.sort((e,t)=>{let n=(e.status||``).toLowerCase(),r=(t.status||``).toLowerCase(),i=a[n]??999,o=a[r]??999;if(i!==o)return i-o;let s=e.updatedAt?new Date(e.updatedAt).getTime():0;return(t.updatedAt?new Date(t.updatedAt).getTime():0)-s}),s=e.find(e=>e.id===t);return{tags:o,currentTag:s&&(s.document?.title||s.document?.document_name)||null,totalTags:o.length}}validateBriefFound(e,t){if(!e)throw new y(`Brief "${t}" not found in organization`,v.NOT_FOUND)}},Nt=class{static parse(e){let t=e?.trim()??``;if(!t)return{orgSlug:null,briefId:null};let n=this.parseAsUrl(t),r=n?n.pathname:t.includes(`/`)?t:null;return r?this.parsePathComponents(r,n):{orgSlug:null,briefId:t}}static extractOrgSlug(e){return this.parse(e).orgSlug}static extractBriefId(e){return this.parse(e).briefId||e.trim()}static parseAsUrl(e){try{return new URL(e)}catch{}try{return new URL(`https://${e}`)}catch{}return null}static parsePathComponents(e,t){let n=e.split(`/`).filter(Boolean),r=n.lastIndexOf(`briefs`),i=null,a=null;if(r>0&&(i=n[r-1]||null),t){let e=t.searchParams.get(`id`)||t.searchParams.get(`briefId`);e&&(a=e)}return!a&&r>=0&&n.length>r+1&&(a=n[r+1]),!a&&n.length>0&&!(r>=0&&r===n.length-1)&&(a=n[n.length-1]),{orgSlug:i,briefId:a}}static validate(e,t={}){if(t.requireOrg&&!e.orgSlug)throw new y(`Organization slug could not be extracted from input`,v.VALIDATION_ERROR);if(t.requireBrief&&!e.briefId)throw new y(`Brief identifier could not be extracted from input`,v.VALIDATION_ERROR)}},Pt=class{briefService;authManager;constructor(){this.briefService=new Mt,this.authManager=E.getInstance()}async resolveBrief(e,t){let n=Nt.parse(e),r=n.briefId||e.trim(),i=t;if(!i&&n.orgSlug)try{let e=(await this.authManager.getOrganizations()).find(e=>e.slug?.toLowerCase()===n.orgSlug?.toLowerCase()||e.name.toLowerCase()===n.orgSlug?.toLowerCase());e&&(i=e.id)}catch{}if(i||=this.authManager.getContext()?.orgId,!i)throw new y(`No organization selected. Run "tm context org" first.`,v.CONFIG_ERROR);let a=await this.authManager.getBriefs(i),o=await this.briefService.findBrief(a,r);return this.briefService.validateBriefFound(o,r),o}async switchBrief(e){let t=await this.resolveBrief(e);await this.authManager.updateContext({briefId:t.id,briefName:t.document?.title||`Brief ${t.id.slice(-8)}`,briefStatus:t.status,briefUpdatedAt:t.updatedAt})}async getBriefsWithStats(e,t){let n=this.authManager.getContext();if(!n?.orgId)throw new y(`No organization context available`,v.MISSING_CONFIGURATION,{operation:`getBriefsWithStats`,userMessage:`No organization selected. Please authenticate first using: tm auth login`});let r=await this.authManager.getBriefs(n.orgId);return this.briefService.getTagsWithStats(r,n.briefId,e,t)}},Ft=class{repository;projectId;apiClient;authManager;logger=x(`TaskExpansionService`);constructor(e,t,n,r){this.repository=e,this.projectId=t,this.apiClient=n,this.authManager=r}async expandTask(e,t){try{let n=this.authManager.ensureBriefSelected(`expandTask`),r=await this.repository.getTask(this.projectId,e);if(!r)throw new y(`Task ${e} not found`,v.TASK_NOT_FOUND,{operation:`expandTask`,taskId:e,userMessage:`Task ${e} isn't available in the current project.`});let i=await this.repository.getBrief(n.briefId),a={briefContext:{title:i?.name||n.briefName||n.briefId,description:i?.description||void 0,status:i?.status||`active`},allTasks:await this.repository.getTasks(this.projectId),existingSubtasks:r.subtasks||[],enrichedContext:t?.additionalContext},o=new URLSearchParams;if(t?.numSubtasks!==void 0&&o.set(`numSubtasks`,t.numSubtasks.toString()),t?.useResearch!==void 0&&o.set(`useResearch`,t.useResearch.toString()),t?.force!==void 0&&o.set(`force`,t.force.toString()),!r.databaseId)throw new y(`Task ${e} is missing a database ID. Task expansion requires tasks to be synced with the remote database.`,v.VALIDATION_ERROR,{operation:`expandTask`,taskId:e,userMessage:`This task has not been synced with the remote database. Please ensure the task is saved remotely before attempting expansion.`});if(!_.uuid().safeParse(r.databaseId).success)throw new y(`Task ${e} has an invalid database ID format: ${r.databaseId}`,v.VALIDATION_ERROR,{operation:`expandTask`,taskId:e,databaseId:r.databaseId,userMessage:`The task database ID is not in valid UUID format. This may indicate data corruption.`});let s=r.databaseId,c=`/ai/api/v1/tasks/${s}/subtasks/generate${o.toString()?`?${o.toString()}`:``}`,l=await this.apiClient.post(c,a),u=`${process.env.TM_BASE_DOMAIN||process.env.TM_PUBLIC_BASE_DOMAIN||`http://localhost:8080`}/home/hamster/briefs/${n.briefId}/task/${s}`;return this.logger.info(`✓ Task expansion queued for ${e}`),this.logger.info(` Job ID: ${l.jobId}`),this.logger.info(` ${l.message}`),this.logger.info(` View task: ${u}`),{...l,taskLink:u}}catch(n){throw n instanceof y?n.withContext({operation:`expandTask`,taskId:e,numSubtasks:t?.numSubtasks,useResearch:t?.useResearch}):new y(n instanceof Error?n.message:String(n),v.STORAGE_ERROR,{operation:`expandTask`,taskId:e,numSubtasks:t?.numSubtasks,useResearch:t?.useResearch},n)}}},It=class{repository;projectId;apiClient;authManager;logger=x(`TaskRetrievalService`);constructor(e,t,n,r){this.repository=e,this.projectId=t,this.apiClient=n,this.authManager=r}async getTask(e){try{this.authManager.ensureBriefSelected(`getTask`);let t=await this.repository.getTask(this.projectId,e);if(!t)throw new y(`Task ${e} not found`,v.TASK_NOT_FOUND,{operation:`getTask`,taskId:e,userMessage:`Task ${e} isn't available in the current project.`});try{let e=`/ai/api/v1/tasks/${t.id}`,n=await this.apiClient.get(e);n.document?.content&&(t.details=n.document.content)}catch(t){this.logger.debug(`Could not fetch document content for task ${e}: ${t}`)}return this.logger.info(`✓ Retrieved task ${e}`),t.details&&this.logger.debug(` Document content available (${t.details.length} chars)`),t}catch(t){throw t instanceof y?t.withContext({operation:`getTask`,taskId:e}):new y(t instanceof Error?t.message:String(t),v.STORAGE_ERROR,{operation:`getTask`,taskId:e},t)}}},Lt=class{static mapDatabaseTasksToTasks(e,t){if(!e||e.length===0)return[];let n=t instanceof Map?t:this.groupDependenciesByTaskId(t),r=e.filter(e=>!e.parent_task_id),i=this.groupSubtasksByParentId(e);return r.map(e=>this.mapDatabaseTaskToTask(e,i.get(e.id)||[],n))}static mapDatabaseTaskToTask(e,t,n){let r=t.map((t,r)=>{let i=this.extractImplementationMetadata(t.metadata);return{id:t.display_id||String(r+1),parentId:e.id,title:t.title,description:t.description||``,status:this.mapStatus(t.status),priority:this.mapPriority(t.priority),dependencies:n.get(t.id)||[],details:this.extractMetadataField(t.metadata,`details`,``),testStrategy:this.extractMetadataField(t.metadata,`testStrategy`,``),createdAt:t.created_at,updatedAt:t.updated_at,assignee:t.assignee_id||void 0,complexity:t.complexity??void 0,databaseId:t.id,...this.filterUndefined(i)}}),i=this.extractImplementationMetadata(e.metadata);return{id:e.display_id||e.id,databaseId:e.id,title:e.title,description:e.description||``,status:this.mapStatus(e.status),priority:this.mapPriority(e.priority),dependencies:n.get(e.id)||[],details:this.extractMetadataField(e.metadata,`details`,``),testStrategy:this.extractMetadataField(e.metadata,`testStrategy`,``),subtasks:r,createdAt:e.created_at,updatedAt:e.updated_at,assignee:e.assignee_id||void 0,complexity:e.complexity??void 0,effort:e.estimated_hours||void 0,actualEffort:e.actual_hours||void 0,...this.filterUndefined(i)}}static groupDependenciesByTaskId(e){let t=new Map;if(e)for(let n of e){let e=t.get(n.task_id)||[],r=typeof n.depends_on_task==`object`?n.depends_on_task?.display_id:n.depends_on_task_id;r&&e.push(r),t.set(n.task_id,e)}return t}static groupSubtasksByParentId(e){let t=new Map;for(let n of e)if(n.parent_task_id){let e=t.get(n.parent_task_id)||[];e.push(n),t.set(n.parent_task_id,e)}for(let e of t.values())e.sort((e,t)=>e.subtask_position-t.subtask_position);return t}static mapStatus(e){switch(e){case`todo`:return`pending`;case`in_progress`:return`in-progress`;case`done`:return`done`;default:return`pending`}}static mapPriority(e){switch(e){case`urgent`:return`critical`;default:return e}}static extractMetadataField(e,t,n){if(!e||typeof e!=`object`)return n;let r=e[t];if(r===void 0)return n;let i=typeof n,a=typeof r;return i===a?r:(console.warn(`Type mismatch in metadata field "${t}": expected ${i}, got ${a}. Using default value.`),n)}static extractOptionalString(e,t){if(!e||typeof e!=`object`)return;let n=e[t];return typeof n==`string`?n:void 0}static extractStringArray(e,t){if(!e||typeof e!=`object`)return;let n=e[t];if(!Array.isArray(n))return;let r=n.filter(e=>typeof e==`string`);return r.length>0?r:void 0}static extractRelevantFiles(e){if(!e||typeof e!=`object`)return;let t=e.relevantFiles;if(!Array.isArray(t))return;let n=t.filter(e=>{if(!e||typeof e!=`object`)return!1;let t=e;return typeof t.path==`string`&&typeof t.description==`string`&&(t.action===`create`||t.action===`modify`||t.action===`reference`)});return n.length>0?n:void 0}static extractExistingInfrastructure(e){if(!e||typeof e!=`object`)return;let t=e.existingInfrastructure;if(!Array.isArray(t))return;let n=t.filter(e=>{if(!e||typeof e!=`object`)return!1;let t=e;return typeof t.name==`string`&&typeof t.location==`string`&&typeof t.usage==`string`});return n.length>0?n:void 0}static extractScopeBoundaries(e){if(!e||typeof e!=`object`)return;let t=e.scopeBoundaries;if(!t||typeof t!=`object`)return;let n=t,r={};return typeof n.included==`string`&&(r.included=n.included),typeof n.excluded==`string`&&(r.excluded=n.excluded),r.included||r.excluded?r:void 0}static extractCategory(e){if(!e||typeof e!=`object`)return;let t=e.category;return[`research`,`design`,`development`,`testing`,`documentation`,`review`].includes(t)?t:void 0}static extractImplementationMetadata(e){return{relevantFiles:this.extractRelevantFiles(e),codebasePatterns:this.extractStringArray(e,`codebasePatterns`),existingInfrastructure:this.extractExistingInfrastructure(e),scopeBoundaries:this.extractScopeBoundaries(e),implementationApproach:this.extractOptionalString(e,`implementationApproach`),technicalConstraints:this.extractStringArray(e,`technicalConstraints`),acceptanceCriteria:this.extractStringArray(e,`acceptanceCriteria`),skills:this.extractStringArray(e,`skills`),category:this.extractCategory(e)}}static filterUndefined(e){return Object.fromEntries(Object.entries(e).filter(([e,t])=>t!==void 0))}},Rt=class{constructor(e){this.supabase=e}async fetchDependenciesWithDisplayIds(e){if(!e||e.length===0)return new Map;let{data:t,error:n}=await this.supabase.from(`task_dependencies`).select(`
|
|
226
|
+
task_id,
|
|
227
|
+
depends_on_task:tasks!task_dependencies_depends_on_task_id_fkey (
|
|
228
|
+
display_id
|
|
229
|
+
)
|
|
230
|
+
`).in(`task_id`,e);if(n)throw Error(`Failed to fetch task dependencies: ${n.message}`);return this.processDependencyData(t)}processDependencyData(e){let t=new Map;if(!e)return t;for(let n of e){if(!n.task_id)continue;let e=t.get(n.task_id)||[],r=n.depends_on_task?.display_id;r&&e.push(r),t.set(n.task_id,e)}return t}};const zt=_.enum([`pending`,`in-progress`,`done`,`review`,`deferred`,`cancelled`,`blocked`]),Bt=_.object({title:_.string().min(1).optional(),description:_.string().optional(),status:zt.optional(),priority:_.enum([`low`,`medium`,`high`,`critical`]).optional(),details:_.string().optional(),testStrategy:_.string().optional()}).partial();var Vt=class{dependencyFetcher;authManager;constructor(e){this.supabase=e,this.dependencyFetcher=new Rt(e),this.authManager=E.getInstance()}getBriefIdOrThrow(){let e=this.authManager.getContext();if(!e?.briefId)throw Error(`No brief selected. Please select a brief first using: tm context brief`);return e.briefId}async getTasks(e,t){let n=this.getBriefIdOrThrow(),r=this.supabase.from(`tasks`).select(`
|
|
231
|
+
*,
|
|
232
|
+
document:document_id (
|
|
233
|
+
id,
|
|
234
|
+
document_name,
|
|
235
|
+
title,
|
|
236
|
+
description
|
|
237
|
+
)
|
|
238
|
+
`).eq(`brief_id`,n);if(t?.status){let e=this.mapStatusToDatabase(t.status);r=r.eq(`status`,e)}t?.excludeSubtasks&&(r=r.is(`parent_task_id`,null));let{data:i,error:a}=await r.order(`position`,{ascending:!0}).order(`subtask_position`,{ascending:!0}).order(`created_at`,{ascending:!0});if(a)throw Error(`Failed to fetch tasks: ${a.message}`);if(!i||i.length===0)return[];let o=i.map(e=>e.id),s=await this.dependencyFetcher.fetchDependenciesWithDisplayIds(o);return Lt.mapDatabaseTasksToTasks(i,s)}async getTask(e,t){let n=this.getBriefIdOrThrow(),{data:r,error:i}=await this.supabase.from(`tasks`).select(`*`).eq(`brief_id`,n).eq(`display_id`,t.toUpperCase()).single();if(i){if(i.code===`PGRST116`)return null;throw Error(`Failed to fetch task: ${i.message}`)}let{data:a}=await this.supabase.from(`tasks`).select(`*`).eq(`parent_task_id`,r.id).order(`subtask_position`,{ascending:!0}),o=[r.id,...a?.map(e=>e.id)||[]],s=await this.dependencyFetcher.fetchDependenciesWithDisplayIds(o);return Lt.mapDatabaseTaskToTask(r,a||[],s)}async getBrief(e){let{data:t,error:n}=await this.supabase.from(`brief`).select(`
|
|
239
|
+
*,
|
|
240
|
+
document:document_id (
|
|
241
|
+
id,
|
|
242
|
+
title,
|
|
243
|
+
description
|
|
244
|
+
)
|
|
245
|
+
`).eq(`id`,e).single();if(n){if(n.code===`PGRST116`)return null;throw Error(`Failed to fetch brief: ${n.message}`)}if(!t)return null;let r=t.document;return{id:t.id,accountId:t.account_id,createdAt:t.created_at,name:r?.title||void 0,description:r?.description||void 0,status:t.status||void 0}}async updateTask(e,t,n){let r=this.getBriefIdOrThrow();try{Bt.parse(n)}catch(e){if(e instanceof _.ZodError){let t=e.issues.map(e=>`${e.path.join(`.`)}: ${e.message}`).join(`, `);throw Error(`Invalid task update data: ${t}`)}throw e}let i={};n.title!==void 0&&(i.title=n.title),n.description!==void 0&&(i.description=n.description),n.status!==void 0&&(i.status=this.mapStatusToDatabase(n.status)),n.priority!==void 0&&(i.priority=this.mapPriorityToDatabase(n.priority));let{data:a,error:o}=await this.supabase.from(`tasks`).select(`metadata`).eq(`brief_id`,r).eq(`display_id`,t.toUpperCase()).single();if(o)throw Error(`Failed to load existing task metadata: ${o.message}`);let s={...a?.metadata??{}};n.details!==void 0&&(s.details=n.details),n.testStrategy!==void 0&&(s.testStrategy=n.testStrategy),Object.keys(s).length>0&&(i.metadata=s);let{error:c}=await this.supabase.from(`tasks`).update(i).eq(`brief_id`,r).eq(`display_id`,t.toUpperCase());if(c)throw Error(`Failed to update task: ${c.message}`);let l=await this.getTask(e,t);if(!l)throw Error(`Failed to retrieve updated task ${t}`);return l}mapStatusToDatabase(e){switch(e){case`pending`:return`todo`;case`in-progress`:case`in_progress`:return`in_progress`;case`done`:return`done`;default:throw Error(`Invalid task status: ${e}. Valid statuses are: pending, in-progress, done`)}}mapPriorityToDatabase(e){switch(e){case`critical`:return`urgent`;case`low`:case`medium`:case`high`:return e;default:throw Error(`Invalid task priority: ${e}. Valid priorities are: low, medium, high, critical`)}}},Ht=class{constructor(e){this.options=e}async request(e,t={}){let{baseUrl:n,authManager:r,accountId:i}=this.options,a=await r.supabaseClient.getSession();if(!a)throw new y(`Not authenticated`,v.AUTHENTICATION_ERROR,{operation:`api-request`,endpoint:e});let o=`${n}${e}`,s={"Content-Type":`application/json`,Authorization:`Bearer ${a.access_token}`,...i?{"x-account-id":i}:{},...t.headers};try{let n=await fetch(o,{...t,headers:s});return n.ok||await this.handleErrorResponse(n,e),await n.json()}catch(t){throw t instanceof y?t:new y(t instanceof Error?t.message:String(t),v.API_ERROR,{operation:`api-request`,endpoint:e},t)}}async handleErrorResponse(e,t){let n;try{let t=await e.json();n=t.message||t.error||`Unknown API error`}catch{n=await e.text()||e.statusText}throw new y(n,v.API_ERROR,{operation:`api-request`,endpoint:t,statusCode:e.status})}async get(e){return this.request(e,{method:`GET`})}async post(e,t){return this.request(e,{method:`POST`,body:t?JSON.stringify(t):void 0})}async patch(e,t){return this.request(e,{method:`PATCH`,body:t?JSON.stringify(t):void 0})}async put(e,t){return this.request(e,{method:`PUT`,body:t?JSON.stringify(t):void 0})}async delete(e){return this.request(e,{method:`DELETE`})}},Ut=class{repository;projectId;enableRetry;maxRetries;initialized=!1;tagsCache=new Map;apiClient;expansionService;retrievalService;logger=x(`ApiStorage`);constructor(e){if(this.validateConfig(e),e.repository)this.repository=e.repository;else if(e.supabaseClient)this.repository=new Vt(e.supabaseClient);else throw new y(`Either repository or supabaseClient must be provided`,v.MISSING_CONFIGURATION);this.projectId=e.projectId,this.enableRetry=e.enableRetry??!0,this.maxRetries=e.maxRetries??3}validateConfig(e){if(!e.projectId)throw new y(`Project ID is required for API storage`,v.MISSING_CONFIGURATION);if(!e.repository&&!e.supabaseClient)throw new y(`Either repository or supabaseClient must be provided`,v.MISSING_CONFIGURATION)}async initialize(){if(!this.initialized)try{await this.loadTagsIntoCache(),this.initialized=!0}catch(e){throw new y(`Failed to initialize API storage`,v.STORAGE_ERROR,{operation:`initialize`},e)}}getStorageType(){return`api`}getCurrentBriefName(){return E.getInstance().getContext()?.briefName||null}async getTagsWithStats(){await this.ensureInitialized();try{return await new Pt().getBriefsWithStats(this.repository,this.projectId)}catch(e){throw new y(`Failed to get tags with stats from API`,v.STORAGE_ERROR,{operation:`getTagsWithStats`},e)}}async loadTagsIntoCache(){try{let e=E.getInstance().getContext();if(e?.briefId){let t={name:e.briefId,tasks:[],metadata:{briefId:e.briefId,briefName:e.briefName,organizationId:e.orgId}};this.tagsCache.clear(),this.tagsCache.set(e.briefId,t)}}catch{console.debug(`No brief selected, starting with empty cache`)}}async loadTasks(e,t){await this.ensureInitialized();try{let e=E.getInstance().ensureBriefSelected(`loadTasks`),n=await this.retryOperation(()=>this.repository.getTasks(this.projectId,t)),r=this.tagsCache.get(e.briefId);return r&&(r.tasks=n.map(e=>e.id)),n}catch(t){this.wrapError(t,`Failed to load tasks from API`,{operation:`loadTasks`,tag:e,context:`brief-based loading`})}}async saveTasks(e,t){await this.ensureInitialized();try{if(t){let n=this.tagsCache.get(t)||{name:t,tasks:[],metadata:{}};n.tasks=e.map(e=>e.id),this.tagsCache.has(t)?await this.repository.updateTag(this.projectId,t,n):await this.repository.createTag(this.projectId,n),this.tagsCache.set(t,n)}await this.retryOperation(()=>this.repository.bulkCreateTasks(this.projectId,e))}catch(n){throw new y(`Failed to save tasks to API`,v.STORAGE_ERROR,{operation:`saveTasks`,tag:t,taskCount:e.length},n)}}async loadTask(e,t){await this.ensureInitialized();try{let t=this.getRetrievalService();return await this.retryOperation(()=>t.getTask(e))}catch(n){this.wrapError(n,`Failed to load task from API`,{operation:`loadTask`,taskId:e,tag:t})}}async saveTask(e,t){await this.ensureInitialized();try{if(await this.repository.getTask(this.projectId,e.id)?await this.retryOperation(()=>this.repository.updateTask(this.projectId,e.id,e)):await this.retryOperation(()=>this.repository.createTask(this.projectId,e)),t){let n=this.tagsCache.get(t);n&&!n.tasks.includes(e.id)&&(n.tasks.push(e.id),await this.repository.updateTag(this.projectId,t,n))}}catch(n){throw new y(`Failed to save task to API`,v.STORAGE_ERROR,{operation:`saveTask`,taskId:e.id,tag:t},n)}}async deleteTask(e,t){await this.ensureInitialized();try{if(await this.retryOperation(()=>this.repository.deleteTask(this.projectId,e)),t){let n=this.tagsCache.get(t);n&&(n.tasks=n.tasks.filter(t=>t!==e),await this.repository.updateTag(this.projectId,t,n))}}catch(n){throw new y(`Failed to delete task from API`,v.STORAGE_ERROR,{operation:`deleteTask`,taskId:e,tag:t},n)}}async listTags(){await this.ensureInitialized();try{let e=E.getInstance().getContext();return e?.briefId?(await this.loadTagsIntoCache(),[e.briefId]):[]}catch(e){throw new y(`Failed to list tags from API`,v.STORAGE_ERROR,{operation:`listTags`},e)}}async loadMetadata(e){await this.ensureInitialized();try{return e?this.tagsCache.get(e)?.metadata||null:(await this.repository.getTag(this.projectId,`_system`))?.metadata||null}catch(t){throw new y(`Failed to load metadata from API`,v.STORAGE_ERROR,{operation:`loadMetadata`,tag:e},t)}}async saveMetadata(e,t){await this.ensureInitialized();try{if(t){let n=this.tagsCache.get(t)||{name:t,tasks:[],metadata:{}};n.metadata=e,this.tagsCache.has(t)?await this.repository.updateTag(this.projectId,t,n):await this.repository.createTag(this.projectId,n),this.tagsCache.set(t,n)}else{let t={name:`_system`,tasks:[],metadata:e};await this.repository.getTag(this.projectId,`_system`)?await this.repository.updateTag(this.projectId,`_system`,t):await this.repository.createTag(this.projectId,t)}}catch(e){throw new y(`Failed to save metadata to API`,v.STORAGE_ERROR,{operation:`saveMetadata`,tag:t},e)}}async exists(){try{return await this.initialize(),!0}catch{return!1}}async appendTasks(e,t){await this.ensureInitialized();try{if(await this.retryOperation(()=>this.repository.bulkCreateTasks(this.projectId,e)),t){let n=this.tagsCache.get(t)||{name:t,tasks:[],metadata:{}},r=e.map(e=>e.id);n.tasks=[...new Set([...n.tasks,...r])],this.tagsCache.has(t)?await this.repository.updateTag(this.projectId,t,n):await this.repository.createTag(this.projectId,n),this.tagsCache.set(t,n)}}catch(n){throw new y(`Failed to append tasks to API`,v.STORAGE_ERROR,{operation:`appendTasks`,tag:t,taskCount:e.length},n)}}async updateTask(e,t,n){await this.ensureInitialized();try{await this.retryOperation(()=>this.repository.updateTask(this.projectId,e,t))}catch(t){throw new y(`Failed to update task via API`,v.STORAGE_ERROR,{operation:`updateTask`,taskId:e,tag:n},t)}}async updateTaskWithPrompt(e,t,n,r){await this.ensureInitialized();let i=r?.mode??`append`;try{let n=await this.getApiClient().patch(`/ai/api/v1/tasks/${e}/prompt`,{prompt:t,mode:i});if(!n.success)throw Error(n.message||`Update failed for task ${e}. The server did not provide details.`);this.logger.info(`Successfully updated task ${n.task.displayId||n.task.id} using AI prompt (mode: ${i})`),this.logger.info(` Title: ${n.task.title}`),this.logger.info(` Status: ${n.task.status}`),n.message&&this.logger.info(` ${n.message}`)}catch(r){throw r instanceof y?r.withContext({operation:`updateTaskWithPrompt`,taskId:e,tag:n,promptLength:t.length,mode:i}):new y(r instanceof Error?r.message:String(r),v.STORAGE_ERROR,{operation:`updateTaskWithPrompt`,taskId:e,tag:n,promptLength:t.length,mode:i},r)}}async expandTaskWithPrompt(e,t,n){return await this.ensureInitialized(),await this.getExpansionService().expandTask(e,n)}async updateTaskStatus(e,t,n){await this.ensureInitialized();try{E.getInstance().ensureBriefSelected(`updateTaskStatus`);let n=await this.retryOperation(()=>this.repository.getTask(this.projectId,e));if(!n)throw Error(`Task ${e} not found`);let r=n.status;return r===t||await this.retryOperation(()=>this.repository.updateTask(this.projectId,e,{status:t,updatedAt:new Date().toISOString()})),{success:!0,oldStatus:r,newStatus:t,taskId:e}}catch(r){this.wrapError(r,`Failed to update task status via API`,{operation:`updateTaskStatus`,taskId:e,newStatus:t,tag:n})}}async getAllTags(){return this.listTags()}async createTag(e,t){throw new y(`Tag creation is not supported with API storage. Please create briefs through Hamster Studio.`,v.NOT_IMPLEMENTED,{storageType:`api`,operation:`createTag`,tagName:e})}async deleteTag(e){await this.ensureInitialized();try{await this.retryOperation(()=>this.repository.deleteTag(this.projectId,e)),this.tagsCache.delete(e)}catch(t){throw new y(`Failed to delete tag via API`,v.STORAGE_ERROR,{operation:`deleteTag`,tag:e},t)}}async renameTag(e,t){await this.ensureInitialized();try{let n=this.tagsCache.get(e);if(!n)throw Error(`Tag ${e} not found`);let r={...n,name:t};await this.repository.createTag(this.projectId,r),await this.repository.deleteTag(this.projectId,e),this.tagsCache.delete(e),this.tagsCache.set(t,r)}catch(n){throw new y(`Failed to rename tag via API`,v.STORAGE_ERROR,{operation:`renameTag`,oldTag:e,newTag:t},n)}}async copyTag(e,t){await this.ensureInitialized();try{let n=this.tagsCache.get(e);if(!n)throw Error(`Source tag ${e} not found`);let r={...n,name:t};await this.repository.createTag(this.projectId,r),this.tagsCache.set(t,r)}catch(n){throw new y(`Failed to copy tag via API`,v.STORAGE_ERROR,{operation:`copyTag`,sourceTag:e,targetTag:t},n)}}async getStats(){await this.ensureInitialized();try{let e=await this.repository.getTasks(this.projectId),t=await this.repository.getTags(this.projectId),n=t.map(e=>({tag:e.name,taskCount:e.tasks.length,lastModified:new Date().toISOString()}));return{totalTasks:e.length,totalTags:t.length,storageSize:0,lastModified:new Date().toISOString(),tagStats:n}}catch(e){throw new y(`Failed to get stats from API`,v.STORAGE_ERROR,{operation:`getStats`},e)}}async backup(){await this.ensureInitialized();try{return await this.repository.getTasks(this.projectId),await this.repository.getTags(this.projectId),`backup-${this.projectId}-${Date.now()}`}catch(e){throw new y(`Failed to create backup via API`,v.STORAGE_ERROR,{operation:`backup`},e)}}async restore(e){throw await this.ensureInitialized(),new y(`Restore not implemented for API storage`,v.NOT_IMPLEMENTED,{operation:`restore`,backupId:e})}async clear(){await this.ensureInitialized();try{let e=await this.repository.getTasks(this.projectId);e.length>0&&await this.repository.bulkDeleteTasks(this.projectId,e.map(e=>e.id));let t=await this.repository.getTags(this.projectId);for(let e of t)await this.repository.deleteTag(this.projectId,e.name);this.tagsCache.clear()}catch(e){throw new y(`Failed to clear data via API`,v.STORAGE_ERROR,{operation:`clear`},e)}}async close(){this.initialized=!1,this.tagsCache.clear()}async watch(e,t){await this.ensureInitialized();let n=E.getInstance(),r=n.getContext();if(!r?.briefId)throw new y(`No brief context found for watching. Please connect to a brief first.`,v.NO_BRIEF_SELECTED,{operation:`watch`});let i=n.supabaseClient.getClient(),a=`tasks-watch-${r.briefId}-${Date.now()}`,o=t?.debounceMs??300,s,c=!1,l=i.channel(a).on(`postgres_changes`,{event:`*`,schema:`public`,table:`tasks`,filter:`brief_id=eq.${r.briefId}`},()=>{c||(s&&clearTimeout(s),s=setTimeout(()=>{c||e({type:`change`,timestamp:new Date})},o))}).subscribe((t,n)=>{(t===`CHANNEL_ERROR`||t===`TIMED_OUT`||t===`CLOSED`||n)&&e({type:`error`,timestamp:new Date,error:n||Error(`Channel subscription ${t.toLowerCase()}`)})});return{unsubscribe:()=>{c=!0,s&&clearTimeout(s),l.unsubscribe()}}}async ensureInitialized(){this.initialized||await this.initialize()}getApiClient(){if(!this.apiClient){let e=process.env.TM_BASE_DOMAIN||process.env.TM_PUBLIC_BASE_DOMAIN;if(!e)throw new y(`API endpoint not configured. Please set TM_PUBLIC_BASE_DOMAIN environment variable.`,v.MISSING_CONFIGURATION,{operation:`getApiClient`});let t=E.getInstance().ensureBriefSelected(`getApiClient`);this.apiClient=new Ht({baseUrl:e,authManager:E.getInstance(),accountId:t.orgId})}return this.apiClient}getExpansionService(){if(!this.expansionService){let e=this.getApiClient(),t=E.getInstance();this.expansionService=new Ft(this.repository,this.projectId,e,t)}return this.expansionService}getRetrievalService(){if(!this.retrievalService){let e=this.getApiClient(),t=E.getInstance();this.retrievalService=new It(this.repository,this.projectId,e,t)}return this.retrievalService}async retryOperation(e,t=1){try{return await e()}catch(n){if(this.enableRetry&&t<this.maxRetries){let n=2**t*1e3;return await new Promise(e=>setTimeout(e,n)),this.retryOperation(e,t+1)}throw n}}wrapError(e,t,n){throw e instanceof y&&e.is(v.NO_BRIEF_SELECTED)?e:new y(t,v.STORAGE_ERROR,n,e)}},Wt=class e{static async createFromStorageConfig(t,n){return e.create({storage:t,projectPath:n},n)}static async create(t,n){let r=t.storage?.type||`auto`,i=x(`StorageFactory`);switch(r){case`file`:return i.debug(`📁 Using local file storage`),e.createFileStorage(n,t);case`api`:if(!e.isHamsterAvailable(t)){let e=[];t.storage?.apiEndpoint||e.push(`apiEndpoint`),t.storage?.apiAccessToken||e.push(`apiAccessToken`);let n=E.getInstance();if(!await n.hasValidSession())throw new y(`API storage not fully configured (${e.join(`, `)||`credentials missing`}). Run: tm auth login, or set the missing field(s).`,v.MISSING_CONFIGURATION,{storageType:`api`,missing:e});let r=await n.getAccessToken();if(r){let e={...t.storage,type:`api`,apiAccessToken:r,apiEndpoint:t.storage?.apiEndpoint||process.env.TM_BASE_DOMAIN||process.env.TM_PUBLIC_BASE_DOMAIN||`https://tryhamster.com/api`};if(!e.apiEndpoint)throw new y(`API endpoint could not be determined.`,v.MISSING_CONFIGURATION,{storageType:`api`});t.storage=e}}return i.info(`☁️ Using API storage`),e.createApiStorage(t);case`auto`:let a=E.getInstance();if(e.isHamsterAvailable(t))return i.info(`☁️ Using API storage (configured)`),e.createApiStorage(t);if(await a.hasValidSession()){let r=await a.getAccessToken();if(!a.getContext()?.briefId)return i.debug(`📁 User authenticated but no brief selected, using file storage`),e.createFileStorage(n,t);if(r)return t.storage={...t.storage,type:`api`,apiAccessToken:r,apiEndpoint:t.storage?.apiEndpoint||process.env.TM_BASE_DOMAIN||process.env.TM_PUBLIC_BASE_DOMAIN||`https://tryhamster.com/api`},i.info(`☁️ Using API storage (authenticated)`),e.createApiStorage(t)}return i.debug(`📁 Using local file storage`),e.createFileStorage(n,t);default:throw new y(`Unknown storage type: ${r}`,v.INVALID_INPUT,{storageType:r})}}static createFileStorage(e,t){return new M(t.storage?.basePath||e)}static createApiStorage(e){return new Ut({supabaseClient:Fe.getInstance().getClient(),projectId:e.projectPath||``,enableRetry:e.retry?.retryOnNetworkError,maxRetries:e.retry?.retryAttempts})}static detectOptimalStorage(e){return e.storage?.apiEndpoint&&e.storage?.apiAccessToken?`api`:`file`}static validateStorageConfig(e){let t=[],n=e.storage?.type;if(!n)return t.push(`Storage type is not specified`),{isValid:!1,errors:t};switch(n){case`api`:e.storage?.apiEndpoint||t.push(`API endpoint is required for API storage`),e.storage?.apiAccessToken||t.push(`API access token is required for API storage`);break;case`file`:break;case`auto`:break;default:t.push(`Unknown storage type: ${n}`)}return{isValid:t.length===0,errors:t}}static isHamsterAvailable(e){return!!(e.storage?.apiEndpoint&&e.storage?.apiAccessToken)}static async createWithFallback(t,n){if(e.isHamsterAvailable(t))try{let n=e.createApiStorage(t);return await n.initialize(),n}catch(e){x(`StorageFactory`).warn(`Failed to initialize API storage, falling back to file storage:`,e)}return e.createFileStorage(n,t)}},Gt=class e{id;title;description;status;priority;dependencies;details;testStrategy;subtasks;createdAt;updatedAt;effort;actualEffort;tags;assignee;complexity;recommendedSubtasks;expansionPrompt;complexityReasoning;metadata;constructor(e){this.validate(e),this.id=String(e.id),this.title=e.title,this.description=e.description,this.status=e.status,this.priority=e.priority,this.dependencies=(e.dependencies||[]).map(e=>String(e)),this.details=e.details,this.testStrategy=e.testStrategy,this.subtasks=(e.subtasks||[]).map(e=>({...e,id:String(e.id),parentId:String(e.parentId)})),this.createdAt=e.createdAt,this.updatedAt=e.updatedAt,this.effort=e.effort,this.actualEffort=e.actualEffort,this.tags=e.tags,this.assignee=e.assignee,this.complexity=e.complexity,this.recommendedSubtasks=e.recommendedSubtasks,this.expansionPrompt=e.expansionPrompt,this.complexityReasoning=e.complexityReasoning,this.metadata=e.metadata}validate(e){if(e.id===void 0||e.id===null||typeof e.id!=`string`&&typeof e.id!=`number`)throw new y(`Task ID is required and must be a string or number`,v.VALIDATION_ERROR);if(!e.title||e.title.trim().length===0)throw new y(`Task title is required`,v.VALIDATION_ERROR);if(!e.description||e.description.trim().length===0)throw new y(`Task description is required`,v.VALIDATION_ERROR);if(!this.isValidStatus(e.status))throw new y(`Invalid task status: ${e.status}`,v.VALIDATION_ERROR);if(!this.isValidPriority(e.priority))throw new y(`Invalid task priority: ${e.priority}`,v.VALIDATION_ERROR)}isValidStatus(e){return[`pending`,`in-progress`,`done`,`deferred`,`cancelled`,`blocked`,`review`].includes(e)}isValidPriority(e){return[`low`,`medium`,`high`,`critical`].includes(e)}canComplete(){return this.status===`done`||this.status===`cancelled`||this.status===`blocked`?!1:this.subtasks.every(e=>e.status===`done`||e.status===`cancelled`)}markAsComplete(){if(!this.canComplete())throw new y(`Task cannot be marked as complete`,v.TASK_STATUS_ERROR,{taskId:this.id,currentStatus:this.status,hasIncompleteSubtasks:this.subtasks.some(e=>e.status!==`done`&&e.status!==`cancelled`)});this.status=`done`,this.updatedAt=new Date().toISOString()}hasDependencies(){return this.dependencies.length>0}hasSubtasks(){return this.subtasks.length>0}addSubtask(e){let t=this.subtasks.length+1;this.subtasks.push({...e,id:t,parentId:this.id}),this.updatedAt=new Date().toISOString()}updateStatus(e){if(!this.isValidStatus(e))throw new y(`Invalid status: ${e}`,v.VALIDATION_ERROR);if(this.status===`done`&&e===`pending`)throw new y(`Cannot move completed task back to pending`,v.TASK_STATUS_ERROR);this.status=e,this.updatedAt=new Date().toISOString()}toJSON(){return{id:this.id,title:this.title,description:this.description,status:this.status,priority:this.priority,dependencies:this.dependencies,details:this.details,testStrategy:this.testStrategy,subtasks:this.subtasks,createdAt:this.createdAt,updatedAt:this.updatedAt,effort:this.effort,actualEffort:this.actualEffort,tags:this.tags,assignee:this.assignee,complexity:this.complexity,recommendedSubtasks:this.recommendedSubtasks,expansionPrompt:this.expansionPrompt,complexityReasoning:this.complexityReasoning,metadata:this.metadata}}static fromObject(t){return new e(t)}static fromArray(t){return t.map(t=>new e(t))}},Kt=class{configManager;storage;initialized=!1;logger=x(`TaskService`);constructor(e){this.configManager=e,this.storage=null}async initialize(){if(this.initialized)return;let e=this.configManager.getStorageConfig(),t=this.configManager.getProjectRoot();this.storage=await Wt.createFromStorageConfig(e,t),await this.storage.initialize(),this.initialized=!0}async getTaskList(e={}){let t=this.configManager.getActiveTag(),n=e.tag||t;try{let t=e.filter?.status&&!e.filter.priority&&!e.filter.tags&&!e.filter.assignee&&!e.filter.search&&e.filter.hasSubtasks===void 0,r={};if(t){let t=Array.isArray(e.filter.status)?e.filter.status:[e.filter.status];t.length===1&&(r.status=t[0])}e.includeSubtasks===!1&&(r.excludeSubtasks=!0);let i=await this.storage.loadTasks(n,r),a={};e.includeSubtasks===!1&&(a.excludeSubtasks=!0);let o=r.status===void 0?i:await this.storage.loadTasks(n,a),s=Gt.fromArray(i),c=s;(e.filter&&!t||e.filter?.status&&Array.isArray(e.filter.status)&&e.filter.status.length>1)&&(c=this.applyFilters(s,e.filter));let l=c.map(e=>e.toJSON()),u=this.getStorageType(),d=u===`api`&&this.storage.getCurrentBriefName()||n;return{tasks:l,total:o.length,filtered:c.length,tag:d,storageType:u}}catch(t){throw t instanceof y?t:(this.logger.error(`Failed to get task list`,t),new y(`Failed to get task list`,v.INTERNAL_ERROR,{operation:`getTaskList`,tag:n,hasFilter:!!e.filter},t))}}async getTask(e,t){let n=t||this.getActiveTag();try{return await this.storage.loadTask(String(e),n)}catch(t){throw t instanceof y?t:new y(`Failed to get task ${e}`,v.STORAGE_ERROR,{operation:`getTask`,resource:`task`,taskId:String(e),tag:n},t)}}async getTasksByStatus(e,t){let n=Array.isArray(e)?e:[e];return(await this.getTaskList({tag:t,filter:{status:n}})).tasks}async getTaskStats(e){let t=await this.getTaskList({tag:e,includeSubtasks:!0}),n={total:t.total,byStatus:{},withSubtasks:0,blocked:0,storageType:t.storageType};return[`pending`,`in-progress`,`done`,`deferred`,`cancelled`,`blocked`,`review`].forEach(e=>{n.byStatus[e]=0}),t.tasks.forEach(e=>{n.byStatus[e.status]++,e.subtasks&&e.subtasks.length>0&&n.withSubtasks++,e.status===`blocked`&&n.blocked++}),n}async getNextTask(e){let t=(await this.getTaskList({tag:e,filter:{status:[`pending`,`in-progress`,`done`]}})).tasks,n={critical:4,high:3,medium:2,low:1},r=(e,t)=>typeof t==`string`&&t.includes(`.`)?t:`${e}.${t}`,i=new Set;t.forEach(e=>{e.status===`done`&&i.add(String(e.id)),Array.isArray(e.subtasks)&&e.subtasks.forEach(t=>{t.status===`done`&&i.add(`${e.id}.${t.id}`)})});let a=[];if(t.filter(e=>e.status===`in-progress`&&Array.isArray(e.subtasks)).forEach(e=>{e.subtasks.forEach(t=>{let n=(t.status||`pending`).toLowerCase();if(n!==`pending`&&n!==`in-progress`)return;let o=t.dependencies?.map(t=>r(String(e.id),t))??[];(o.length===0||o.every(e=>i.has(String(e))))&&a.push({id:`${e.id}.${t.id}`,title:t.title||`Subtask ${t.id}`,status:t.status||`pending`,priority:t.priority||e.priority||`medium`,dependencies:o,parentId:String(e.id),description:t.description,details:t.details,testStrategy:t.testStrategy,subtasks:[]})})}),a.length>0)return a.sort((e,t)=>{let r=n[e.priority]??2,i=n[t.priority]??2;if(i!==r)return i-r;if(e.dependencies.length!==t.dependencies.length)return e.dependencies.length-t.dependencies.length;let[a,o]=String(e.id).split(`.`).map(Number),[s,c]=String(t.id).split(`.`).map(Number);return a===s?o-c:a-s}),a[0];let o=t.filter(e=>{let t=(e.status||`pending`).toLowerCase();return t!==`pending`&&t!==`in-progress`?!1:(e.dependencies??[]).every(e=>i.has(String(e)))});return o.length===0?null:o.sort((e,t)=>{let r=n[e.priority]??2,i=n[t.priority]??2;if(i!==r)return i-r;let a=(e.dependencies??[]).length,o=(t.dependencies??[]).length;return a===o?Number(e.id)-Number(t.id):a-o})[0]}applyFilters(e,t){return e.filter(e=>{if(t.status&&!(Array.isArray(t.status)?t.status:[t.status]).includes(e.status)||t.priority&&!(Array.isArray(t.priority)?t.priority:[t.priority]).includes(e.priority)||t.tags&&t.tags.length>0&&(!e.tags||!t.tags.some(t=>e.tags?.includes(t)))||t.assignee&&e.assignee!==t.assignee)return!1;if(t.search){let n=t.search.toLowerCase(),r=e.title.toLowerCase().includes(n),i=e.description.toLowerCase().includes(n),a=e.details.toLowerCase().includes(n);if(!r&&!i&&!a)return!1}return!(t.hasSubtasks!==void 0&&e.subtasks.length>0!==t.hasSubtasks)})}getStorageType(){return this.storage.getStorageType()}getStorage(){return this.storage}getActiveTag(){if(this.initialized&&this.getStorageType()===`api`){let e=this.storage.getCurrentBriefName();if(e)return e}return this.configManager.getActiveTag()}async setActiveTag(e){await this.configManager.setActiveTag(e)}async updateTask(e,t,n){if(!this.storage)throw new y(`Storage not initialized`,v.STORAGE_ERROR);this.initialized||await this.initialize();let r=n||this.getActiveTag(),i=String(e);try{await this.storage.updateTask(i,t,r)}catch(t){throw t instanceof y?t:new y(`Failed to update task ${e}`,v.STORAGE_ERROR,{operation:`updateTask`,resource:`task`,taskId:i,tag:r},t)}}async updateTaskWithPrompt(e,t,n,r){if(!this.storage)throw new y(`Storage not initialized`,v.STORAGE_ERROR);this.initialized||await this.initialize();let i=n||this.getActiveTag(),a=String(e);try{await this.storage.updateTaskWithPrompt(a,t,i,r)}catch(n){throw n instanceof y?n:new y(`Failed to update task ${e} with prompt`,v.STORAGE_ERROR,{operation:`updateTaskWithPrompt`,resource:`task`,taskId:a,tag:i,promptLength:t.length},n)}}async expandTaskWithPrompt(e,t,n){if(!this.storage)throw new y(`Storage not initialized`,v.STORAGE_ERROR);this.initialized||await this.initialize();let r=t||this.getActiveTag(),i=String(e);try{return await this.storage.expandTaskWithPrompt(i,r,n)}catch(t){throw t instanceof y?t:new y(`Failed to expand task ${e}`,v.STORAGE_ERROR,{operation:`expandTaskWithPrompt`,resource:`task`,taskId:i,tag:r,numSubtasks:n?.numSubtasks},t)}}async updateTaskStatus(e,t,n){if(!this.storage)throw new y(`Storage not initialized`,v.STORAGE_ERROR);let r=n||this.getActiveTag(),i=String(e);try{return await this.storage.updateTaskStatus(i,t,r)}catch(e){throw e instanceof y?e:new y(`Failed to update task status for ${i}`,v.STORAGE_ERROR,{operation:`updateTaskStatus`,resource:`task`,taskId:i,newStatus:t,tag:r},e)}}async getTagsWithStats(){if(!this.storage)throw new y(`Storage not initialized`,v.STORAGE_ERROR);this.initialized||await this.initialize();try{return await this.storage.getTagsWithStats()}catch(e){throw e instanceof y?e:new y(`Failed to get tags with stats`,v.STORAGE_ERROR,{operation:`getTagsWithStats`,resource:`tags`},e)}}async close(){this.storage&&await this.storage.close(),this.initialized=!1}},qt=class{constructor(e){this.taskService=e}async startTask(e,t={}){try{let{parentId:n,subtaskId:r}=this.parseTaskId(e);if(!t.force){let t=await this.checkInProgressConflicts(e);if(!t.canProceed)return{task:null,found:!1,started:!1,error:`Conflicting tasks in progress: ${t.conflictingTasks.map(e=>`#${e.id}: ${e.title}`).join(`, `)}`}}let i=await this.taskService.getTask(n);if(!i)return{task:null,found:!1,started:!1,error:`Task ${n} not found`};let a;if(r&&i.subtasks&&(a=i.subtasks.find(e=>String(e.id)===r)),t.updateStatus&&!t.dryRun)try{await this.taskService.updateTaskStatus(n,`in-progress`)}catch(e){console.warn(`Could not update task status: ${e instanceof Error?e.message:String(e)}`)}let o=!1,s=`Task ready to execute`,c,l=this.normalizeExecutor(t.executor);return t.dryRun?(o=!0,s=`Dry run - task would be executed`,c=await this.prepareExecutionCommand(i,a,l)):(c=await this.prepareExecutionCommand(i,a,l),o=!!c,s=c?`Command prepared: ${c.executable} ${c.args.join(` `)}`:`Failed to prepare execution command`),{task:i,found:!0,started:o,subtaskId:r,subtask:a,executionOutput:s,command:c||void 0}}catch(e){return{task:null,found:!1,started:!1,error:e instanceof Error?e.message:String(e)}}}async checkInProgressConflicts(e){let t=(await this.taskService.getTaskList()).tasks.filter(e=>e.status===`in-progress`);if(t.find(t=>t.id===e))return{canProceed:!0,conflictingTasks:[]};let n=e.includes(`.`);if(n){let n=e.split(`.`)[0];if(t.find(e=>e.id===n))return{canProceed:!0,conflictingTasks:[]}}let r=t.filter(t=>{if(t.id===e)return!1;if(n){let n=e.split(`.`)[0];if(t.id===n)return!1}if(t.id.toString().includes(`.`)){let r=t.id.toString().split(`.`)[0];if(n&&r===e.split(`.`)[0])return!1}return!0});return r.length>0?{canProceed:!1,conflictingTasks:r,reason:`Other tasks are already in progress`}:{canProceed:!0,conflictingTasks:[]}}async getNextAvailableTask(){return(await this.taskService.getNextTask())?.id||null}parseTaskId(e){if(e.includes(`.`)){let[t,n]=e.split(`.`);return{parentId:t,subtaskId:n}}return{parentId:e}}async canStartTask(e,t=!1){return t?!0:(await this.checkInProgressConflicts(e)).canProceed}async prepareExecutionCommand(e,t,n=`claude`){try{let r=this.formatTaskPrompt(e,t);return{executable:n,args:this.getExecutionArgs(n,r),cwd:process.cwd()}}catch(e){return console.warn(`Failed to prepare execution command: ${e instanceof Error?e.message:String(e)}`),null}}normalizeExecutor(e){if(!e)return`claude`;let t=e.toLowerCase();return t===`claude`||t===`codex`?t:(console.warn(`Unknown executor "${e}", defaulting to "claude". Supported executors: claude, codex.`),`claude`)}getExecutionArgs(e,t){return[t]}formatTaskPrompt(e,t){let n=t||e,r=t?`Subtask`:`Task`,i=`${r} #${t?`${e.id}.${t.id}`:e.id}: ${n.title}\n\n`;return n.description&&(i+=`Description:\n${n.description}\n\n`),n.details&&(i+=`Implementation Details:\n${n.details}\n\n`),n.testStrategy&&(i+=`Test Strategy:\n${n.testStrategy}\n\n`),e.dependencies&&e.dependencies.length>0&&(i+=`Dependencies: ${e.dependencies.join(`, `)}\n\n`),i+=`Please help me implement this ${r.toLowerCase()}.`,i}async getTaskWithSubtask(e){let{parentId:t,subtaskId:n}=this.parseTaskId(e),r=await this.taskService.getTask(t);return r?n&&r.subtasks?{task:r,subtask:r.subtasks.find(e=>String(e.id)===n),subtaskId:n}:{task:r}:{task:null}}};const P=x(`TaskLoader`);var Jt=class{taskService;constructor(e){if(!e)throw Error(`taskService is required for TaskLoaderService`);this.taskService=e}async loadAndValidateTask(e){P.info(`Loading task ${e}...`);let t=await this.loadTask(e);if(!t)return{success:!1,errorType:`task_not_found`,errorMessage:`Task with ID "${e}" not found`,suggestion:`Use "task-master list" to see available tasks or verify the task ID is correct.`};let n=this.validateTaskStatus(t);if(!n.success)return n;let r=this.validateSubtasksExist(t);if(!r.success)return r;let i=this.validateSubtaskStructure(t);if(!i.success)return i;let a=this.validateDependencies(t);return a.success?(P.info(`Task ${e} validated successfully`),{success:!0,task:t}):a}async loadTask(e){try{return await this.taskService.getTask(e)}catch(t){return P.error(`Failed to load task ${e}:`,t),null}}validateTaskStatus(e){return Xe(e.status)?{success:!1,errorType:`task_completed`,errorMessage:`Task "${e.title}" is already ${e.status}`,suggestion:`Autopilot can only execute tasks that are pending or in-progress. Use a different task.`}:{success:!0}}validateSubtasksExist(e){return!e.subtasks||e.subtasks.length===0?{success:!1,errorType:`no_subtasks`,errorMessage:`Task "${e.title}" has no subtasks`,suggestion:this.buildExpansionSuggestion(e)}:{success:!0}}buildExpansionSuggestion(e){let t=[`Autopilot requires tasks to be broken down into subtasks for execution.`];return t.push(`
|
|
246
|
+
Expand this task using:`),t.push(` task-master expand --id=${e.id}`),e.complexity||e.recommendedSubtasks?(t.push(`
|
|
247
|
+
This task has complexity analysis available. Consider reviewing it first:`),t.push(` task-master show ${e.id}`)):(t.push(`
|
|
248
|
+
Or analyze task complexity first to determine optimal subtask count:`),t.push(` task-master analyze-complexity --from=${e.id}`)),t.join(`
|
|
249
|
+
`)}validateSubtaskStructure(e){for(let t of e.subtasks){if(!t.title||!t.description)return{success:!1,errorType:`invalid_structure`,errorMessage:`Subtask ${e.id}.${t.id} is missing required fields`,suggestion:`Subtasks must have title and description. Re-expand the task or manually fix the subtask structure.`};if(t.dependencies&&!Array.isArray(t.dependencies))return{success:!1,errorType:`invalid_structure`,errorMessage:`Subtask ${e.id}.${t.id} has invalid dependencies format`,suggestion:`Dependencies must be an array. Fix the task structure manually.`}}return{success:!0}}validateDependencies(e){let t=[],n=new Set(e.subtasks.map(e=>String(e.id)));for(let r of e.subtasks){let i=`${e.id}.${r.id}`;if(r.dependencies&&r.dependencies.length>0)for(let e of r.dependencies){let r=String(e);n.has(r)||t.push({subtaskId:i,issueType:`missing`,message:`References non-existent subtask ${r}`,dependencyRef:r})}let a=this.detectCircularDependency(r,e.subtasks,new Set);a&&t.push({subtaskId:i,issueType:`circular`,message:`Circular dependency detected: ${a.join(` -> `)}`})}return t.length>0?{success:!1,errorType:t[0].issueType===`circular`?`circular_dependencies`:`missing_dependencies`,errorMessage:`Task "${e.title}" has dependency issues`,suggestion:`Fix dependency issues manually or re-expand the task:
|
|
250
|
+
`+t.map(e=>` - ${e.subtaskId}: ${e.message}`).join(`
|
|
251
|
+
`),dependencyIssues:t}:{success:!0}}detectCircularDependency(e,t,n){let r=String(e.id);if(n.has(r))return[r];if(n.add(r),e.dependencies&&e.dependencies.length>0)for(let i of e.dependencies){let e=String(i),a=t.find(t=>String(t.id)===e);if(a){let e=this.detectCircularDependency(a,t,new Set(n));if(e)return[r,...e]}}return null}getExecutionOrder(e){let t=[],n=new Set;for(;t.length<e.subtasks.length;){let r=!1;for(let i of e.subtasks){let e=String(i.id);if(!n.has(e)&&(!i.dependencies||i.dependencies.length===0||i.dependencies.every(e=>n.has(String(e))))){t.push(i),n.add(e),r=!0;break}}if(!r&&t.length<e.subtasks.length){P.warn(`Could not determine complete execution order for task ${e.id}`);for(let r of e.subtasks)n.has(String(r.id))||t.push(r);break}}return t}async cleanup(){}};const F=pe(de);async function Yt(e){if(!e)throw Error(`projectRoot is required for isGitRepository`);try{return await F(`git rev-parse --git-dir`,{cwd:e}),!0}catch{return!1}}async function Xt(e){if(!e)throw Error(`projectRoot is required for getLocalBranches`);try{let{stdout:t}=await F(`git branch --format="%(refname:short)"`,{cwd:e,maxBuffer:10*1024*1024});return t.trim().split(`
|
|
252
|
+
`).filter(e=>e.length>0).map(e=>e.trim())}catch{return[]}}async function Zt(e){if(!e)throw Error(`projectRoot is required for getRemoteBranches`);try{let{stdout:t}=await F(`git branch -r --format="%(refname:short)"`,{cwd:e,maxBuffer:10*1024*1024}),n=t.trim().split(`
|
|
253
|
+
`).filter(e=>e.length>0&&!e.includes(`HEAD`)).map(e=>e.replace(/^[^/]+\//,``).trim());return Array.from(new Set(n))}catch{return[]}}async function Qt(e){try{return await F(`gh auth status`,e?{cwd:e}:{}),!0}catch{return!1}}async function $t(e){if(!e)throw Error(`projectRoot is required for getGitHubRepoInfo`);try{let{stdout:t}=await F(`gh repo view --json name,owner,defaultBranchRef`,{cwd:e});return JSON.parse(t)}catch{return null}}async function en(e){if(!e)throw Error(`projectRoot is required for getDefaultBranch`);try{if(await Qt(e)){let t=await $t(e);if(t&&t.defaultBranchRef)return t.defaultBranchRef.name}let t=(await F(`git remote`,{cwd:e})).stdout.trim().split(`
|
|
254
|
+
`).filter(Boolean);if(t.length>0){let n=t.includes(`origin`)?`origin`:t[0];try{let{stdout:t}=await F(`git remote show ${n}`,{cwd:e,maxBuffer:10*1024*1024}),r=t.match(/HEAD branch:\s+([^\s]+)/);if(r)return r[1].trim()}catch{}try{let{stdout:t}=await F(`git symbolic-ref refs/remotes/${n}/HEAD`,{cwd:e});return t.replace(`refs/remotes/${n}/`,``).trim()}catch{}}throw Error(`default-branch-not-found`)}catch{let t=[`main`,`master`],n=await Xt(e),r=await Zt(e);for(let e of t)if(n.includes(e)||r.includes(e))return e;return null}}const I=x(`PreflightChecker`);var tn=class{projectRoot;constructor(e){if(!e)throw Error(`projectRoot is required for PreflightChecker`);this.projectRoot=e}async detectTestCommand(){try{let e=oe(l(this.projectRoot,`package.json`),`utf-8`),t=JSON.parse(e);if(!t.scripts||!t.scripts.test)return{success:!1,message:`No test script found in package.json. Please add a "test" script.`};let n=t.scripts.test;return{success:!0,value:n,message:`Test command: ${n}`}}catch(e){return e.code===`ENOENT`?{success:!1,message:`package.json not found in project root`}:{success:!1,message:`Failed to read package.json: ${e.message}`}}}async checkGitWorkingTree(){try{return await Yt(this.projectRoot)?fe(`git status --porcelain`,{cwd:this.projectRoot,encoding:`utf-8`,timeout:5e3}).trim().length>0?{success:!1,value:`dirty`,message:`Working tree has uncommitted or untracked changes. Please commit or stash them.`}:{success:!0,value:`clean`,message:`Working tree is clean`}:{success:!1,message:`Not a git repository. Initialize git first.`}}catch(e){return{success:!1,message:`Git check failed: ${e.message}`}}}detectProjectTypes(){let e=[];return g(l(this.projectRoot,`package.json`))&&e.push(`node`),(g(l(this.projectRoot,`requirements.txt`))||g(l(this.projectRoot,`setup.py`))||g(l(this.projectRoot,`pyproject.toml`)))&&e.push(`python`),(g(l(this.projectRoot,`pom.xml`))||g(l(this.projectRoot,`build.gradle`)))&&e.push(`java`),g(l(this.projectRoot,`go.mod`))&&e.push(`go`),g(l(this.projectRoot,`Cargo.toml`))&&e.push(`rust`),g(l(this.projectRoot,`composer.json`))&&e.push(`php`),g(l(this.projectRoot,`Gemfile`))&&e.push(`ruby`),se(this.projectRoot).some(e=>e.endsWith(`.csproj`)||e.endsWith(`.sln`))&&e.push(`dotnet`),e}getToolsForProjectType(e){return{node:[{command:`node`,args:[`--version`]},{command:`npm`,args:[`--version`]}],python:[{command:`python3`,args:[`--version`]},{command:`pip3`,args:[`--version`]}],java:[{command:`java`,args:[`--version`]}],go:[{command:`go`,args:[`version`]}],rust:[{command:`cargo`,args:[`--version`]}],php:[{command:`php`,args:[`--version`]},{command:`composer`,args:[`--version`]}],ruby:[{command:`ruby`,args:[`--version`]},{command:`bundle`,args:[`--version`]}],dotnet:[{command:`dotnet`,args:[`--version`]}]}[e]||[]}async validateRequiredTools(){let e=[];e.push(this.checkTool(`git`,[`--version`])),e.push(await this.checkGhCli());let t=this.detectProjectTypes();t.length===0?I.warn(`No recognized project type detected`):I.info(`Detected project types: ${t.join(`, `)}`);for(let n of t){let t=this.getToolsForProjectType(n);for(let n of t)e.push(this.checkTool(n.command,n.args))}let n=e.every(e=>e.available),r=e.filter(e=>!e.available).map(e=>e.name);return n?{success:!0,value:e,message:`All required tools are available`}:{success:!1,value:e,message:`Missing required tools: ${r.join(`, `)}`}}checkTool(e,t){try{let n=fe(`${e} ${t.join(` `)}`,{cwd:this.projectRoot,encoding:`utf-8`,stdio:`pipe`,timeout:5e3}).trim().split(`
|
|
255
|
+
`)[0];return{name:e,available:!0,version:n,message:`${e} ${n}`}}catch{return{name:e,available:!1,message:`${e} not found`}}}async checkGhCli(){try{return{name:`gh`,available:!0,version:fe(`gh --version`,{cwd:this.projectRoot,encoding:`utf-8`,stdio:`pipe`,timeout:5e3}).trim().split(`
|
|
256
|
+
`)[0],message:await Qt(this.projectRoot)?`GitHub CLI installed (authenticated)`:`GitHub CLI installed (not authenticated)`}}catch{return{name:`gh`,available:!1,message:`GitHub CLI not found`}}}async detectDefaultBranch(){try{let e=await en(this.projectRoot);return e?{success:!0,value:e,message:`Default branch: ${e}`}:{success:!1,message:`Could not determine default branch. Make sure remote is configured.`}}catch(e){return{success:!1,message:`Failed to detect default branch: ${e.message}`}}}async runAllChecks(){I.info(`Running preflight checks...`);let e=await this.detectTestCommand(),t=await this.checkGitWorkingTree(),n=await this.validateRequiredTools(),r=await this.detectDefaultBranch(),i=e.success&&t.success&&n.success&&r.success,a=[],o=[];e.success?a.push(`Test command`):o.push(`Test command`),t.success?a.push(`Git working tree`):o.push(`Git working tree`),n.success?a.push(`Required tools`):o.push(`Required tools`),r.success?a.push(`Default branch`):o.push(`Default branch`);let s=a.length+o.length,c=i?`All preflight checks passed (${a.length}/${s})`:`Preflight checks failed: ${o.join(`, `)} (${a.length}/${s} passed)`;return I.info(c),{success:i,testCommand:e,gitWorkingTree:t,requiredTools:n,defaultBranch:r,summary:c}}};const nn=[`master`];var rn=class{constructor(e){this.storage=e}validateTagName(e,t=`Tag name`){if(!e||typeof e!=`string`)throw new y(`${t} is required and must be a string`,v.VALIDATION_ERROR);if(e.length>50)throw new y(`${t} must be 50 characters or less`,v.VALIDATION_ERROR,{tagName:e,maxLength:50});if(!/^[a-zA-Z0-9_-]+$/.test(e))throw new y(`${t} can only contain letters, numbers, hyphens, and underscores`,v.VALIDATION_ERROR,{tagName:e});if(nn.includes(e.toLowerCase()))throw new y(`"${e}" is a reserved tag name`,v.VALIDATION_ERROR,{tagName:e,reserved:!0})}checkTagMutationSupport(e){if(this.storage.getStorageType()===`api`)throw new y(`${e} is not supported with API storage. Use the web interface at Hamster Studio.`,v.NOT_IMPLEMENTED,{storageType:`api`,operation:e})}async createTag(e,t={}){this.validateTagName(e);let n=await this.storage.getAllTags();if(n.includes(e))throw new y(`Tag "${e}" already exists`,v.VALIDATION_ERROR,{tagName:e});if(t.copyFromTag&&!n.includes(t.copyFromTag))throw new y(`Cannot copy from missing tag "${t.copyFromTag}"`,v.NOT_FOUND,{tagName:t.copyFromTag});this.checkTagMutationSupport(`Tag creation`);let r;return t.copyFromTag?r=t.copyFromTag:t.copyFromCurrent&&(r=(await this.storage.getTagsWithStats()).currentTag||void 0),await this.storage.createTag(e,{copyFrom:r,description:t.description}),{name:e,taskCount:0,completedTasks:0,isCurrent:!1,statusBreakdown:{},description:t.description||`Tag created on ${new Date().toLocaleDateString()}`}}async deleteTag(e,t={}){if(this.validateTagName(e),e===`master`)throw new y(`Cannot delete the "master" tag`,v.VALIDATION_ERROR,{tagName:e,protected:!0});if(this.checkTagMutationSupport(`Tag deletion`),!(await this.storage.getAllTags()).includes(e))throw new y(`Tag "${e}" does not exist`,v.NOT_FOUND,{tagName:e});await this.storage.deleteTag(e)}async renameTag(e,t){if(this.validateTagName(e,`Old tag name`),this.validateTagName(t,`New tag name`),e===`master`)throw new y(`Cannot rename the "master" tag`,v.VALIDATION_ERROR,{tagName:e,protected:!0});this.checkTagMutationSupport(`Tag renaming`);let n=await this.storage.getAllTags();if(!n.includes(e))throw new y(`Tag "${e}" does not exist`,v.NOT_FOUND,{tagName:e});if(n.includes(t))throw new y(`Tag "${t}" already exists`,v.VALIDATION_ERROR,{tagName:t});await this.storage.renameTag(e,t)}async copyTag(e,t,n={}){this.validateTagName(e,`Source tag name`),this.validateTagName(t,`Target tag name`),this.checkTagMutationSupport(`Tag copying`);let r=await this.storage.getAllTags();if(!r.includes(e))throw new y(`Source tag "${e}" does not exist`,v.NOT_FOUND,{tagName:e});if(r.includes(t))throw new y(`Target tag "${t}" already exists`,v.VALIDATION_ERROR,{tagName:t});await this.storage.copyTag(e,t)}async getTagsWithStats(){return await this.storage.getTagsWithStats()}},an=class{constructor(e,t,n){this.storage=e,this.projectPath=t,this.configManager=n}async generateTaskFiles(e={}){let n=e.tag||this.configManager.getActiveTag(),r=e.outputDir||t.join(this.projectPath,`.taskmaster`,`tasks`);try{await m.mkdir(r,{recursive:!0});let e=await this.storage.loadTasks(n);if(e.length===0)return{success:!0,count:0,directory:r,orphanedFilesRemoved:0};let i=await this.cleanupOrphanedFiles(r,e,n),a={},o=await Promise.allSettled(e.map(async i=>{let a=this.formatTaskContent(i,e),o=this.getTaskFileName(i.id,n),s=t.join(r,o);return await m.writeFile(s,a,`utf-8`),i.id})),s=0;for(let t=0;t<o.length;t++){let n=o[t];if(n.status===`fulfilled`)s++;else{let r=String(e[t].id);a[r]=n.reason?.message||`Unknown error`}}return{success:Object.keys(a).length===0,count:s,directory:r,orphanedFilesRemoved:i,...Object.keys(a).length>0&&{fileErrors:a}}}catch(e){return{success:!1,count:0,directory:r,orphanedFilesRemoved:0,error:e.message}}}getTaskFileName(e,t){let n=String(e).padStart(3,`0`);return t===`master`?`task_${n}.md`:`task_${n}_${t}.md`}escapeRegExp(e){return e.replace(/[.*+?^${}()|[\]\\]/g,`\\$&`)}async cleanupOrphanedFiles(e,n,r){let i=0;try{let a=await m.readdir(e),o=n.map(e=>String(e.id)),s=/^task_(\d+)\.md$/,c=RegExp(`^task_(\\d+)_${this.escapeRegExp(r)}\\.md$`),l=[];for(let e of a){let t=null,n=null;if(r===`master`?(t=e.match(s),t&&(n=t[1])):(t=e.match(c),t&&(n=t[1])),n!==null){let t=String(parseInt(n,10));o.includes(t)||l.push(e)}}await Promise.all(l.map(async n=>{let r=t.join(e,n);await m.unlink(r)})),i=l.length}catch{}return i}formatTaskContent(e,t){let n=`# Task ID: ${e.id}\n\n`;if(n+=`**Title:** ${e.title}\n\n`,n+=`**Status:** ${e.status||`pending`}\n\n`,e.dependencies&&e.dependencies.length>0){let r=this.formatDependenciesWithStatus(e.dependencies,t);n+=`**Dependencies:** ${r}\n\n`}else n+=`**Dependencies:** None
|
|
257
|
+
|
|
258
|
+
`;if(n+=`**Priority:** ${e.priority||`medium`}\n\n`,n+=`**Description:** ${e.description||``}\n\n`,n+=`**Details:**
|
|
259
|
+
|
|
260
|
+
`,n+=`${e.details||`No details provided.`}\n\n`,n+=`**Test Strategy:**
|
|
261
|
+
|
|
262
|
+
`,n+=`${e.testStrategy||`No test strategy provided.`}\n`,e.subtasks&&e.subtasks.length>0){n+=`
|
|
263
|
+
## Subtasks
|
|
264
|
+
`;for(let t of e.subtasks)n+=this.formatSubtaskContent(t,e)}return n.replace(/\n{3,}/g,`
|
|
265
|
+
|
|
266
|
+
`)}formatSubtaskContent(e,t){let n=`\n### ${t.id}.${e.id}. ${e.title}\n\n`;if(n+=`**Status:** ${e.status||`pending`} \n`,e.dependencies&&e.dependencies.length>0){let r=e.dependencies.map(e=>{let n=String(e);return n.includes(`.`)?n:`${t.id}.${n}`}).join(`, `);n+=`**Dependencies:** ${r} \n`}else n+=`**Dependencies:** None
|
|
267
|
+
`;return n+=`
|
|
268
|
+
`,e.description&&(n+=`${e.description}\n`),e.details&&(n+=`\n**Details:**\n\n${e.details}\n`),n}formatDependenciesWithStatus(e,t){return e.map(e=>{let n=t.find(t=>String(t.id)===String(e));return n?`${e}${this.getStatusSymbol(n.status)}`:String(e)}).join(`, `)}getStatusSymbol(e){switch(e){case`done`:return` ✓`;case`in-progress`:return` ⧖`;case`blocked`:return` ⛔`;case`cancelled`:return` ✗`;case`deferred`:return` ⏸`;default:return``}}},on=class{taskService;executionService;loaderService;preflightChecker;briefsDomain;tagService;taskFileGenerator;projectRoot;configManager;constructor(e,t){this.projectRoot=e.getProjectRoot(),this.configManager=e,this.taskService=new Kt(e),this.executionService=new qt(this.taskService),this.loaderService=new Jt(this.taskService),this.preflightChecker=new tn(this.projectRoot),this.briefsDomain=new Pt}async initialize(){await this.taskService.initialize(),this.tagService=new rn(this.taskService.getStorage()),this.taskFileGenerator=new an(this.taskService.getStorage(),this.projectRoot,this.configManager)}async list(e){return this.taskService.getTaskList(e)}async get(e,t){let n=e.split(`.`),r=n[0],i=n[1],a=await this.taskService.getTask(r,t);if(!a)return{task:null,isSubtask:!1};if(i&&a.subtasks){let e=a.subtasks.find(e=>String(e.id)===i);return e?{task:e,isSubtask:!0}:{task:null,isSubtask:!0}}return{task:a,isSubtask:!1}}async getByStatus(e,t){return this.taskService.getTasksByStatus(e,t)}async getStats(e){return this.taskService.getTaskStats(e)}async getNext(e){return this.taskService.getNextTask(e)}async getCount(e,t){let n=await this.list({tag:t}),r=0;for(let t of n.tasks)if(t.status===e&&r++,t.subtasks&&t.subtasks.length>0)for(let n of t.subtasks)(n.status===e||e===`pending`&&!n.status)&&r++;return r}async update(e,t,n){return this.taskService.updateTask(e,t,n)}async updateWithPrompt(e,t,n,r){return this.taskService.updateTaskWithPrompt(e,t,n,r)}async expand(e,t,n){return this.taskService.expandTaskWithPrompt(e,t,n)}async updateStatus(e,t,n){return this.taskService.updateTaskStatus(e,t,n)}async setActiveTag(e){return this.taskService.setActiveTag(e)}async resolveBrief(e,t){return this.briefsDomain.resolveBrief(e,t)}async switchTag(e){this.taskService.getStorageType()===`file`?await this.setActiveTag(e):await this.briefsDomain.switchBrief(e)}async start(e,t){return this.executionService.startTask(e,t)}async checkInProgressConflicts(e){return this.executionService.checkInProgressConflicts(e)}async getNextAvailable(){return this.executionService.getNextAvailableTask()}async canStart(e,t){return this.executionService.canStartTask(e,t)}async loadAndValidate(e){return this.loaderService.loadAndValidateTask(e)}getExecutionOrder(e){return this.loaderService.getExecutionOrder(e)}async runPreflightChecks(){return this.preflightChecker.runAllChecks()}async detectTestCommand(){return this.preflightChecker.detectTestCommand()}async checkGitWorkingTree(){return this.preflightChecker.checkGitWorkingTree()}async validateRequiredTools(){return this.preflightChecker.validateRequiredTools()}async detectDefaultBranch(){return this.preflightChecker.detectDefaultBranch()}async createTag(e,t){return this.tagService.createTag(e,t)}async deleteTag(e,t){return this.tagService.deleteTag(e,t)}async renameTag(e,t){return this.tagService.renameTag(e,t)}async copyTag(e,t,n){return this.tagService.copyTag(e,t,n)}async getTagsWithStats(){return this.tagService.getTagsWithStats()}getStorageType(){return this.taskService.getStorageType()}async watch(e,t){return this.taskService.getStorage().watch(e,t)}async generateTaskFiles(e){return this.getStorageType()===`api`?{success:!1,count:0,directory:``,orphanedFilesRemoved:0,error:`Task file generation is only available for local file storage. API storage manages tasks in the cloud.`}:this.taskFileGenerator.generateTaskFiles(e)}async close(){await this.taskService.close()}},sn=class{projectRoot;statePath;backupDir;sessionDir;maxBackups;logger=x(`WorkflowStateManager`);writer=null;writerInitPromise=null;constructor(e,n=5){this.projectRoot=t.resolve(e),this.maxBackups=n;let r=this.getProjectIdentifier(this.projectRoot),i=me.homedir(),a=t.join(i,`.taskmaster`,r);this.sessionDir=t.join(a,`sessions`),this.statePath=t.join(this.sessionDir,`workflow-state.json`),this.backupDir=t.join(this.sessionDir,`backups`)}getProjectIdentifier(e){return`-`+t.resolve(e).replace(/^\//,``).replace(/[^a-zA-Z0-9]+/g,`-`).replace(/-+/g,`-`).replace(/-+$/,``)}async ensureWriter(){if(!this.writer){if(this.writerInitPromise){await this.writerInitPromise;return}this.writerInitPromise=(async()=>{await m.mkdir(this.sessionDir,{recursive:!0}),this.writer=new d(this.statePath)})(),await this.writerInitPromise,this.writerInitPromise=null}}async exists(){try{return await m.access(this.statePath),!0}catch{return!1}}async load(){try{let e=await m.readFile(this.statePath,`utf-8`);return JSON.parse(e)}catch(e){throw e.code===`ENOENT`?Error(`Workflow state file not found at ${this.statePath}`):Error(`Failed to load workflow state: ${e.message}`)}}async save(e){try{await this.ensureWriter();let t=JSON.stringify(e,null,2);try{JSON.parse(t)}catch{throw this.logger.error(`Generated invalid JSON:`,t),Error(`Failed to generate valid JSON from workflow state`)}await this.writer.write(t+`
|
|
269
|
+
`),this.logger.debug(`Saved workflow state (${t.length} bytes)`)}catch(e){throw Error(`Failed to save workflow state: ${e.message}`)}}async createBackup(){try{if(!await this.exists())return;let e=await this.load();await m.mkdir(this.backupDir,{recursive:!0});let n=new Date().toISOString().replace(/[:.]/g,`-`),r=t.join(this.backupDir,`workflow-state-${n}.json`),i={timestamp:new Date().toISOString(),state:e};await m.writeFile(r,JSON.stringify(i,null,2),`utf-8`),await this.pruneBackups()}catch(e){throw Error(`Failed to create backup: ${e.message}`)}}async delete(){try{await m.unlink(this.statePath)}catch(e){if(e.code!==`ENOENT`)throw Error(`Failed to delete workflow state: ${e.message}`)}}async listBackups(){try{return(await m.readdir(this.backupDir)).filter(e=>e.startsWith(`workflow-state-`)&&e.endsWith(`.json`)).sort().reverse()}catch(e){if(e.code===`ENOENT`)return[];throw Error(`Failed to list backups: ${e.message}`)}}async restoreBackup(e){try{let n=t.join(this.backupDir,e),r=await m.readFile(n,`utf-8`),i=JSON.parse(r);await this.save(i.state)}catch(e){throw Error(`Failed to restore backup: ${e.message}`)}}async pruneBackups(){try{let e=await this.listBackups();if(e.length>this.maxBackups){let n=e.slice(this.maxBackups);for(let e of n)await m.unlink(t.join(this.backupDir,e))}}catch(e){this.logger.warn(`Failed to prune backups: ${e.message}`)}}getStatePath(){return this.statePath}getBackupDir(){return this.backupDir}getSessionDir(){return this.sessionDir}getProjectRoot(){return this.projectRoot}getActivityLogPath(){return t.join(this.sessionDir,`activity.jsonl`)}},cn=class{currentPhase;context;transitions;eventListeners;persistCallback;autoPersistEnabled=!1;phaseGuards;aborted=!1;testResultValidator;gitOperationHook;executeHook;constructor(e){this.currentPhase=`PREFLIGHT`,this.context={...e},this.transitions=this.defineTransitions(),this.eventListeners=new Map,this.phaseGuards=new Map}defineTransitions(){return[{from:`PREFLIGHT`,to:`BRANCH_SETUP`,event:`PREFLIGHT_COMPLETE`},{from:`BRANCH_SETUP`,to:`SUBTASK_LOOP`,event:`BRANCH_CREATED`},{from:`SUBTASK_LOOP`,to:`FINALIZE`,event:`ALL_SUBTASKS_COMPLETE`},{from:`FINALIZE`,to:`COMPLETE`,event:`FINALIZE_COMPLETE`}]}getCurrentPhase(){return this.currentPhase}getCurrentTDDPhase(){if(this.currentPhase===`SUBTASK_LOOP`)return this.context.currentTDDPhase||`RED`}getContext(){return{...this.context}}async transition(e){if(this.aborted&&e.type!==`ABORT`)throw Error(`Workflow has been aborted`);if(e.type===`ERROR`){this.handleError(e.error),await this.triggerAutoPersist();return}if(e.type===`ABORT`){this.aborted=!0,await this.triggerAutoPersist();return}if(e.type===`RETRY`){this.handleRetry(),await this.triggerAutoPersist();return}if(this.currentPhase===`SUBTASK_LOOP`){await this.handleTDDPhaseTransition(e),await this.triggerAutoPersist();return}let t=this.transitions.find(t=>t.from===this.currentPhase&&t.event===e.type);if(!t)throw Error(`Invalid transition: ${e.type} from ${this.currentPhase}`);this.executeTransition(t,e),await this.triggerAutoPersist()}async handleTDDPhaseTransition(e){let t=this.context.currentTDDPhase||`RED`;switch(e.type){case`RED_PHASE_COMPLETE`:if(t!==`RED`)throw Error(`Invalid transition: RED_PHASE_COMPLETE from non-RED phase`);if(!e.testResults)throw Error(`Test results required for RED phase transition`);if(this.context.lastTestResults=e.testResults,e.testResults.failed===0){this.emit(`tdd:red:completed`),this.emit(`tdd:feature-already-implemented`,{subtaskId:this.getCurrentSubtaskId(),testResults:e.testResults});let t=this.context.subtasks[this.context.currentSubtaskIndex];t&&(t.status=`completed`),this.emit(`subtask:completed`),this.context.currentSubtaskIndex++;let n=this.getProgress();this.emit(`progress:updated`,{completed:n.completed,total:n.total,percentage:n.percentage}),this.context.currentSubtaskIndex<this.context.subtasks.length?(this.context.currentTDDPhase=`RED`,this.emit(`tdd:red:started`),this.emit(`subtask:started`)):await this.transition({type:`ALL_SUBTASKS_COMPLETE`});break}this.emit(`tdd:red:completed`),this.context.currentTDDPhase=`GREEN`,this.emit(`tdd:green:started`);break;case`GREEN_PHASE_COMPLETE`:if(t!==`GREEN`)throw Error(`Invalid transition: GREEN_PHASE_COMPLETE from non-GREEN phase`);if(!e.testResults)throw Error(`Test results required for GREEN phase transition`);if(e.testResults.failed!==0)throw Error(`GREEN phase must have zero failures`);this.context.lastTestResults=e.testResults,this.emit(`tdd:green:completed`),this.context.currentTDDPhase=`COMMIT`,this.emit(`tdd:commit:started`);break;case`COMMIT_COMPLETE`:if(t!==`COMMIT`)throw Error(`Invalid transition: COMMIT_COMPLETE from non-COMMIT phase`);this.emit(`tdd:commit:completed`);let n=this.context.subtasks[this.context.currentSubtaskIndex];n&&(n.status=`completed`);break;case`SUBTASK_COMPLETE`:this.emit(`subtask:completed`),this.context.currentSubtaskIndex++;let r=this.getProgress();this.emit(`progress:updated`,{completed:r.completed,total:r.total,percentage:r.percentage}),this.context.currentSubtaskIndex<this.context.subtasks.length?(this.context.currentTDDPhase=`RED`,this.emit(`tdd:red:started`),this.emit(`subtask:started`)):await this.transition({type:`ALL_SUBTASKS_COMPLETE`});break;case`ALL_SUBTASKS_COMPLETE`:this.emit(`phase:exited`),this.currentPhase=`FINALIZE`,this.context.currentTDDPhase=void 0,this.emit(`phase:entered`);break;default:throw Error(`Invalid transition: ${e.type} in SUBTASK_LOOP`)}}executeTransition(e,t){if(e.guard&&!e.guard(this.context))throw Error(`Guard condition failed for transition to ${e.to}`);let n=this.phaseGuards.get(e.to);if(n&&!n(this.context))throw Error(`Guard condition failed`);this.emit(`phase:exited`),this.updateContext(t),this.currentPhase=e.to,this.emit(`phase:entered`),this.currentPhase===`SUBTASK_LOOP`&&(this.context.currentTDDPhase=`RED`,this.emit(`tdd:red:started`),this.emit(`subtask:started`))}updateContext(e){switch(e.type){case`BRANCH_CREATED`:this.context.branchName=e.branchName,this.emit(`git:branch:created`,{branchName:e.branchName}),this.gitOperationHook&&this.gitOperationHook(`branch:created`,{branchName:e.branchName});break;case`ERROR`:this.context.errors.push(e.error),this.emit(`error:occurred`,{error:e.error});break}}getState(){return{phase:this.currentPhase,context:{...this.context}}}restoreState(e){this.currentPhase=e.phase,this.context={...e.context},this.emit(`workflow:resumed`,{phase:this.currentPhase,progress:this.getProgress()})}on(e,t){this.eventListeners.has(e)||this.eventListeners.set(e,new Set),this.eventListeners.get(e).add(t)}off(e,t){let n=this.eventListeners.get(e);n&&n.delete(t)}emit(e,t){let n={type:e,timestamp:new Date,phase:this.currentPhase,tddPhase:this.context.currentTDDPhase,subtaskId:this.getCurrentSubtaskId(),data:{...t,adapters:{testValidator:!!this.testResultValidator,gitHook:!!this.gitOperationHook,executeHook:!!this.executeHook}}},r=this.eventListeners.get(e);r&&r.forEach(e=>e(n))}getCurrentSubtaskId(){return this.context.subtasks[this.context.currentSubtaskIndex]?.id}onStatePersist(e){this.persistCallback=e}enableAutoPersist(e){this.persistCallback=e,this.autoPersistEnabled=!0}disableAutoPersist(){this.autoPersistEnabled=!1}async persistState(){this.persistCallback&&await this.persistCallback(this.getState()),this.emit(`state:persisted`)}async triggerAutoPersist(){this.autoPersistEnabled&&this.persistCallback&&await this.persistCallback(this.getState())}addGuard(e,t){this.phaseGuards.set(e,t)}removeGuard(e){this.phaseGuards.delete(e)}getCurrentSubtask(){return this.context.subtasks[this.context.currentSubtaskIndex]}getProgress(){let e=this.context.subtasks.filter(e=>e.status===`completed`).length,t=this.context.subtasks.length;return{completed:e,total:t,current:this.context.currentSubtaskIndex+1,percentage:t>0?Math.round(e/t*100):0}}canProceed(){return this.currentPhase===`SUBTASK_LOOP`?this.getCurrentSubtask()?.status===`completed`:!1}incrementAttempts(){let e=this.getCurrentSubtask();e&&e.attempts++}hasExceededMaxAttempts(){let e=this.getCurrentSubtask();return!e||!e.maxAttempts?!1:e.attempts>e.maxAttempts}handleError(e){this.context.errors.push(e),this.emit(`error:occurred`,{error:e})}handleRetry(){this.currentPhase===`SUBTASK_LOOP`&&(this.context.currentTDDPhase=`RED`,this.emit(`tdd:red:started`))}retryCurrentSubtask(){this.currentPhase===`SUBTASK_LOOP`&&(this.context.currentTDDPhase=`RED`,this.emit(`tdd:red:started`))}handleMaxAttemptsExceeded(){let e=this.getCurrentSubtask();e&&(e.status=`failed`,this.emit(`subtask:failed`,{subtaskId:e.id,attempts:e.attempts,maxAttempts:e.maxAttempts}))}isAborted(){return this.aborted}canResumeFromState(e){return!(![`PREFLIGHT`,`BRANCH_SETUP`,`SUBTASK_LOOP`,`FINALIZE`,`COMPLETE`].includes(e.phase)||!e.context||typeof e.context!=`object`||!e.context.taskId||!Array.isArray(e.context.subtasks)||typeof e.context.currentSubtaskIndex!=`number`||!Array.isArray(e.context.errors))}setTestResultValidator(e){this.testResultValidator=e,this.emit(`adapter:configured`,{adapterType:`test-validator`})}hasTestResultValidator(){return!!this.testResultValidator}removeTestResultValidator(){this.testResultValidator=void 0}onGitOperation(e){this.gitOperationHook=e}onExecute(e){this.executeHook=e}executeCommand(e){this.executeHook&&this.executeHook(e,this.context)}};async function ln(e,t){let n={...t,timestamp:new Date().toISOString()};await ne.ensureDir(c.dirname(e));let r=JSON.stringify(n)+`
|
|
270
|
+
`;await ne.appendFile(e,r,`utf-8`)}const un=[`workflow:started`,`workflow:completed`,`workflow:error`,`workflow:resumed`,`phase:entered`,`phase:exited`,`tdd:feature-already-implemented`,`tdd:red:started`,`tdd:red:completed`,`tdd:green:started`,`tdd:green:completed`,`tdd:commit:started`,`tdd:commit:completed`,`subtask:started`,`subtask:completed`,`subtask:failed`,`test:run`,`test:passed`,`test:failed`,`git:branch:created`,`git:commit:created`,`error:occurred`,`state:persisted`,`progress:updated`,`adapter:configured`];var dn=class{activityLogPath;orchestrator;logger=x(`WorkflowActivityLogger`);listenerMap=new Map;isActive=!1;constructor(e,t){this.orchestrator=e,this.activityLogPath=t}start(){if(this.isActive){this.logger.warn(`Activity logger is already active`);return}un.forEach(e=>{let t=e=>this.logEvent(e);this.listenerMap.set(e,t),this.orchestrator.on(e,t)}),this.isActive=!0,this.logger.debug(`Activity logger started, logging to: ${this.activityLogPath}`)}stop(){this.isActive&&(this.listenerMap.forEach((e,t)=>{this.orchestrator.off(t,e)}),this.listenerMap.clear(),this.isActive=!1,this.logger.debug(`Activity logger stopped and listeners removed`))}async logEvent(e){if(this.isActive)try{let t=e.timestamp instanceof Date?e.timestamp.toISOString():new Date(e.timestamp).toISOString(),n={type:e.type,phase:e.phase,tddPhase:e.tddPhase,subtaskId:e.subtaskId,eventTimestamp:t,...e.data||{}};await ln(this.activityLogPath,n)}catch(t){this.logger.error(`Failed to log activity event ${e.type}: ${t.message}`)}}getActivityLogPath(){return this.activityLogPath}isLogging(){return this.isActive}},fn=class{projectRoot;stateManager;taskStatusUpdater;tag;logger=x(`WorkflowService`);orchestrator;activityLogger;constructor(e){typeof e==`string`?this.projectRoot=e:(this.projectRoot=e.projectRoot,this.taskStatusUpdater=e.taskStatusUpdater,this.tag=e.tag),this.stateManager=new sn(this.projectRoot)}async updateTaskStatus(e,t,n){if(this.taskStatusUpdater)try{await this.taskStatusUpdater.updateStatus(e,t,n??this.tag)}catch(t){let n=t instanceof Error?t.message:String(t);this.logger.warn(`Failed to update task ${e} status: ${n}`)}}async hasWorkflow(){return await this.stateManager.exists()}async startWorkflow(e){let{taskId:t,taskTitle:n,subtasks:r,maxAttempts:i=3,force:a,tag:o,orgSlug:s}=e;if(await this.hasWorkflow()&&!a)throw Error(`Workflow already exists. Use force=true to override or resume existing workflow.`);let c=new A(this.projectRoot);await c.ensureGitRepository(),await c.ensureCleanWorkingTree();let l=r.map(e=>({id:e.id,title:e.title,status:e.status===`done`?`completed`:`pending`,attempts:0,maxAttempts:e.maxAttempts||i})),u=l.findIndex(e=>e.status!==`completed`);if(u===-1)throw Error(`All subtasks for task ${t} are already completed. Nothing to do.`);this.orchestrator=new cn({taskId:t,subtasks:l,currentSubtaskIndex:u,tag:o,errors:[],metadata:{startedAt:new Date().toISOString(),taskTitle:n,resumedFromSubtask:u>0?l[u].id:void 0}}),this.orchestrator.enableAutoPersist(async e=>{await this.stateManager.save(e)}),this.activityLogger=new dn(this.orchestrator,this.stateManager.getActivityLogPath()),this.activityLogger.start(),await this.orchestrator.transition({type:`PREFLIGHT_COMPLETE`});let d=this.generateBranchName(t,n,o,s);return await c.getCurrentBranch()!==d&&await c.createAndCheckoutBranch(d),await this.orchestrator.transition({type:`BRANCH_CREATED`,branchName:d}),await this.updateTaskStatus(t,`in-progress`,o),this.getStatus()}async resumeWorkflow(){let e=await this.stateManager.load();if(this.orchestrator=new cn(e.context),!this.orchestrator.canResumeFromState(e))throw Error(`Invalid workflow state. State may be corrupted. Consider starting a new workflow.`);return this.orchestrator.restoreState(e),this.orchestrator.enableAutoPersist(async e=>{await this.stateManager.save(e)}),this.activityLogger=new dn(this.orchestrator,this.stateManager.getActivityLogPath()),this.activityLogger.start(),this.getStatus()}getStatus(){if(!this.orchestrator)throw Error(`No active workflow. Start or resume a workflow first.`);let e=this.orchestrator.getContext(),t=this.orchestrator.getProgress(),n=this.orchestrator.getCurrentSubtask();return{taskId:e.taskId,phase:this.orchestrator.getCurrentPhase(),tddPhase:this.orchestrator.getCurrentTDDPhase(),branchName:e.branchName,currentSubtask:n?{id:n.id,title:n.title,attempts:n.attempts,maxAttempts:n.maxAttempts||3}:void 0,progress:t}}getContext(){if(!this.orchestrator)throw Error(`No active workflow. Start or resume a workflow first.`);return this.orchestrator.getContext()}getNextAction(){if(!this.orchestrator)throw Error(`No active workflow. Start or resume a workflow first.`);let e=this.orchestrator.getCurrentPhase(),t=this.orchestrator.getCurrentTDDPhase(),n=this.orchestrator.getCurrentSubtask();if(e===`COMPLETE`)return{action:`workflow_complete`,description:`All subtasks completed`,nextSteps:`All subtasks completed! Review the entire implementation and merge your branch when ready.`,phase:e};if(e===`FINALIZE`)return{action:`finalize_workflow`,description:`Finalize and complete the workflow`,nextSteps:`All subtasks are complete! Use autopilot_finalize to verify no uncommitted changes remain and mark the workflow as complete.`,phase:e};if(e!==`SUBTASK_LOOP`||!t||!n)return{action:`unknown`,description:`Workflow is not in active state`,nextSteps:`Use autopilot_status to check workflow state.`,phase:e};let r={phase:e,tddPhase:t,subtask:{id:n.id,title:n.title}};switch(t){case`RED`:return{...r,action:`generate_test`,description:`Generate failing test for current subtask`,nextSteps:`Write failing tests for subtask ${n.id}: "${n.title}". Create test file(s) that validate the expected behavior. Run tests and use autopilot_complete_phase with results. Note: If all tests pass (0 failures), the feature is already implemented and the subtask will be auto-completed.`};case`GREEN`:return{...r,action:`implement_code`,description:`Implement feature to make tests pass`,nextSteps:`Implement code to make tests pass for subtask ${n.id}: "${n.title}". Write the minimal code needed to pass all tests (GREEN phase), then use autopilot_complete_phase with test results.`};case`COMMIT`:return{...r,action:`commit_changes`,description:`Commit RED-GREEN cycle changes`,nextSteps:`Review and commit your changes for subtask ${n.id}: "${n.title}". Use autopilot_commit to create the commit and advance to the next subtask.`};default:return{...r,action:`unknown`,description:`Unknown TDD phase`,nextSteps:`Use autopilot_status to check workflow state.`}}}async completePhase(e){if(!this.orchestrator)throw Error(`No active workflow. Start or resume a workflow first.`);let t=this.orchestrator.getCurrentTDDPhase();if(!t)throw Error(`Not in active TDD phase`);switch(t){case`RED`:await this.orchestrator.transition({type:`RED_PHASE_COMPLETE`,testResults:e});break;case`GREEN`:await this.orchestrator.transition({type:`GREEN_PHASE_COMPLETE`,testResults:e});break;case`COMMIT`:throw Error(`Cannot complete COMMIT phase with test results. Use commit() instead.`);default:throw Error(`Unknown TDD phase: ${t}`)}return this.getStatus()}async commit(){if(!this.orchestrator)throw Error(`No active workflow. Start or resume a workflow first.`);let e=this.orchestrator.getCurrentTDDPhase();if(e!==`COMMIT`)throw Error(`Cannot commit in ${e} phase. Complete RED and GREEN phases first.`);let t=this.orchestrator.getCurrentSubtask()?.id;await this.orchestrator.transition({type:`COMMIT_COMPLETE`});let n=this.orchestrator.getProgress();if(n.current<n.total?await this.orchestrator.transition({type:`SUBTASK_COMPLETE`}):await this.orchestrator.transition({type:`ALL_SUBTASKS_COMPLETE`}),t){let e=this.orchestrator.getContext();await this.updateTaskStatus(t,`done`,e.tag)}return this.getStatus()}async finalizeWorkflow(){if(!this.orchestrator)throw Error(`No active workflow. Start or resume a workflow first.`);let e=this.orchestrator.getCurrentPhase();if(e!==`FINALIZE`)throw Error(`Cannot finalize workflow in ${e} phase. Complete all subtasks first.`);let t=await new A(this.projectRoot).getStatusSummary();if(!t.isClean)throw Error(`Cannot finalize workflow: working tree has uncommitted changes.\nStaged: ${t.staged}, Modified: ${t.modified}, Deleted: ${t.deleted}, Untracked: ${t.untracked}\nPlease commit all changes before finalizing the workflow.`);let n=this.orchestrator.getContext(),r=n.taskId;await this.orchestrator.transition({type:`FINALIZE_COMPLETE`});let i=this.getStatus();return await this.updateTaskStatus(r,`done`,n.tag),await this.stateManager.delete(),this.orchestrator=void 0,i}async abortWorkflow(){this.orchestrator&&await this.orchestrator.transition({type:`ABORT`}),await this.stateManager.delete(),this.orchestrator=void 0}generateBranchName(e,t,n,r){let i=t.toLowerCase().replace(/[^a-z0-9]+/g,`-`).replace(/^-+|-+$/g,``).substring(0,50),a=e.replace(/\./g,`-`),o=r||n;return`${o?`tm/${o}`:`tm`}/task-${a}-${i}`}},pn=class{workflowService=null;projectRoot;configManager;tasksDomain=null;constructor(e){this.configManager=e,this.projectRoot=e.getProjectRoot()}setTasksDomain(e){this.tasksDomain=e}getWorkflowService(){if(!this.workflowService){let e=this.configManager.getActiveTag(),t=this.tasksDomain?{updateStatus:async(e,t,n)=>{await this.tasksDomain.updateStatus(e,t,n)}}:void 0;this.workflowService=new fn({projectRoot:this.projectRoot,taskStatusUpdater:t,tag:e})}return this.workflowService}resetWorkflowService(){this.workflowService=null}async start(e){return this.resetWorkflowService(),this.getWorkflowService().startWorkflow(e)}async resume(){return this.resetWorkflowService(),this.getWorkflowService().resumeWorkflow()}getStatus(){return this.getWorkflowService().getStatus()}getContext(){return this.getWorkflowService().getContext()}getNextAction(){return this.getWorkflowService().getNextAction()}async completePhase(e){return this.getWorkflowService().completePhase(e)}async commit(){return this.getWorkflowService().commit()}async finalize(){let e=await this.getWorkflowService().finalizeWorkflow();return this.resetWorkflowService(),e}async abort(){await this.getWorkflowService().abortWorkflow(),this.resetWorkflowService()}async hasWorkflow(){return this.getWorkflowService().hasWorkflow()}},mn=class e{_projectPath;_configManager;_logger;_tasks;_auth;_workflow;_git;_config;_integration;_loop;get tasks(){return this._tasks}get auth(){return this._auth}get workflow(){return this._workflow}get git(){return this._git}get config(){return this._config}get integration(){return this._integration}get loop(){return this._loop}get logger(){return this._logger}static async create(t){let n=new e(t);return await n.initialize(),n}_options;constructor(e){if(!e.projectPath)throw new y(`Project path is required`,v.MISSING_CONFIGURATION);if(!t.isAbsolute(e.projectPath))throw new y(`Project path must be an absolute path, received: "${e.projectPath}"`,v.INVALID_INPUT);this._projectPath=t.resolve(e.projectPath),this._options=e}async initialize(){try{this._logger=De(this._options.loggerConfig),this._configManager=await dt.create(this._projectPath),this._options.configuration&&await this._configManager.updateConfig(this._options.configuration),this._auth=new D,this._tasks=new on(this._configManager,this._auth),this._workflow=new pn(this._configManager),this._git=new yt(this._projectPath),this._config=new at(this._configManager),this._integration=new Et(this._configManager),this._loop=new jt(this._configManager),await this._tasks.initialize(),this._workflow.setTasksDomain(this._tasks),this._logger.info(`TmCore initialized successfully`)}catch(e){throw this._logger&&this._logger.error(`Failed to initialize TmCore:`,e),new y(`Failed to initialize TmCore`,v.INTERNAL_ERROR,{operation:`initialize`},e)}}get projectPath(){return this._projectPath}async close(){this._tasks&&await this._tasks.close()}};async function hn(e){return mn.create(e)}function gn(e,n){try{return ie.existsSync(t.join(e,n))}catch{return!1}}function L(e,t){return t.some(t=>gn(e,t))}function _n(e=process.cwd()){let n=t.resolve(e),r=t.parse(n).root,i=0,a=null;if(L(n,We)||L(n,Ge))return n;let o=t.dirname(n);for(i=1;i<50;){let e=L(o,We),n=L(o,Ge);if(e&&(n||i===1))return o;if(n&&!e){a=o;break}if(o===r)break;let s=t.dirname(o);if(s===o)break;o=s,i++}for(n=a||t.resolve(e),i=0;i<50;){if(L(n,Ke))return n;if(n===r)break;let e=t.dirname(n);if(e===n)break;n=e,i++}return t.resolve(e)}function vn(e){if(!e)return``;let n=String(e).split(t.sep),r=n.findIndex(e=>e===`.taskmaster`);return r===-1?String(e):n.slice(0,r).join(t.sep)||t.sep}function yn(e){let t=e?r(process.cwd(),e):_n();return{projectRoot:t,tasksPath:n(t,Ue)}}function bn(e){return ge(typeof e==`string`?new Date(e):e,{addSuffix:!0})}function xn(e){return he(e,`hh:mm:ss a`)}function R(e){if(!e)return e;let t=e.trim();if(/^\d+(\.\d+)?$/.test(t))return t;let n=t.match(/^([a-zA-Z]{3})-?(\d+)$/);return n?`${n[1].toUpperCase()}-${n[2]}`:t}const Sn=/^\d+$/,Cn=/^\d+\.\d+$/,wn=/^[a-zA-Z]{3}-?\d+$/;function Tn(e){if(!e)return!1;let t=e.trim();return!!(Sn.test(t)||Cn.test(t)||wn.test(t))}function En(e){if(!e)return!1;let t=e.trim();return!!(Sn.test(t)||wn.test(t))}const Dn=_.string().trim().refine(Tn,{message:`Invalid task ID format. Expected: numeric ("1", "1.2") or prefixed with hyphen ("HAM-1")`}),On=_.string().trim().refine(Tn,{message:`Invalid task ID format. Expected: numeric ("1") or prefixed with hyphen ("HAM-1")`}).refine(En,{message:`Subtask IDs are not allowed. Please provide a main task ID (e.g., "1", "HAM-1")`}),kn=Dn.transform(R),An=On.transform(R),jn=Dn,Mn=On,Nn=/^(\d+(\.\d+)*|[A-Za-z]+-?\d+)$/;function Pn(e){return Nn.test(e)}_.string().min(1,`Task ID cannot be empty`).refine(Pn,{message:`Invalid task ID format. Expected numeric (e.g., '15'), subtask (e.g., '15.2'), or display ID (e.g., 'HAM-123')`});const Fn=_.string().min(1,`Task ID(s) cannot be empty`).refine(e=>{let t=e.split(`,`).map(e=>e.trim()).filter(e=>e.length>0);return t.length>0&&t.every(Pn)},{message:`Invalid task ID format. Expected numeric (e.g., '15'), subtask (e.g., '15.2'), or display ID (e.g., 'HAM-123'). Multiple IDs should be comma-separated.`});function In(e){let t=e.split(`,`).map(e=>e.trim()).filter(e=>e.length>0);if(t.length===0)throw Error(`No valid task IDs provided`);let n=t.filter(e=>!Pn(e));if(n.length>0)throw Error(`Invalid task ID format: ${n.join(`, `)}. Expected numeric (e.g., '15'), subtask (e.g., '15.2'), or display ID (e.g., 'HAM-123')`);return t.map(R)}const Ln=x(`TaskFilters`),Rn=[`pending`,`in-progress`,`review`];function zn(e){let t=new Map(e.map(e=>[String(e.id),[]])),n=[];for(let r of e)for(let e of r.dependencies??[]){let i=String(e),a=t.get(i);a?a.push(String(r.id)):n.push({taskId:String(r.id),depId:i})}return{blocksMap:t,invalidDependencies:n}}function Bn(e){let t=new Set(e.filter(e=>Xe(e.status)).map(e=>String(e.id)));return e.filter(e=>(Je.includes(e.status)||Ln.warn(`Task ${e.id} has unexpected status "${e.status}". Valid statuses are: ${Je.join(`, `)}`),Rn.includes(e.status)?(e.dependencies??[]).every(e=>t.has(String(e))):!1))}function Vn(e){return e.filter(e=>e.blocks.length>0)}const Hn=[{type:`task_count`,threshold:10,message:`Your tasks are growing! Upgrade to Hamster Studio (Multiplayer) for coordinated team action, AI context sharing, and faster shipping.`,promptType:`upgrade_suggestion`,showOnce:!1,cooldownDays:7,priority:80},{type:`tags_used`,threshold:3,message:`Organize by tags? Hamster briefs let you group and collaborate on tagged tasks with your team.`,promptType:`educational_notice`,showOnce:!1,cooldownDays:14,priority:70},{type:`list_count`,threshold:5,message:`Managing multiple projects? Create Hamster briefs to organize work across your team.`,promptType:`educational_notice`,showOnce:!1,cooldownDays:14,priority:50},{type:`dependencies_complex`,threshold:5,message:`Your tasks have complex dependencies. Hamster visualizes these relationships and tracks blockers automatically.`,promptType:`educational_notice`,showOnce:!1,cooldownDays:14,priority:60},{type:`days_active`,threshold:7,message:`Ready to collaborate? Export your tasks to Hamster Studio and start shipping faster with your team.`,promptType:`upgrade_suggestion`,showOnce:!0,priority:90},{type:`export_attempt`,threshold:1,message:`Export to Hamster Studio to enable coordinated team action, AI context sharing, and alignment in hours.`,promptType:`critical_choice`,showOnce:!1,cooldownDays:1,priority:100},{type:`no_connection`,threshold:1,message:`Connect to Hamster Studio to sync your tasks across devices and collaborate with your team.`,promptType:`upgrade_suggestion`,showOnce:!1,cooldownDays:3,priority:75},{type:`parse_prd`,threshold:1,message:`Export your PRD to Hamster for dynamic task generation and team collaboration.`,promptType:`critical_choice`,showOnce:!1,cooldownDays:1,priority:95}],Un=`1.0.0`,Wn=`upgradePrompts`;var Gn=class{logger=x(`PromptStateManager`);runtimeStateManager;cachedState=null;constructor(e){this.runtimeStateManager=new ut(e)}async getState(){return this.cachedState||=await this.loadState(),this.cachedState}async loadState(){try{await this.runtimeStateManager.loadState();let e=this.runtimeStateManager.getState().metadata?.[Wn];if(e&&typeof e==`object`)return this.validateAndMigrate(e)}catch(e){this.logger.warn(`Failed to load prompt state, using defaults:`,e)}return this.createDefaultState()}createDefaultState(){return{triggers:{},metrics:{totalTaskCount:0,tagCount:0,listCommandCount:0,tasksWithDependencies:0},lastUpdated:new Date().toISOString(),version:Un}}validateAndMigrate(e){return{triggers:e.triggers||{},metrics:{totalTaskCount:e.metrics?.totalTaskCount||0,tagCount:e.metrics?.tagCount||0,listCommandCount:e.metrics?.listCommandCount||0,tasksWithDependencies:e.metrics?.tasksWithDependencies||0,firstActivityAt:e.metrics?.firstActivityAt,lastActivityAt:e.metrics?.lastActivityAt},lastUpdated:e.lastUpdated||new Date().toISOString(),version:Un}}async saveState(){if(this.cachedState)try{this.cachedState.lastUpdated=new Date().toISOString(),await this.runtimeStateManager.updateMetadata({[Wn]:this.cachedState})}catch(e){throw this.logger.error(`Failed to save prompt state:`,e),e}}async getTriggerState(e){return(await this.getState()).triggers[e]||null}async recordPromptShown(e){let t=await this.getState(),n=new Date().toISOString(),r=t.triggers[e];t.triggers[e]={firstShownAt:r?.firstShownAt||n,lastShownAt:n,showCount:(r?.showCount||0)+1,dismissed:r?.dismissed||!1},await this.saveState()}async recordPromptAction(e,t){let n=await this.getState(),r=new Date().toISOString(),i=n.triggers[e]||{showCount:1,dismissed:!1};n.triggers[e]={...i,action:t,actionAt:r,dismissed:t===`dismissed`},await this.saveState()}async updateMetrics(e){let t=await this.getState(),n=new Date().toISOString();t.metrics.firstActivityAt||(t.metrics.firstActivityAt=n),t.metrics.lastActivityAt=n,Object.assign(t.metrics,e),await this.saveState()}async incrementMetric(e,t=1){let n=await this.getState();n.metrics[e]=(n.metrics[e]||0)+t,n.metrics.firstActivityAt||(n.metrics.firstActivityAt=new Date().toISOString()),n.metrics.lastActivityAt=new Date().toISOString(),await this.saveState()}async getMetrics(){return(await this.getState()).metrics}async isWithinCooldown(e,t){let n=await this.getTriggerState(e);if(!n?.lastShownAt)return!1;let r=new Date(n.lastShownAt),i=t*24*60*60*1e3;return Date.now()-r.getTime()<i}async isDismissed(e){return(await this.getTriggerState(e))?.dismissed||!1}async getDaysActive(){let e=await this.getState();if(!e.metrics.firstActivityAt)return 0;let t=new Date(e.metrics.firstActivityAt),n=Date.now();return Math.floor((n-t.getTime())/(1440*60*1e3))}async reset(){this.cachedState=this.createDefaultState(),await this.saveState()}async resetTrigger(e){let t=await this.getState();delete t.triggers[e],await this.saveState()}},Kn=class{stateManager;config;constructor(e,t){this.stateManager=e,this.config=t||{enabled:!0,triggers:Hn,defaultCooldownDays:7,respectDismissed:!0}}async evaluate(e={}){if(!this.config.enabled)return{shouldShow:!1,reason:`Prompts are disabled`};let t=await this.stateManager.getMetrics(),n=await this.stateManager.getDaysActive(),r=[...this.config.triggers].sort((e,t)=>t.priority-e.priority);for(let i of r){let r=await this.evaluateTrigger(i,t,n,e);if(r.shouldShow)return r}return{shouldShow:!1,reason:`No trigger conditions met`}}async evaluateTriggerType(e,t={}){let n=this.config.triggers.find(t=>t.type===e);if(!n)return{shouldShow:!1,reason:`Unknown trigger type: ${e}`};let r=await this.stateManager.getMetrics(),i=await this.stateManager.getDaysActive();return this.evaluateTrigger(n,r,i,t)}async evaluateTrigger(e,t,n,r){if(this.config.respectDismissed&&await this.stateManager.isDismissed(e.type))return{shouldShow:!1,trigger:e,reason:`Prompt was dismissed by user`};let i=e.cooldownDays??this.config.defaultCooldownDays;if(await this.stateManager.isWithinCooldown(e.type,i))return{shouldShow:!1,trigger:e,reason:`Within cooldown period (${i} days)`};if(e.showOnce){let t=await this.stateManager.getTriggerState(e.type);if(t&&t.showCount>0)return{shouldShow:!1,trigger:e,reason:`Prompt already shown (showOnce=true)`}}let a=this.evaluateThreshold(e,t,n,r);return a.met?{shouldShow:!0,trigger:e,reason:a.reason}:{shouldShow:!1,trigger:e,reason:a.reason}}evaluateThreshold(e,t,n,r){switch(e.type){case`task_count`:let i=t.totalTaskCount>=e.threshold;return{met:i,reason:i?`Task count ${t.totalTaskCount} >= ${e.threshold}`:`Task count ${t.totalTaskCount} < ${e.threshold}`};case`tags_used`:let a=t.tagCount>=e.threshold;return{met:a,reason:a?`Tag count ${t.tagCount} >= ${e.threshold}`:`Tag count ${t.tagCount} < ${e.threshold}`};case`list_count`:let o=t.listCommandCount>=e.threshold;return{met:o,reason:o?`List count ${t.listCommandCount} >= ${e.threshold}`:`List count ${t.listCommandCount} < ${e.threshold}`};case`dependencies_complex`:let s=t.tasksWithDependencies>=e.threshold;return{met:s,reason:s?`Tasks with dependencies ${t.tasksWithDependencies} >= ${e.threshold}`:`Tasks with dependencies ${t.tasksWithDependencies} < ${e.threshold}`};case`days_active`:let c=n>=e.threshold;return{met:c,reason:c?`Days active ${n} >= ${e.threshold}`:`Days active ${n} < ${e.threshold}`};case`export_attempt`:let l=r.currentCommand===`export`;return{met:l,reason:l?`User is attempting export`:`Not an export command`};case`no_connection`:let u=!r.isAuthenticated||!r.hasBriefConnected;return{met:u,reason:u?`No Hamster connection detected`:`User is connected to Hamster`};case`parse_prd`:let d=r.currentCommand===`parse-prd`;return{met:d,reason:d?`User is parsing a PRD`:`Not a parse-prd command`};default:return{met:!1,reason:`Unknown trigger type: ${e.type}`}}}getTriggers(){return this.config.triggers}getTrigger(e){return this.config.triggers.find(t=>t.type===e)}isEnabled(){return this.config.enabled}},qn=class{logger=x(`PromptService`);stateManager;evaluator;constructor(e,t){this.stateManager=new Gn(e),this.evaluator=new Kn(this.stateManager,t)}async evaluatePrompts(e={}){try{return await this.evaluator.evaluate(e)}catch(e){return this.logger.error(`Error evaluating prompts:`,e),{shouldShow:!1,reason:`Evaluation error: ${e.message}`}}}async evaluateTrigger(e,t={}){try{return await this.evaluator.evaluateTriggerType(e,t)}catch(t){return this.logger.error(`Error evaluating trigger ${e}:`,t),{shouldShow:!1,reason:`Evaluation error: ${t.message}`}}}async recordPromptShown(e){try{await this.stateManager.recordPromptShown(e),this.logger.debug(`Recorded prompt shown: ${e}`)}catch(e){this.logger.error(`Error recording prompt shown:`,e)}}async recordAction(e,t){try{await this.stateManager.recordPromptAction(e,t),this.logger.debug(`Recorded prompt action: ${e} -> ${t}`)}catch(e){this.logger.error(`Error recording prompt action:`,e)}}async updateMetrics(e){try{await this.stateManager.updateMetrics(e)}catch(e){this.logger.error(`Error updating metrics:`,e)}}async incrementMetric(e,t=1){try{await this.stateManager.incrementMetric(e,t)}catch(t){this.logger.error(`Error incrementing metric ${e}:`,t)}}async getMetrics(){return this.stateManager.getMetrics()}async dismissPrompt(e){await this.recordAction(e,`dismissed`)}isEnabled(){return this.evaluator.isEnabled()}getPromptMessage(e){return this.evaluator.getTrigger(e)?.message||null}async reset(){await this.stateManager.reset()}async resetTrigger(e){await this.stateManager.resetTrigger(e)}async syncMetrics(e){let t={};e.taskCount!==void 0&&(t.totalTaskCount=e.taskCount),e.tagCount!==void 0&&(t.tagCount=e.tagCount),e.tasksWithDependencies!==void 0&&(t.tasksWithDependencies=e.tasksWithDependencies),Object.keys(t).length>0&&await this.updateMetrics(t)}static buildContext(e){return{currentCommand:e.command,isAuthenticated:e.isAuthenticated,hasBriefConnected:e.hasBriefConnected,custom:e.custom}}};const Jn=[`add-task`,`analyze-complexity`,`expand-task`,`parse-prd`,`research`,`research-save`,`update-subtask`,`update-task`,`update-tasks`],Yn=`.taskmaster`,Xn=`.taskmaster/tasks`,Zn=`.taskmaster/docs`,Qn=`.taskmaster/reports`,$n=`.taskmaster/templates`,er=`.taskmaster/config.json`,tr=`.taskmaster/state.json`,z=`.taskmasterconfig`,nr=`.taskmaster/reports/task-complexity-report.json`,rr=`.taskmaster/docs/prd.txt`,ir=`.taskmaster/templates/example_prd.txt`,ar=`.taskmaster/tasks/tasks.json`,or=`tasks/tasks.json`,sr=`.env.example`,cr=`.gitignore`;let lr=!1;const ur={maxRetries:5,retryDelay:100,staleLockAge:1e4};function dr(e){if(typeof SharedArrayBuffer<`u`&&typeof Atomics<`u`&&typeof Atomics.wait==`function`)try{let t=new SharedArrayBuffer(4),n=new Int32Array(t);Atomics.wait(n,0,0,e);return}catch{}let t=Date.now()+e;for(;Date.now()<t;);}function fr(e,t,n={}){let{createIfMissing:r=!1}=n,i=c.dirname(e);if(s.existsSync(i)||s.mkdirSync(i,{recursive:!0}),r)try{s.writeFileSync(e,`{}`,{flag:`wx`})}catch(e){if(e.code!==`EEXIST`)throw e}let a=`${e}.lock`,{maxRetries:o,retryDelay:l,staleLockAge:u}=ur,d=!1;for(let e=0;e<o;e++)try{let e=JSON.stringify({pid:process.pid,timestamp:Date.now()});s.writeFileSync(a,e,{flag:`wx`}),d=!0;break}catch(t){if(t.code===`EEXIST`){try{let e=s.statSync(a);if(Date.now()-e.mtimeMs>u){let e=`${a}.stale.${process.pid}.${Date.now()}`;try{s.renameSync(a,e);try{s.unlinkSync(e)}catch{}continue}catch{}}}catch(e){if(e.code===`ENOENT`)continue;throw e}e<o-1&&dr(l*2**e)}else throw t}if(!d)throw Error(`Failed to acquire lock on ${e} after ${o} attempts`);try{return t()}finally{try{s.unlinkSync(a)}catch(t){U(`warn`,`Failed to release lock for ${e}: ${t.message}`)}}}function B(e,t=null,n=null){if(t?.env?.[e])return t.env[e];if(n){let t=c.join(n,`.env`);if(s.existsSync(t))try{let n=s.readFileSync(t,`utf-8`),r=ve.parse(n);if(r&&r[e])return r[e]}catch(e){U(`warn`,`Could not read or parse ${t}: ${e.message}`)}}if(process.env[e])return process.env[e]}function V(e=process.cwd(),t=[`package.json`,`pyproject.toml`,`.git`,z]){let n=c.resolve(e),r=c.parse(n).root;for(;n!==r;){if(t.some(e=>{let t=c.join(n,e);return s.existsSync(t)}))return n;n=c.dirname(n)}return t.some(e=>{let t=c.join(r,e);return s.existsSync(t)})?r:null}const H={debug:0,info:1,warn:2,error:3,success:1};function pr(){lr=!0}function mr(){lr=!1}function hr(){return lr}function U(e,...t){if(hr())return;let n=`info`;try{n=gi()||`info`}catch{n=`info`}let r={debug:i.gray(`[DEBUG]`),info:i.blue(`[INFO]`),warn:i.yellow(`[WARN]`),error:i.red(`[ERROR]`),success:i.green(`[SUCCESS]`)},a=H.hasOwnProperty(e)?e:`info`;if(H[a]>=(H[n]??H.info)){let e=r[a]||``,n=t.map(e=>typeof e==`object`?JSON.stringify(e):e).join(` `);console.log(`${e} ${n}`)}}function gr(e){if(!e||typeof e!=`object`)return!1;for(let t in e)if(e.hasOwnProperty(t)&&typeof e[t]==`object`&&Array.isArray(e[t].tasks))return!0;return!1}function W(e){Array.isArray(e)&&e.forEach(e=>{if(e.id!==void 0){let t=parseInt(e.id,10);!isNaN(t)&&t>0&&(e.id=t)}Array.isArray(e.subtasks)&&e.subtasks.forEach(e=>{if(e.id!==void 0)if(typeof e.id==`string`&&e.id.includes(`.`)){let t=e.id.split(`.`);e.id=parseInt(t[t.length-1],10)}else{let t=parseInt(e.id,10);!isNaN(t)&&t>0&&(e.id=t)}})})}function _r(t,n=null,r=null){let i=!1;try{i=$()}catch{}if(i&&console.log(`readJSON called with: ${t}, projectRoot: ${n}, tag: ${r}`),!t)return null;let a;try{a=JSON.parse(s.readFileSync(t,`utf8`)),i&&console.log(`Successfully read JSON from ${t}`)}catch(e){return i&&console.log(`Failed to read JSON from ${t}: ${e.message}`),null}if(!t.includes(`tasks.json`)||!a)return i&&console.log(`File is not tasks.json or data is null, returning as-is`),a;if(Array.isArray(a.tasks)&&!a._rawTaggedData&&!gr(a)){i&&console.log(`File is in legacy format, performing migration...`),W(a.tasks);let r={master:{tasks:a.tasks,metadata:a.metadata||{created:new Date().toISOString(),updated:new Date().toISOString(),description:`Tasks for master context`}}};try{if(Sr(t,r),i&&console.log(`Successfully migrated legacy format to tagged format`),vr(t),n)try{e(n,t)}catch{}xr(t)}catch(e){i&&console.log(`Error writing migrated data: ${e.message}`)}a=r}if(typeof a==`object`&&!a.tasks){for(let e in i&&console.log(`File is in tagged format, resolving tag...`),a)if(a.hasOwnProperty(e)&&typeof a[e]==`object`&&a[e].tasks)try{Rr(a[e],{description:`Tasks for ${e} context`,skipUpdate:!0})}catch(t){i&&console.log(`Failed to ensure metadata for tag ${e}: ${t.message}`)}let o=JSON.parse(JSON.stringify(a));for(let e in o)o[e]&&Array.isArray(o[e].tasks)&&W(o[e].tasks);if(n)try{e(n,t)}catch{}try{let e=`master`;try{if(r)e=r;else if(n)e=Fr({projectRoot:n});else{let n=V(c.dirname(t));n&&(e=Fr({projectRoot:n}))}}catch(e){i&&console.log(`Tag resolution failed, using master: ${e.message}`)}i&&console.log(`Resolved tag: ${e}`);let s=a[e];if(s&&s.tasks){W(s.tasks);let t={...s,tag:e,_rawTaggedData:o};return i&&console.log(`Returning data for tag '${e}' with ${s.tasks.length} tasks`),t}else{let t=a.master;return t&&t.tasks?(W(t.tasks),i&&console.log(`Tag '${e}' not found, falling back to master with ${t.tasks.length} tasks`),{...t,tag:`master`,_rawTaggedData:o}):(i&&console.log(`No valid tag data found, returning empty structure`),{tasks:[],tag:`master`,_rawTaggedData:o})}}catch(e){i&&console.log(`Error during tag resolution: ${e.message}`);let t=a.master;return t&&t.tasks?(W(t.tasks),{...t,_rawTaggedData:o}):{tasks:[],_rawTaggedData:o}}}return i&&console.log(`File format not recognized, returning as-is`),a}function vr(e){try{let t=V(c.dirname(e))||c.dirname(e),n=c.join(t,`.taskmaster`,`config.json`);s.existsSync(n)&&yr(n);let r=c.join(t,`.taskmaster`,`state.json`);s.existsSync(r)||br(r),$()&&U(`debug`,`Complete tag migration performed for project: ${t}`)}catch(e){$()&&U(`warn`,`Error during complete tag migration: ${e.message}`)}}function yr(e){try{let t=s.readFileSync(e,`utf8`),n=JSON.parse(t);if(!n)return;let r=!1;n.global||={},n.global.defaultTag||(n.global.defaultTag=`master`,r=!0),r&&(s.writeFileSync(e,JSON.stringify(n,null,2),`utf8`),process.env.TASKMASTER_DEBUG===`true`&&console.log(`[DEBUG] Updated config.json with tagged task system settings`))}catch(e){process.env.TASKMASTER_DEBUG===`true`&&console.warn(`[WARN] Error migrating config.json: ${e.message}`)}}function br(e){try{let t={currentTag:`master`,lastSwitched:new Date().toISOString(),branchTagMapping:{},migrationNoticeShown:!1};s.writeFileSync(e,JSON.stringify(t,null,2),`utf8`),process.env.TASKMASTER_DEBUG===`true`&&console.log(`[DEBUG] Created initial state.json for tagged task system`)}catch(e){process.env.TASKMASTER_DEBUG===`true`&&console.warn(`[WARN] Error creating state.json: ${e.message}`)}}function xr(e){try{let t=c.dirname(c.dirname(e)),n=c.join(t,`.taskmaster`,`state.json`);s.existsSync(n)||br(n);try{let e=s.readFileSync(n,`utf8`),t=JSON.parse(e)||{};t.migrationNoticeShown===void 0&&(t.migrationNoticeShown=!1,s.writeFileSync(n,JSON.stringify(t,null,2),`utf8`))}catch(e){process.env.TASKMASTER_DEBUG===`true`&&console.warn(`[WARN] Error updating state for migration notice: ${e.message}`)}}catch(e){process.env.TASKMASTER_DEBUG===`true`&&console.warn(`[WARN] Error marking migration for notice: ${e.message}`)}}function Sr(e,t,n=null,r=null){let i=process.env.TASKMASTER_DEBUG===`true`;try{fr(e,()=>{let a=t;if(t&&!t._rawTaggedData&&n&&Array.isArray(t.tasks)&&!gr(t)){let o=r||Pr(n);i&&console.log(`writeJSON: Detected resolved tag data missing _rawTaggedData. Re-reading raw data to prevent data loss for tag '${o}'.`);let c={};try{c=JSON.parse(s.readFileSync(e,`utf8`))}catch(e){i&&console.log(`writeJSON: Could not read existing file, starting fresh: ${e.message}`)}a={...c,[o]:{metadata:{...c[o]?.metadata||{},...t.metadata||{}},tasks:t.tasks}}}else if(t&&t._rawTaggedData&&n){let o=r||Pr(n),c;try{c=JSON.parse(s.readFileSync(e,`utf8`))}catch(e){c=t._rawTaggedData,i&&console.log(`writeJSON: Using _rawTaggedData as fallback: ${e.message}`)}let{_rawTaggedData:l,tag:u,...d}=t;a={...c,[o]:d},i&&console.log(`writeJSON: Merging resolved data back into tag '${o}'`)}let o=a;if(o&&typeof o==`object`){let{_rawTaggedData:e,tag:t,...n}=o;if(o=n,typeof o==`object`&&!Array.isArray(o)){let e={};for(let[t,n]of Object.entries(o))if(n&&typeof n==`object`&&Array.isArray(n.tasks)){let{created:r,description:i,...a}=n;a.metadata||={},r&&!a.metadata.created&&(a.metadata.created=r),i&&!a.metadata.description&&(a.metadata.description=i),e[t]=a}else e[t]=n;o=e}}let c=`${e}.tmp.${process.pid}`;try{s.writeFileSync(c,JSON.stringify(o,null,2),`utf8`),s.renameSync(c,e)}catch(e){try{s.existsSync(c)&&s.unlinkSync(c)}catch{}throw e}i&&console.log(`writeJSON: Successfully wrote to ${e}`)},{createIfMissing:!0})}catch(t){throw U(`error`,`Error writing JSON file ${e}:`,t.message),i&&U(`error`,`Full error details:`,t),t}}function Cr(e=null){let t=!1;try{t=$()}catch{t=!1}try{let n;if(e)n=e;else{let e=c.join(process.cwd(),nr),t=c.join(process.cwd(),`scripts/task-complexity-report.json`);n=s.existsSync(e)?e:t}if(!s.existsSync(n))return t&&U(`debug`,`Complexity report not found at ${n}`),null;let r=_r(n);return t&&U(`debug`,`Successfully read complexity report from ${n}`),r}catch(e){return t&&U(`error`,`Error reading complexity report: ${e.message}`),null}}function wr(e,t){return!e||!e.complexityAnalysis||!Array.isArray(e.complexityAnalysis)?null:e.complexityAnalysis.find(e=>e.taskId===t)}function Tr(e,t){let n;n=e.isSubtask?e.parentTask.id:e.parentId?e.parentId:e.id;let r=wr(t,n);r&&(e.complexityScore=r.complexityScore)}function Er(e,t){if(!t||!e||!Array.isArray(e))return!1;if(typeof t==`string`&&t.includes(`.`)){let[n,r]=t.split(`.`).map(e=>parseInt(e,10)),i=e.find(e=>e.id===n);return!i||!i.subtasks?!1:i.subtasks.some(e=>e.id===r)}let n=parseInt(t,10);return e.some(e=>e.id===n)}function Dr(e){return typeof e==`string`&&e.includes(`.`)?e:typeof e==`number`?e.toString():e}function Or(e,t,n=null,r=null){if(!t||!e||!Array.isArray(e))return{task:null,originalSubtaskCount:null};if(typeof t==`string`&&t.includes(`.`)){let[r,i]=t.split(`.`).map(e=>parseInt(e,10)),a=e.find(e=>e.id===r);if(!a||!a.subtasks)return{task:null,originalSubtaskCount:null,originalSubtasks:null};let o=a.subtasks.find(e=>e.id===i);return o&&(o.parentTask={id:a.id,title:a.title,status:a.status},o.isSubtask=!0),o&&n&&Tr(o,n),{task:o||null,originalSubtaskCount:null,originalSubtasks:null}}let i=null,a=null,o=null,s=parseInt(t,10),c=e.find(e=>e.id===s)||null;if(!c)return{task:null,originalSubtaskCount:null,originalSubtasks:null};if(i=c,r&&c.subtasks&&Array.isArray(c.subtasks)){o=[...c.subtasks],a=c.subtasks.length;let e={...c};e.subtasks=c.subtasks.filter(e=>e.status&&e.status.toLowerCase()===r.toLowerCase()),i=e}return i&&n&&Tr(i,n),{task:i,originalSubtaskCount:a,originalSubtasks:o}}function kr(e,t){return!e||e.length<=t?e:`${e.slice(0,t-3)}...`}function Ar(e){return Array.isArray(e)?e.length===0:typeof e==`object`&&e?Object.keys(e).length===0:!1}function jr(e,t,n=new Set,r=new Set,i=[]){n.add(e),r.add(e),i.push(e);let a=[],o=t.get(e)||[];for(let e of o)if(n.has(e)){if(r.has(e)){let t=i.indexOf(e);i.slice(t),a.push(e)}}else{let o=jr(e,t,n,r,[...i]);a.push(...o)}return r.delete(e),a}function Mr(e,t,n={}){let{maxDepth:r=50,includeSelf:i=!1,direction:a=`forward`,logger:o=null}=n,s=new Set,c=new Set;function l(e){if(typeof e==`string`){if(e.includes(`.`))return e;let t=parseInt(e,10);return isNaN(t)?e:t}return e}function u(e,n=0){if(n>=r){let t=`Maximum recursion depth (${r}) reached for task ${e}`;o&&typeof o.warn==`function`?o.warn(t):U!==void 0&&U.warn?U.warn(t):console.warn(t);return}if(c.has(e))return;c.add(e);let a=t.find(t=>t.id===e);!a||!Array.isArray(a.dependencies)||a.dependencies.forEach(t=>{let r=l(t);r==null||!i&&r===e||(s.add(r),u(r,n+1))})}function d(e,n=0){if(n>=r){let t=`Maximum recursion depth (${r}) reached for task ${e}`;o&&typeof o.warn==`function`?o.warn(t):U!==void 0&&U.warn?U.warn(t):console.warn(t);return}c.has(e)||(c.add(e),t.forEach(t=>{if(t.dependencies&&Array.isArray(t.dependencies)&&t.dependencies.some(t=>l(t)===e)){if(t.id==null||!i&&t.id===e)return;s.add(t.id),d(t.id,n+1)}}))}let f=a===`reverse`?d:u;return e.forEach(e=>{e&&e.id&&f(e.id)}),Array.from(s)}function Nr(e,t){if(!e||e.length===0)return null;let n={timestamp:new Date().toISOString(),userId:e[0].userId,commandName:t,modelUsed:`Multiple`,providerName:`Multiple`,inputTokens:0,outputTokens:0,totalTokens:0,totalCost:0,currency:e[0].currency||`USD`},r=new Set,i=new Set,a=new Set;return e.forEach(e=>{n.inputTokens+=e.inputTokens||0,n.outputTokens+=e.outputTokens||0,n.totalCost+=e.totalCost||0,r.add(e.modelUsed),i.add(e.providerName),a.add(e.currency||`USD`)}),n.totalTokens=n.inputTokens+n.outputTokens,n.totalCost=parseFloat(n.totalCost.toFixed(6)),r.size===1&&(n.modelUsed=[...r][0]),i.size===1&&(n.providerName=[...i][0]),a.size>1?n.currency=`Multiple`:a.size===1&&(n.currency=[...a][0]),n}function Pr(e){if(!e)throw Error(`projectRoot is required for getCurrentTag`);try{let t=c.join(e,`.taskmaster`,`state.json`);if(s.existsSync(t)){let e=s.readFileSync(t,`utf8`),n=JSON.parse(e);if(n&&n.currentTag)return n.currentTag}}catch{}try{let t=c.join(e,`.taskmaster`,`config.json`);if(s.existsSync(t)){let e=s.readFileSync(t,`utf8`),n=JSON.parse(e);if(n&&n.global&&n.global.defaultTag)return n.global.defaultTag}}catch{}return`master`}function Fr(e={}){let{projectRoot:t,tag:n}=e;if(!t)throw Error(`projectRoot is required for resolveTag`);return n||Pr(t)}function Ir(e,t){return!e||!t?[]:e[t]&&e[t].tasks&&Array.isArray(e[t].tasks)?e[t].tasks:[]}function Lr(e){let t=[];for(let n of e)if(t.push({...n,searchableId:n.id.toString(),isSubtask:!1}),n.subtasks&&n.subtasks.length>0)for(let e of n.subtasks)t.push({...e,searchableId:`${n.id}.${e.id}`,isSubtask:!0,parentId:n.id,parentTitle:n.title,title:`${e.title} (subtask of: ${n.title})`,description:`${e.description} [Parent: ${n.description}]`});return t}function Rr(e,t={}){if(!e||typeof e!=`object`)throw Error(`tagObj must be a valid object`);let n=new Date().toISOString();return e.metadata?(e.metadata.created||(e.metadata.created=n),t.skipUpdate||(e.metadata.updated=n),t.description&&!e.metadata.description&&(e.metadata.description=t.description)):e.metadata={created:n,updated:n,...t.description?{description:t.description}:{}},e}function zr(){return{info:(e,...t)=>U(`info`,e,...t),warn:(e,...t)=>U(`warn`,e,...t),error:(e,...t)=>U(`error`,e,...t),debug:(e,...t)=>U(`debug`,e,...t),success:(e,...t)=>U(`success`,e,...t)}}function G(e=null){return e||zr()}function K(e){return vn(e)}function q(e=process.cwd()){return _n(e)}function Br(e=null,t=null,n=null){let r=G(n),i=t?.projectRoot||q();if(!i)return r.warn?.(`Could not determine project root directory`),null;let a=K(i);if(e){let t=c.isAbsolute(e)?e:c.resolve(a,e);if(s.existsSync(t))return r.info?.(`Using explicit tasks path: ${t}`),t;r.warn?.(`Explicit tasks path not found: ${t}, trying fallbacks`)}let o=[c.join(a,ar),c.join(a,or)];for(let e of o)if(s.existsSync(e))return r.info?.(`Found tasks file at: ${e}`),e.includes(`tasks/tasks.json`)&&!e.includes(`.taskmaster`)?r.warn?.(`⚠️ DEPRECATION WARNING: Found tasks.json in legacy location '${e}'. Please migrate to the new .taskmaster directory structure. Run 'task-master migrate' to automatically migrate your project.`):e.endsWith(`tasks.json`)&&!e.includes(`.taskmaster`)&&!e.includes(`tasks/`)&&r.warn?.(`⚠️ DEPRECATION WARNING: Found tasks.json in legacy root location '${e}'. Please migrate to the new .taskmaster directory structure. Run 'task-master migrate' to automatically migrate your project.`),e;return r.warn?.(`No tasks.json found in project: ${a}`),null}function Vr(e=null,t=null,n=null){let r=G(n);if(e){let t=process.env.TASKMASTER_ORIGINAL_CWD||process.cwd(),n=c.isAbsolute(e)?e:c.resolve(t,e);if(s.existsSync(n))return r.info?.(`Using explicit PRD path: ${n}`),n;r.warn?.(`Explicit PRD path not found: ${n}, trying fallbacks`)}let i=t?.projectRoot||q();if(!i)return r.warn?.(`Could not determine project root directory`),null;let a=K(i),o=[Zn,`scripts/`,``],l=[`PRD.md`,`prd.md`,`PRD.txt`,`prd.txt`];for(let e of o)for(let t of l){let n=c.join(a,e,t);if(s.existsSync(n))return r.info?.(`Found PRD document at: ${n}`),(e===`scripts/`||e===``)&&r.warn?.(`⚠️ DEPRECATION WARNING: Found PRD file in legacy location '${n}'. Please migrate to .taskmaster/docs/ directory. Run 'task-master migrate' to automatically migrate your project.`),n}return r.warn?.(`No PRD document found in project: ${a}`),null}function Hr(e=null,t=null,n=null){let r=G(n);if(e){let t=process.env.TASKMASTER_ORIGINAL_CWD||process.cwd(),n=c.isAbsolute(e)?e:c.resolve(t,e);if(s.existsSync(n))return r.info?.(`Using explicit complexity report path: ${n}`),n;r.warn?.(`Explicit complexity report path not found: ${n}, trying fallbacks`)}let i=t?.projectRoot||q();if(!i)return r.warn?.(`Could not determine project root directory`),null;let a=K(i),o=[Qn,`scripts/`,``],l=[`task-complexity-report`,`task-complexity`,`complexity-report`].map(e=>t?.tag&&t?.tag!==`master`?`${e}_${t.tag}.json`:`${e}.json`);for(let e of o)for(let t of l){let n=c.join(a,e,t);if(s.existsSync(n))return r.info?.(`Found complexity report at: ${n}`),(e===`scripts/`||e===``)&&r.warn?.(`⚠️ DEPRECATION WARNING: Found complexity report in legacy location '${n}'. Please migrate to .taskmaster/reports/ directory. Run 'task-master migrate' to automatically migrate your project.`),n}return r.warn?.(`No complexity report found in project: ${a}`),null}function Ur(e=null,t=null,n=null){let r=G(n),i=t?.tag;if(e){let t=process.env.TASKMASTER_ORIGINAL_CWD||process.cwd(),n=c.isAbsolute(e)?e:c.resolve(t,e);return r.info?.(`Using explicit complexity report output path: ${n}`),n}let a=K(t?.projectRoot||q()||process.cwd()),o=`task-complexity-report.json`;i&&i!==`master`&&(o=`task-complexity-report_${i}.json`);let l=c.join(a,`.taskmaster/reports`,o);r.info?.(`Using tag-aware complexity report output path: ${l}`);let u=c.dirname(l);return s.existsSync(u)||(r.info?.(`Creating reports directory: ${u}`),s.mkdirSync(u,{recursive:!0})),l}function Wr(e=null,t=null,n=null){let r=G(n);if(e){let t=process.env.TASKMASTER_ORIGINAL_CWD||process.cwd(),n=c.isAbsolute(e)?e:c.resolve(t,e);if(s.existsSync(n))return r.info?.(`Using explicit config path: ${n}`),n;r.warn?.(`Explicit config path not found: ${n}, trying fallbacks`)}let i=t?.projectRoot||q();if(!i)return r.warn?.(`Could not determine project root directory`),null;let a=K(i),o=[c.join(a,er),c.join(a,z)];for(let e of o)if(s.existsSync(e))return e?.endsWith(z)&&r.warn?.(`⚠️ DEPRECATION WARNING: Found configuration in legacy location '${e}'. Please migrate to .taskmaster/config.json. Run 'task-master migrate' to automatically migrate your project.`),e;if(!(Yr()||t?.storageType===`api`)){let e=`config_warning_${a}`;global._tmConfigWarningsThisRun||(global._tmConfigWarningsThisRun=new Set),global._tmConfigWarningsThisRun.has(e)||(global._tmConfigWarningsThisRun.add(e),r.warn?.(`No configuration file found in project: ${a}`))}return null}var J={anthropic:[{id:`claude-sonnet-4-20250514`,swe_score:.727,cost_per_1m_tokens:{input:3,output:15},allowed_roles:[`main`,`fallback`],max_tokens:64e3,supported:!0},{id:`claude-opus-4-20250514`,swe_score:.725,cost_per_1m_tokens:{input:15,output:75},allowed_roles:[`main`,`fallback`],max_tokens:32e3,supported:!0},{id:`claude-3-7-sonnet-20250219`,swe_score:.623,cost_per_1m_tokens:{input:3,output:15},allowed_roles:[`main`,`fallback`],max_tokens:12e4,supported:!0},{id:`claude-3-5-sonnet-20241022`,swe_score:.49,cost_per_1m_tokens:{input:3,output:15},allowed_roles:[`main`,`fallback`],max_tokens:8192,supported:!0},{id:`claude-sonnet-4-5`,name:`Claude Sonnet 4.5`,swe_score:.772,cost_per_1m_tokens:{input:3,output:15},allowed_roles:[`main`,`fallback`],max_tokens:64e3,supported:!0},{id:`claude-haiku-4-5`,name:`Claude Haiku 4.5`,swe_score:.733,cost_per_1m_tokens:{input:1,output:5},allowed_roles:[`main`,`fallback`],max_tokens:2e5,supported:!0},{id:`claude-opus-4-1`,name:`Claude Opus 4.1`,swe_score:.745,cost_per_1m_tokens:{input:15,output:75},allowed_roles:[`main`,`fallback`],max_tokens:32e3,supported:!0},{id:`claude-opus-4-5`,name:`Claude Opus 4.5`,swe_score:.809,cost_per_1m_tokens:{input:5,output:25},allowed_roles:[`main`,`fallback`],max_tokens:32e3,supported:!0}],"claude-code":[{id:`opus`,swe_score:.725,cost_per_1m_tokens:{input:0,output:0},allowed_roles:[`main`,`fallback`,`research`],max_tokens:32e3,supported:!0},{id:`sonnet`,swe_score:.727,cost_per_1m_tokens:{input:0,output:0},allowed_roles:[`main`,`fallback`,`research`],max_tokens:64e3,supported:!0},{id:`haiku`,swe_score:.45,cost_per_1m_tokens:{input:0,output:0},allowed_roles:[`main`,`fallback`,`research`],max_tokens:2e5,supported:!0}],"codex-cli":[{id:`gpt-5.3-codex`,name:`GPT-5.3 Codex`,swe_score:.84,cost_per_1m_tokens:{input:0,output:0},allowed_roles:[`main`,`fallback`,`research`],max_tokens:128e3,reasoning_efforts:[`none`,`low`,`medium`,`high`,`xhigh`],supported:!0},{id:`gpt-5.2-codex`,name:`GPT-5.2 Codex`,swe_score:.82,cost_per_1m_tokens:{input:0,output:0},allowed_roles:[`main`,`fallback`,`research`],max_tokens:128e3,reasoning_efforts:[`none`,`low`,`medium`,`high`,`xhigh`],supported:!0},{id:`gpt-5.1-codex-max`,name:`GPT-5.1 Codex Max`,swe_score:.78,cost_per_1m_tokens:{input:0,output:0},allowed_roles:[`main`,`fallback`,`research`],max_tokens:128e3,reasoning_efforts:[`none`,`low`,`medium`,`high`,`xhigh`],supported:!0},{id:`gpt-5.1-codex-mini`,name:`GPT-5.1 Codex Mini`,swe_score:.72,cost_per_1m_tokens:{input:0,output:0},allowed_roles:[`main`,`fallback`,`research`],max_tokens:128e3,reasoning_efforts:[`none`,`low`,`medium`,`high`],supported:!0},{id:`gpt-5.2`,name:`GPT-5.2`,swe_score:.8,cost_per_1m_tokens:{input:0,output:0},allowed_roles:[`main`,`fallback`,`research`],max_tokens:128e3,reasoning_efforts:[`none`,`low`,`medium`,`high`,`xhigh`],supported:!0}],mcp:[{id:`mcp-sampling`,swe_score:null,cost_per_1m_tokens:{input:0,output:0},allowed_roles:[`main`,`fallback`,`research`],max_tokens:1e5,supported:!0}],"gemini-cli":[{id:`gemini-3-flash-preview`,name:`Gemini 3 Flash`,swe_score:0,cost_per_1m_tokens:{input:0,output:0},allowed_roles:[`main`,`fallback`,`research`],max_tokens:1048576,supported:!0},{id:`gemini-3-pro-preview`,swe_score:.762,cost_per_1m_tokens:{input:0,output:0},allowed_roles:[`main`,`fallback`,`research`],max_tokens:65536,supported:!0},{id:`gemini-2.5-pro`,swe_score:.72,cost_per_1m_tokens:{input:0,output:0},allowed_roles:[`main`,`fallback`,`research`],max_tokens:65536,supported:!0},{id:`gemini-2.5-flash`,swe_score:.71,cost_per_1m_tokens:{input:0,output:0},allowed_roles:[`main`,`fallback`,`research`],max_tokens:65536,supported:!0}],"grok-cli":[{id:`grok-4-latest`,name:`Grok 4 Latest`,swe_score:.7,cost_per_1m_tokens:{input:0,output:0},allowed_roles:[`main`,`fallback`,`research`],max_tokens:131072,supported:!0},{id:`grok-3-latest`,name:`Grok 3 Latest`,swe_score:.65,cost_per_1m_tokens:{input:0,output:0},allowed_roles:[`main`,`fallback`,`research`],max_tokens:131072,supported:!0},{id:`grok-3-fast`,name:`Grok 3 Fast`,swe_score:.6,cost_per_1m_tokens:{input:0,output:0},allowed_roles:[`main`,`fallback`,`research`],max_tokens:131072,supported:!0},{id:`grok-3-mini-fast`,name:`Grok 3 Mini Fast`,swe_score:.55,cost_per_1m_tokens:{input:0,output:0},allowed_roles:[`main`,`fallback`,`research`],max_tokens:32768,supported:!0}],openai:[{id:`gpt-4o`,swe_score:.332,cost_per_1m_tokens:{input:2.5,output:10},allowed_roles:[`main`,`fallback`],max_tokens:16384,supported:!0},{id:`o1`,swe_score:.489,cost_per_1m_tokens:{input:15,output:60},allowed_roles:[`main`],supported:!0},{id:`o3`,swe_score:.5,cost_per_1m_tokens:{input:2,output:8},allowed_roles:[`main`,`fallback`],max_tokens:1e5,supported:!0},{id:`o3-mini`,swe_score:.493,cost_per_1m_tokens:{input:1.1,output:4.4},allowed_roles:[`main`],max_tokens:1e5,supported:!0},{id:`o4-mini`,swe_score:.45,cost_per_1m_tokens:{input:1.1,output:4.4},allowed_roles:[`main`,`fallback`],supported:!0},{id:`o1-mini`,swe_score:.4,cost_per_1m_tokens:{input:1.1,output:4.4},allowed_roles:[`main`],supported:!0},{id:`o1-pro`,swe_score:0,cost_per_1m_tokens:{input:150,output:600},allowed_roles:[`main`],supported:!0},{id:`gpt-4-5-preview`,swe_score:.38,cost_per_1m_tokens:{input:75,output:150},allowed_roles:[`main`],supported:!0},{id:`gpt-4-1-mini`,swe_score:0,cost_per_1m_tokens:{input:.4,output:1.6},allowed_roles:[`main`],supported:!0},{id:`gpt-4-1-nano`,swe_score:0,cost_per_1m_tokens:{input:.1,output:.4},allowed_roles:[`main`],supported:!0},{id:`gpt-4o-mini`,swe_score:.3,cost_per_1m_tokens:{input:.15,output:.6},allowed_roles:[`main`],supported:!0},{id:`gpt-4o-search-preview`,swe_score:.33,cost_per_1m_tokens:{input:2.5,output:10},allowed_roles:[`research`],supported:!0},{id:`gpt-4o-mini-search-preview`,swe_score:.3,cost_per_1m_tokens:{input:.15,output:.6},allowed_roles:[`research`],supported:!0},{id:`gpt-5`,swe_score:.749,cost_per_1m_tokens:{input:5,output:20},allowed_roles:[`main`,`fallback`],max_tokens:1e5,temperature:1,supported:!0},{id:`gpt-5.1`,swe_score:.76,cost_per_1m_tokens:{input:1.25,output:10},allowed_roles:[`main`,`fallback`],max_tokens:128e3,reasoning_efforts:[`none`,`low`,`medium`,`high`],supported:!0},{id:`gpt-5.1-codex-max`,swe_score:.78,cost_per_1m_tokens:{input:1.25,output:10},allowed_roles:[`main`,`fallback`],max_tokens:128e3,reasoning_efforts:[`none`,`low`,`medium`,`high`,`xhigh`],supported:!0},{id:`gpt-5.2`,swe_score:.8,cost_per_1m_tokens:{input:1.75,output:14},allowed_roles:[`main`,`fallback`],max_tokens:128e3,reasoning_efforts:[`none`,`low`,`medium`,`high`,`xhigh`],supported:!0},{id:`gpt-5.2-pro`,swe_score:.82,cost_per_1m_tokens:{input:21,output:168},allowed_roles:[`main`,`fallback`],max_tokens:128e3,reasoning_efforts:[`medium`,`high`,`xhigh`],supported:!0}],google:[{id:`gemini-3-flash-preview`,name:`Gemini 3 Flash`,swe_score:0,cost_per_1m_tokens:{input:.5,output:3},allowed_roles:[`main`,`fallback`],max_tokens:1048576,supported:!0},{id:`gemini-3-pro-preview`,swe_score:.762,cost_per_1m_tokens:{input:2,output:12},allowed_roles:[`main`,`fallback`,`research`],max_tokens:1e6,supported:!0},{id:`gemini-2.5-pro-preview-05-06`,swe_score:.638,cost_per_1m_tokens:null,allowed_roles:[`main`,`fallback`],max_tokens:1048e3,supported:!0},{id:`gemini-2.5-pro-preview-03-25`,swe_score:.638,cost_per_1m_tokens:null,allowed_roles:[`main`,`fallback`],max_tokens:1048e3,supported:!0},{id:`gemini-2.5-flash-preview-04-17`,swe_score:.604,cost_per_1m_tokens:null,allowed_roles:[`main`,`fallback`],max_tokens:1048e3,supported:!0},{id:`gemini-2.0-flash`,swe_score:.518,cost_per_1m_tokens:{input:.15,output:.6},allowed_roles:[`main`,`fallback`],max_tokens:1048e3,supported:!0},{id:`gemini-2.0-flash-lite`,swe_score:0,cost_per_1m_tokens:null,allowed_roles:[`main`,`fallback`],max_tokens:1048e3,supported:!0}],xai:[{id:`grok-3`,name:`Grok 3`,swe_score:null,cost_per_1m_tokens:{input:3,output:15},allowed_roles:[`main`,`fallback`,`research`],max_tokens:131072,supported:!0},{id:`grok-3-fast`,name:`Grok 3 Fast`,swe_score:0,cost_per_1m_tokens:{input:5,output:25},allowed_roles:[`main`,`fallback`,`research`],max_tokens:131072,supported:!0},{id:`grok-4`,name:`Grok 4`,swe_score:null,cost_per_1m_tokens:{input:3,output:15},allowed_roles:[`main`,`fallback`,`research`],max_tokens:131072,supported:!0}],groq:[{id:`moonshotai/kimi-k2-instruct`,swe_score:.66,cost_per_1m_tokens:{input:1,output:3},allowed_roles:[`main`,`fallback`],max_tokens:16384,supported:!0},{id:`llama-3.3-70b-versatile`,swe_score:.55,cost_per_1m_tokens:{input:.59,output:.79},allowed_roles:[`main`,`fallback`,`research`],max_tokens:32768,supported:!0},{id:`llama-3.1-8b-instant`,swe_score:.32,cost_per_1m_tokens:{input:.05,output:.08},allowed_roles:[`main`,`fallback`],max_tokens:131072,supported:!0},{id:`llama-4-scout`,swe_score:.45,cost_per_1m_tokens:{input:.11,output:.34},allowed_roles:[`main`,`fallback`,`research`],max_tokens:32768,supported:!0},{id:`llama-4-maverick`,swe_score:.52,cost_per_1m_tokens:{input:.5,output:.77},allowed_roles:[`main`,`fallback`,`research`],max_tokens:32768,supported:!0},{id:`mixtral-8x7b-32768`,swe_score:.35,cost_per_1m_tokens:{input:.24,output:.24},allowed_roles:[`main`,`fallback`],max_tokens:32768,supported:!0},{id:`qwen-qwq-32b-preview`,swe_score:.4,cost_per_1m_tokens:{input:.18,output:.18},allowed_roles:[`main`,`fallback`,`research`],max_tokens:32768,supported:!0},{id:`deepseek-r1-distill-llama-70b`,swe_score:.52,cost_per_1m_tokens:{input:.75,output:.99},allowed_roles:[`main`,`research`],max_tokens:8192,supported:!0},{id:`gemma2-9b-it`,swe_score:.3,cost_per_1m_tokens:{input:.2,output:.2},allowed_roles:[`main`,`fallback`],max_tokens:8192,supported:!0},{id:`whisper-large-v3`,swe_score:0,cost_per_1m_tokens:{input:.11,output:0},allowed_roles:[`main`],max_tokens:0,supported:!0}],perplexity:[{id:`sonar-pro`,swe_score:0,cost_per_1m_tokens:{input:3,output:15},allowed_roles:[`main`,`research`],max_tokens:8700,supported:!0},{id:`sonar`,swe_score:0,cost_per_1m_tokens:{input:1,output:1},allowed_roles:[`research`],max_tokens:8700,supported:!0},{id:`sonar-deep-research`,swe_score:.211,cost_per_1m_tokens:{input:2,output:8},allowed_roles:[`research`],max_tokens:8700,supported:!0},{id:`sonar-reasoning-pro`,swe_score:.211,cost_per_1m_tokens:{input:2,output:8},allowed_roles:[`main`,`research`,`fallback`],max_tokens:8700,supported:!0},{id:`sonar-reasoning`,swe_score:.211,cost_per_1m_tokens:{input:1,output:5},allowed_roles:[`main`,`research`,`fallback`],max_tokens:8700,supported:!0}],openrouter:[{id:`google/gemini-2.5-flash-preview-05-20`,swe_score:0,cost_per_1m_tokens:{input:.15,output:.6},allowed_roles:[`main`,`fallback`],max_tokens:1048576,supported:!0},{id:`google/gemini-2.5-flash-preview-05-20:thinking`,swe_score:0,cost_per_1m_tokens:{input:.15,output:3.5},allowed_roles:[`main`,`fallback`],max_tokens:1048576,supported:!0},{id:`google/gemini-2.5-pro-exp-03-25`,swe_score:0,cost_per_1m_tokens:{input:0,output:0},allowed_roles:[`main`,`fallback`],max_tokens:1e6,supported:!0},{id:`deepseek/deepseek-chat-v3-0324:free`,swe_score:0,cost_per_1m_tokens:{input:0,output:0},allowed_roles:[`main`,`fallback`],max_tokens:163840,supported:!1,reason:`Free OpenRouter models are not supported due to severe rate limits, lack of tool use support, and other reliability issues that make them impractical for production use.`},{id:`deepseek/deepseek-chat-v3-0324`,swe_score:0,cost_per_1m_tokens:{input:.27,output:1.1},allowed_roles:[`main`],max_tokens:64e3,supported:!0},{id:`openai/gpt-4.1`,swe_score:0,cost_per_1m_tokens:{input:2,output:8},allowed_roles:[`main`,`fallback`],max_tokens:1e6,supported:!0},{id:`openai/gpt-4.1-mini`,swe_score:0,cost_per_1m_tokens:{input:.4,output:1.6},allowed_roles:[`main`,`fallback`],max_tokens:1e6,supported:!0},{id:`openai/gpt-4.1-nano`,swe_score:0,cost_per_1m_tokens:{input:.1,output:.4},allowed_roles:[`main`,`fallback`],max_tokens:1e6,supported:!0},{id:`openai/o3`,swe_score:0,cost_per_1m_tokens:{input:10,output:40},allowed_roles:[`main`,`fallback`],max_tokens:2e5,supported:!0},{id:`openai/codex-mini`,swe_score:0,cost_per_1m_tokens:{input:1.5,output:6},allowed_roles:[`main`,`fallback`],max_tokens:1e5,supported:!0},{id:`openai/gpt-4o-mini`,swe_score:0,cost_per_1m_tokens:{input:.15,output:.6},allowed_roles:[`main`,`fallback`],max_tokens:1e5,supported:!0},{id:`openai/o4-mini`,swe_score:.45,cost_per_1m_tokens:{input:1.1,output:4.4},allowed_roles:[`main`,`fallback`],max_tokens:1e5,supported:!0},{id:`openai/o4-mini-high`,swe_score:0,cost_per_1m_tokens:{input:1.1,output:4.4},allowed_roles:[`main`,`fallback`],max_tokens:1e5,supported:!0},{id:`openai/o1-pro`,swe_score:0,cost_per_1m_tokens:{input:150,output:600},allowed_roles:[`main`,`fallback`],max_tokens:1e5,supported:!0},{id:`meta-llama/llama-3.3-70b-instruct`,swe_score:0,cost_per_1m_tokens:{input:120,output:600},allowed_roles:[`main`,`fallback`],max_tokens:1048576,supported:!0},{id:`meta-llama/llama-4-maverick`,swe_score:0,cost_per_1m_tokens:{input:.18,output:.6},allowed_roles:[`main`,`fallback`],max_tokens:1e6,supported:!0},{id:`meta-llama/llama-4-scout`,swe_score:0,cost_per_1m_tokens:{input:.08,output:.3},allowed_roles:[`main`,`fallback`],max_tokens:1e6,supported:!0},{id:`qwen/qwen-max`,swe_score:0,cost_per_1m_tokens:{input:1.6,output:6.4},allowed_roles:[`main`,`fallback`],max_tokens:32768,supported:!0},{id:`qwen/qwen-turbo`,swe_score:0,cost_per_1m_tokens:{input:.05,output:.2},allowed_roles:[`main`,`fallback`],max_tokens:32768,supported:!0},{id:`qwen/qwen3-235b-a22b`,swe_score:0,cost_per_1m_tokens:{input:.14,output:2},allowed_roles:[`main`,`fallback`],max_tokens:24e3,supported:!0},{id:`mistralai/mistral-small-3.1-24b-instruct:free`,swe_score:0,cost_per_1m_tokens:{input:0,output:0},allowed_roles:[`main`,`fallback`],max_tokens:96e3,supported:!1,reason:`Free OpenRouter models are not supported due to severe rate limits, lack of tool use support, and other reliability issues that make them impractical for production use.`},{id:`mistralai/mistral-small-3.1-24b-instruct`,swe_score:0,cost_per_1m_tokens:{input:.1,output:.3},allowed_roles:[`main`,`fallback`],max_tokens:128e3,supported:!0},{id:`mistralai/devstral-small`,swe_score:0,cost_per_1m_tokens:{input:.1,output:.3},allowed_roles:[`main`],max_tokens:11e4,supported:!0},{id:`mistralai/mistral-nemo`,swe_score:0,cost_per_1m_tokens:{input:.03,output:.07},allowed_roles:[`main`,`fallback`],max_tokens:1e5,supported:!0},{id:`thudm/glm-4-32b:free`,swe_score:0,cost_per_1m_tokens:{input:0,output:0},allowed_roles:[`main`,`fallback`],max_tokens:32768,supported:!1,reason:`Free OpenRouter models are not supported due to severe rate limits, lack of tool use support, and other reliability issues that make them impractical for production use.`}],zai:[{id:`glm-4.6`,swe_score:.68,cost_per_1m_tokens:{input:.6,output:2.2},allowed_roles:[`main`,`fallback`,`research`],max_tokens:204800,supported:!0},{id:`glm-4.5`,swe_score:.65,cost_per_1m_tokens:{input:.6,output:2.2},allowed_roles:[`main`,`fallback`,`research`],max_tokens:131072,supported:!0},{id:`glm-4.5-air`,swe_score:.62,cost_per_1m_tokens:{input:.2,output:1.1},allowed_roles:[`main`,`fallback`,`research`],max_tokens:131072,supported:!0}],"zai-coding":[{id:`glm-4.6`,swe_score:.68,cost_per_1m_tokens:{input:0,output:0},allowed_roles:[`main`,`fallback`,`research`],max_tokens:204800,supported:!0},{id:`glm-4.5`,swe_score:.65,cost_per_1m_tokens:{input:0,output:0},allowed_roles:[`main`,`fallback`,`research`],max_tokens:131072,supported:!0},{id:`glm-4.5-air`,swe_score:.62,cost_per_1m_tokens:{input:0,output:0},allowed_roles:[`main`,`fallback`,`research`],max_tokens:131072,supported:!0}],ollama:[{id:`gpt-oss:latest`,swe_score:.607,cost_per_1m_tokens:{input:0,output:0},allowed_roles:[`main`,`fallback`],max_tokens:128e3,supported:!0},{id:`gpt-oss:20b`,swe_score:.607,cost_per_1m_tokens:{input:0,output:0},allowed_roles:[`main`,`fallback`],max_tokens:128e3,supported:!0},{id:`gpt-oss:120b`,swe_score:.624,cost_per_1m_tokens:{input:0,output:0},allowed_roles:[`main`,`fallback`],max_tokens:128e3,supported:!0},{id:`devstral:latest`,swe_score:0,cost_per_1m_tokens:{input:0,output:0},allowed_roles:[`main`,`fallback`],supported:!0},{id:`qwen3:latest`,swe_score:0,cost_per_1m_tokens:{input:0,output:0},allowed_roles:[`main`,`fallback`],supported:!0},{id:`qwen3:14b`,swe_score:0,cost_per_1m_tokens:{input:0,output:0},allowed_roles:[`main`,`fallback`],supported:!0},{id:`qwen3:32b`,swe_score:0,cost_per_1m_tokens:{input:0,output:0},allowed_roles:[`main`,`fallback`],supported:!0},{id:`mistral-small3.1:latest`,swe_score:0,cost_per_1m_tokens:{input:0,output:0},allowed_roles:[`main`,`fallback`],supported:!0},{id:`llama3.3:latest`,swe_score:0,cost_per_1m_tokens:{input:0,output:0},allowed_roles:[`main`,`fallback`],supported:!0},{id:`phi4:latest`,swe_score:0,cost_per_1m_tokens:{input:0,output:0},allowed_roles:[`main`,`fallback`],supported:!0}],azure:[{id:`gpt-4o`,swe_score:.332,cost_per_1m_tokens:{input:2.5,output:10},allowed_roles:[`main`,`fallback`],max_tokens:16384,supported:!0},{id:`gpt-4o-mini`,swe_score:.3,cost_per_1m_tokens:{input:.15,output:.6},allowed_roles:[`main`,`fallback`],max_tokens:16384,supported:!0},{id:`gpt-4-1`,swe_score:0,cost_per_1m_tokens:{input:2,output:10},allowed_roles:[`main`,`fallback`],max_tokens:16384,supported:!0},{id:`gpt-5`,name:`GPT-5`,swe_score:.749,cost_per_1m_tokens:{input:5,output:20},allowed_roles:[`main`,`fallback`],max_tokens:1e5,temperature:1,supported:!0,api_type:`responses`},{id:`o1`,name:`o1`,swe_score:.489,cost_per_1m_tokens:{input:15,output:60},allowed_roles:[`main`],max_tokens:1e5,supported:!0,api_type:`responses`},{id:`o3`,name:`o3`,swe_score:.5,cost_per_1m_tokens:{input:2,output:8},allowed_roles:[`main`,`fallback`],max_tokens:1e5,supported:!0,api_type:`responses`},{id:`o3-mini`,name:`o3-mini`,swe_score:.493,cost_per_1m_tokens:{input:1.1,output:4.4},allowed_roles:[`main`],max_tokens:1e5,supported:!0,api_type:`responses`},{id:`o4-mini`,name:`o4-mini`,swe_score:.45,cost_per_1m_tokens:{input:1.1,output:4.4},allowed_roles:[`main`,`fallback`],max_tokens:1e5,supported:!0,api_type:`responses`},{id:`gpt-5.1`,name:`GPT-5.1`,swe_score:.76,cost_per_1m_tokens:{input:1.25,output:10},allowed_roles:[`main`,`fallback`],max_tokens:128e3,reasoning_efforts:[`none`,`low`,`medium`,`high`],supported:!0,api_type:`responses`},{id:`gpt-5.2`,name:`GPT-5.2`,swe_score:.8,cost_per_1m_tokens:{input:1.75,output:14},allowed_roles:[`main`,`fallback`],max_tokens:128e3,reasoning_efforts:[`none`,`low`,`medium`,`high`,`xhigh`],supported:!0,api_type:`responses`}],bedrock:[{id:`us.anthropic.claude-3-haiku-20240307-v1:0`,swe_score:.4,cost_per_1m_tokens:{input:.25,output:1.25},allowed_roles:[`main`,`fallback`],supported:!0},{id:`us.anthropic.claude-3-opus-20240229-v1:0`,swe_score:.725,cost_per_1m_tokens:{input:15,output:75},allowed_roles:[`main`,`fallback`,`research`],supported:!0},{id:`us.anthropic.claude-3-5-sonnet-20240620-v1:0`,swe_score:.49,cost_per_1m_tokens:{input:3,output:15},allowed_roles:[`main`,`fallback`,`research`],supported:!0},{id:`us.anthropic.claude-3-5-sonnet-20241022-v2:0`,swe_score:.49,cost_per_1m_tokens:{input:3,output:15},allowed_roles:[`main`,`fallback`,`research`],supported:!0},{id:`us.anthropic.claude-3-7-sonnet-20250219-v1:0`,swe_score:.623,cost_per_1m_tokens:{input:3,output:15},allowed_roles:[`main`,`fallback`,`research`],max_tokens:65536,supported:!0},{id:`us.anthropic.claude-3-5-haiku-20241022-v1:0`,swe_score:.4,cost_per_1m_tokens:{input:.8,output:4},allowed_roles:[`main`,`fallback`],supported:!0},{id:`us.anthropic.claude-opus-4-20250514-v1:0`,swe_score:.725,cost_per_1m_tokens:{input:15,output:75},allowed_roles:[`main`,`fallback`,`research`],supported:!0},{id:`us.anthropic.claude-sonnet-4-20250514-v1:0`,swe_score:.727,cost_per_1m_tokens:{input:3,output:15},allowed_roles:[`main`,`fallback`,`research`],supported:!0},{id:`us.deepseek.r1-v1:0`,swe_score:0,cost_per_1m_tokens:{input:1.35,output:5.4},allowed_roles:[`research`],max_tokens:65536,supported:!0}]};const Gr=_e(import.meta.url);c.dirname(Gr);const Y={models:{main:{provider:`anthropic`,modelId:`claude-sonnet-4-20250514`,maxTokens:64e3,temperature:.2},research:{provider:`perplexity`,modelId:`sonar`,maxTokens:8700,temperature:.1},fallback:{provider:`anthropic`,modelId:`claude-3-7-sonnet-20250219`,maxTokens:12e4,temperature:.2}},global:{logLevel:`info`,debug:!1,defaultNumTasks:10,defaultSubtasks:5,defaultPriority:`medium`,projectName:`Task Master`,ollamaBaseURL:`http://localhost:11434/api`,bedrockBaseURL:`https://bedrock.us-east-1.amazonaws.com`,responseLanguage:`English`,enableCodebaseAnalysis:!0,enableProxy:!1,anonymousTelemetry:!0},claudeCode:{},codexCli:{},grokCli:{timeout:12e4,workingDirectory:null,defaultModel:`grok-4-latest`}};let Kr=null,qr=null;function Jr(e){global._tmSuppressConfigWarnings=e}function Yr(){return global._tmSuppressConfigWarnings===!0}var Xr=class extends Error{constructor(e){super(e),this.name=`ConfigurationError`}};function Zr(e=null,t={}){let n=Y,r=e,{storageType:a}=t;e&&`${e}`,r||(r=V(),r||=process.cwd(),`${r}`);let o=null,l={...n};if((s.existsSync(c.join(r,Yn))||s.existsSync(c.join(r,z)))&&(o=Wr(null,{projectRoot:r,storageType:a})),o){let e=o.endsWith(z);try{let t=s.readFileSync(o,`utf-8`),r=JSON.parse(t);l={models:{main:{...n.models.main,...r?.models?.main},research:{...n.models.research,...r?.models?.research},fallback:r?.models?.fallback?.provider&&r?.models?.fallback?.modelId?{...n.models.fallback,...r.models.fallback}:{...n.models.fallback}},global:{...n.global,...r?.global},claudeCode:{...n.claudeCode,...r?.claudeCode},codexCli:{...n.codexCli,...r?.codexCli},grokCli:{...n.grokCli,...r?.grokCli}},`${o}`,e&&console.warn(i.yellow(`⚠️ DEPRECATION WARNING: Found configuration in legacy location '${o}'. Please migrate to .taskmaster/config.json. Run 'task-master migrate' to automatically migrate your project.`)),Qr(l.models.main.provider)||(console.warn(i.yellow(`Warning: Invalid main provider "${l.models.main.provider}" in ${o}. Falling back to default.`)),l.models.main={...n.models.main}),Qr(l.models.research.provider)||(console.warn(i.yellow(`Warning: Invalid research provider "${l.models.research.provider}" in ${o}. Falling back to default.`)),l.models.research={...n.models.research}),l.models.fallback?.provider&&!Qr(l.models.fallback.provider)&&(console.warn(i.yellow(`Warning: Invalid fallback provider "${l.models.fallback.provider}" in ${o}. Fallback model configuration will be ignored.`)),l.models.fallback.provider=void 0,l.models.fallback.modelId=void 0),l.claudeCode&&!Ar(l.claudeCode)&&(l.claudeCode=ei(l.claudeCode)),l.codexCli&&!Ar(l.codexCli)&&(l.codexCli=ti(l.codexCli))}catch(e){console.error(i.red(`Error reading or parsing ${o}: ${e.message}. Using default configuration.`)),l={...n},`${o}`}}else{if(!Yr()&&a!==`api`)if(e)console.warn(i.yellow(`Warning: Configuration file not found at provided project root (${e}). Using default configuration. Run 'task-master models --setup' to configure.`));else{let e=s.existsSync(c.join(r,Yn)),t=s.existsSync(c.join(r,z));(e||t)&&console.warn(i.yellow(`Warning: Configuration file not found at derived root (${r}). Using defaults.`))}l={...n},`${r}`}return l}function X(e=null,t=!1,n={}){if(!Kr||t||e&&e!==qr){let r=Zr(e,n);return(t||e)&&(Kr=r,qr=e),r}return Kr}function Qr(e){return Ve.includes(e)?!0:Be.includes(e)?!!(J&&J[e]):!1}function $r(e){return J[e]?J[e].filter(e=>e.supported!==!1).map(e=>e.id):[]}function ei(e){let t=_.object({pathToClaudeCodeExecutable:_.string().optional(),maxTurns:_.number().int().positive().optional(),customSystemPrompt:_.string().optional(),appendSystemPrompt:_.string().optional(),permissionMode:_.enum([`default`,`acceptEdits`,`plan`,`bypassPermissions`]).optional(),allowedTools:_.array(_.string()).optional(),disallowedTools:_.array(_.string()).optional(),mcpServers:_.record(_.string(),_.object({type:_.enum([`stdio`,`sse`]).optional(),command:_.string(),args:_.array(_.string()).optional(),env:_.record(_.string(),_.string()).optional(),url:_.url().optional(),headers:_.record(_.string(),_.string()).optional()})).optional()}),n=_.record(_.string(),t).refine(e=>Object.keys(e||{}).every(e=>Jn.includes(e)),{message:`Invalid command name in commandSpecific`}),r=t.extend({commandSpecific:n.optional()}),a={};try{a=r.parse(e)}catch(e){console.warn(i.yellow(`Warning: Invalid Claude Code settings in config: ${e.message}. Falling back to default.`)),a={}}return a}function ti(e){let t=_.object({codexPath:_.string().optional(),cwd:_.string().optional(),approvalMode:_.enum([`untrusted`,`on-failure`,`on-request`,`never`]).optional(),sandboxMode:_.enum([`read-only`,`workspace-write`,`danger-full-access`]).optional(),fullAuto:_.boolean().optional(),dangerouslyBypassApprovalsAndSandbox:_.boolean().optional(),skipGitRepoCheck:_.boolean().optional(),color:_.enum([`always`,`never`,`auto`]).optional(),allowNpx:_.boolean().optional(),outputLastMessageFile:_.string().optional(),env:_.record(_.string(),_.string()).optional(),verbose:_.boolean().optional(),logger:_.union([_.object({}).passthrough(),_.literal(!1)]).optional(),reasoningEffort:_.enum([`none`,`minimal`,`low`,`medium`,`high`,`xhigh`]).optional()}),n=_.record(_.string(),t).refine(e=>Object.keys(e||{}).every(e=>Jn.includes(e)),{message:`Invalid command name in commandSpecific`}),r=t.extend({commandSpecific:n.optional()});try{return r.parse(e)}catch(e){return console.warn(i.yellow(`Warning: Invalid Codex CLI settings in config: ${e.message}. Falling back to default.`)),{}}}function ni(e=null,t=!1){let n=X(e,t);return{...Y.claudeCode,...n?.claudeCode||{}}}function ri(e=null,t=!1){let n=X(e,t);return{...Y.codexCli,...n?.codexCli||{}}}function ii(e,t=null,n=!1){let r=ri(t,n),i=r?.commandSpecific||{};return{...r,...i[e]}}function ai(e,t=null,n=!1){let r=ni(t,n),i=r?.commandSpecific||{};return{...r,...i[e]}}function oi(e=null,t=!1){let n=X(e,t);return{...Y.grokCli,...n?.grokCli||{}}}function si(e,t=null,n=!1){let r=oi(t,n),i=r?.commandSpecific||{};return{...r,...i[e]}}function Z(e,t=null){return X(t)?.models?.[e]||(U(`warn`,`No model configuration found for role: ${e}. Returning default.`),Y.models[e]||{})}function ci(e=null){return Z(`main`,e).provider}function li(e=null){return Z(`main`,e).modelId}function ui(e=null){return Z(`research`,e).provider}function di(e=null,t=null){let n=B(`TASKMASTER_ENABLE_CODEBASE_ANALYSIS`,e,t);if(n!=null&&n!==``)return n.toLowerCase()===`true`||n===`1`;if(e?.env?.TASKMASTER_ENABLE_CODEBASE_ANALYSIS){let t=e.env.TASKMASTER_ENABLE_CODEBASE_ANALYSIS;return t.toLowerCase()===`true`||t===`1`}return Q(t).enableCodebaseAnalysis!==!1}function fi(e=!1,t=null,n=null){if(!di(n,t))return!1;let r=e?ui(t):ci(t);return r===T.CLAUDE_CODE||r===T.GEMINI_CLI||r===T.GROK_CLI||r===T.CODEX_CLI}function pi(e=null){return Z(`research`,e).modelId}function mi(e=null){return Z(`fallback`,e).provider}function hi(e=null){return Z(`fallback`,e).modelId}function Q(e=null){let t=X(e);return{...Y.global,...t?.global||{}}}function gi(e=null){return Q(e).logLevel.toLowerCase()}function $(e=null){return Q(e).debug===!0}function _i(e=null){let t=Q(e).defaultSubtasks,n=parseInt(t,10);return Number.isNaN(n)?Y.global.defaultSubtasks:n}function vi(e=null){let t=Q(e).defaultNumTasks,n=parseInt(t,10);return Number.isNaN(n)?Y.global.defaultNumTasks:n}function yi(e=null){return Q(e).defaultPriority}function bi(e=null){return Q(e).projectName}function xi(e=null){return Q(e).ollamaBaseURL}function Si(e=null){return Q(e).azureBaseURL}function Ci(e=null){return Q(e).bedrockBaseURL}function wi(e=null){return Q(e).vertexProjectId}function Ti(e=null){return Q(e).vertexLocation}function Ei(e=null){return Q(e).responseLanguage}function Di(e=null){return Q(e).enableProxy===!0}function Oi(e=null){return Q(e).anonymousTelemetry!==!1}function ki(e=null,t=null){let n=B(`TASKMASTER_ENABLE_PROXY`,e,t);if(n!=null&&n!==``)return n.toLowerCase()===`true`||n===`1`;if(e?.env?.TASKMASTER_ENABLE_PROXY){let t=e.env.TASKMASTER_ENABLE_PROXY;return t.toLowerCase()===`true`||t===`1`}return Di(t)}function Ai(e,t=null){let n=Z(e,t),r=n.maxTokens,i=n.temperature,a=n.modelId,o=n.provider,s=r,c=i;try{let e=J[o];if(e&&Array.isArray(e)){let t=e.find(e=>e.id===a);if(t&&typeof t.max_tokens==`number`&&t.max_tokens>0){let e=t.max_tokens;s=Math.min(r,e),U(`debug`,`Applying model-specific max_tokens (${e}) for ${a}. Effective limit: ${s}`)}else U(`debug`,`No valid model-specific max_tokens override found for ${a}. Using role default: ${r}`);t&&typeof t.temperature==`number`&&t.temperature>=0&&t.temperature<=1&&(c=t.temperature,U(`debug`,`Applying model-specific temperature (${t.temperature}) for ${a}`))}else o===T.OPENROUTER?(s=Math.min(r,32768),U(`debug`,`Custom OpenRouter model ${a} detected. Using conservative max_tokens: ${s}`)):U(`debug`,`No model definitions found for provider ${o} in MODEL_MAP. Using role default maxTokens: ${r}`)}catch(e){U(`warn`,`Error looking up model-specific parameters for ${a}: ${e.message}. Using role defaults.`),s=r,c=i}return{maxTokens:s,temperature:c}}function ji(e,t=null,n=null){if([T.OLLAMA,T.BEDROCK,T.GEMINI_CLI,T.GROK_CLI,T.MCP,T.CODEX_CLI].includes(e?.toLowerCase())||e?.toLowerCase()===`claude-code`||e?.toLowerCase()===`codex-cli`)return!0;let r={openai:`OPENAI_API_KEY`,anthropic:`ANTHROPIC_API_KEY`,google:`GOOGLE_API_KEY`,perplexity:`PERPLEXITY_API_KEY`,mistral:`MISTRAL_API_KEY`,azure:`AZURE_OPENAI_API_KEY`,openrouter:`OPENROUTER_API_KEY`,xai:`XAI_API_KEY`,zai:`ZAI_API_KEY`,"zai-coding":`ZAI_API_KEY`,groq:`GROQ_API_KEY`,vertex:`GOOGLE_API_KEY`,"claude-code":`CLAUDE_CODE_API_KEY`,bedrock:`AWS_ACCESS_KEY_ID`},i=e?.toLowerCase();if(!i||!r[i])return U(`warn`,`Unknown provider name: ${e} in isApiKeySet check.`),!1;let a=r[i],o=B(a,t,n);return o&&o.trim()!==``&&!/YOUR_.*_API_KEY_HERE/.test(o)&&!o.includes(`KEY_HERE`)}function Mi(e,t=null){let n=t||V();if(!n)return console.warn(i.yellow(`Warning: Could not find project root to check mcp.json.`)),!1;let r=c.join(n,`.cursor`,`mcp.json`);if(!s.existsSync(r))return!1;try{let t=s.readFileSync(r,`utf-8`),n=JSON.parse(t),i=n?.mcpServers?.[`task-master-ai`]?.env||n?.mcpServers?.[`taskmaster-ai`]?.env;if(!i)return!1;let a=null;switch(e){case`anthropic`:a=i.ANTHROPIC_API_KEY;break;case`openai`:a=i.OPENAI_API_KEY;break;case`openrouter`:a=i.OPENROUTER_API_KEY;break;case`google`:a=i.GOOGLE_API_KEY;break;case`perplexity`:a=i.PERPLEXITY_API_KEY;break;case`xai`:a=i.XAI_API_KEY;break;case`zai`:case`zai-coding`:a=i.ZAI_API_KEY;break;case`groq`:a=i.GROQ_API_KEY;break;case`ollama`:return!0;case`claude-code`:return!0;case`codex-cli`:return!0;case`mistral`:a=i.MISTRAL_API_KEY;break;case`azure`:a=i.AZURE_OPENAI_API_KEY;break;case`vertex`:a=i.GOOGLE_API_KEY;break;case`bedrock`:a=i.AWS_ACCESS_KEY_ID;break;default:return!1}return!!a&&!/KEY_HERE$/.test(a)}catch(e){return console.error(i.red(`Error reading or parsing .cursor/mcp.json: ${e.message}`)),!1}}function Ni(){let e=[];for(let[t,n]of Object.entries(J))n.length>0?n.filter(e=>!!e.supported).forEach(n=>{let r=n.id,i=n.swe_score,a=n.cost_per_1m_tokens,o=n.allowed_roles||[`main`,`fallback`],s=n.name;s||(s=r.split(`-`).map(e=>e.charAt(0).toUpperCase()+e.slice(1)).join(` `),r===`claude-3.5-sonnet-20240620`&&(s=`Claude 3.5 Sonnet`),r===`claude-3-7-sonnet-20250219`&&(s=`Claude 3.7 Sonnet`),r===`gpt-4o`&&(s=`GPT-4o`),r===`gpt-4-turbo`&&(s=`GPT-4 Turbo`),r===`sonar-pro`&&(s=`Perplexity Sonar Pro`),r===`sonar-mini`&&(s=`Perplexity Sonar Mini`)),e.push({id:r,name:s,provider:t,swe_score:i,cost_per_1m_tokens:a,allowed_roles:o,max_tokens:n.max_tokens})}):e.push({id:`[${t}-any]`,name:`Any (${t})`,provider:t});return e}function Pi(e,t=null){let n=t;if(t==null){let e=V();if(!e)return console.error(i.red(`Error: Could not determine project root. Configuration not saved.`)),!1;n=e}let r=c.join(n,`.taskmaster`),a=c.join(r,`config.json`);try{return s.existsSync(r)||s.mkdirSync(r,{recursive:!0}),s.writeFileSync(a,JSON.stringify(e,null,2)),Kr=e,!0}catch(e){return console.error(i.red(`Error writing configuration to ${a}: ${e.message}`)),!1}}function Fi(e=null){return Wr(null,{projectRoot:e})!==null}function Ii(e=null){let t=X(e);return t.global||={},t.global.userId||(t.global.userId=`1234567890`,Pi(t,e)||U(`warning`,`Failed to write updated configuration with new userId. Please let the developers know.`)),t.global.userId}function Li(){return He}function Ri(e,t=null){let n=Z(e,t);if(n&&typeof n.baseURL==`string`)return n.baseURL;let r=n?.provider;if(r)return B(`${r.toUpperCase()}_BASE_URL`,null,t)}async function zi(e){if(e===`solo`||e===`team`)return e;try{Jr(!0);let e=X(null,!1,{storageType:`api`});if(e?.storage?.operatingMode)return e.storage.operatingMode}catch{}finally{Jr(!1)}try{if(await E.getInstance().getAuthCredentials())return`team`}catch{}return`solo`}T.OLLAMA,T.BEDROCK,T.GEMINI_CLI,T.GROK_CLI,T.MCP,T.CODEX_CLI;export{Br as $,Fn as $t,pi as A,xe as An,kr as At,Fi as B,er as Bt,ci as C,Be as Cn,vr as Ct,Ai as D,C as Dn,Fr as Dt,zi as E,Ae as En,B as Et,Ti as F,ir as Ft,ti as G,Xn as Gt,ki as H,Zn as Ht,wi as I,cr as It,J,qn as Jt,Qr as K,ar as Kt,fi as L,z as Lt,Ei as M,Sr as Mt,$r as N,nr as Nt,bi as O,S as On,Er as Ot,Ii as P,sr as Pt,q as Q,In as Qt,ji as R,or as Rt,li as S,Ve as Sn,W as St,xi as T,ze as Tn,_r as Tt,Jr as U,Qn as Ut,Yr as V,Yn as Vt,ei as W,tr as Wt,Wr as X,Vn as Xt,Hr as Y,zn as Yt,Vr as Z,Bn as Zt,hi as _,Qe as _n,Ar as _t,Si as a,bn as an,br as at,si as b,He as bn,xr as bt,ni as c,_n as cn,Rr as ct,ii as d,M as dn,Or as dt,An as en,K as et,X as f,vt as fn,wr as ft,_i as g,Ze as gn,Ir as gt,yi as h,E as hn,Pr as ht,Ni as i,R as in,Nr as it,ui as j,be as jn,fr as jt,Di as k,ye as kn,Mr as kt,ai as l,hn as ln,jr as lt,vi as m,D as mn,Dr as mt,Li as n,kn as nn,H as nt,Ri as o,xn as on,mr as ot,$ as p,A as pn,Lr as pt,Pi as q,$n as qt,Oi as r,jn as rn,Tr as rt,Ci as s,yn as sn,pr as st,Xr as t,Mn as tn,Ur as tt,ri as u,Dt as un,V as ut,mi as v,Je as vn,hr as vt,Mi as w,Re as wn,Cr as wt,gi as x,T as xn,yr as xt,oi as y,Xe as yn,U as yt,di as z,rr as zt};
|