@hhsw2015/task-master-ai 0.43.29 → 0.43.31
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/dist/ai-services-unified-Ba0FpUZx.js +1 -0
- package/dist/{ai-services-unified-CA2_lqmH.js → ai-services-unified-DtYBHWxu.js} +1 -1
- package/dist/{commands-AmWleL4Z.js → commands-CI1rUd3p.js} +4 -4
- package/dist/{config-manager-YUjvDSOp.js → config-manager-B0ancnG6.js} +1 -1
- package/dist/{config-manager-C6naCnWC.js → config-manager-Bj2cZEwZ.js} +2 -2
- package/dist/{dependency-manager-BZdDZHa6.js → dependency-manager-DVN8Tt-x.js} +4 -4
- package/dist/mcp-server.js +2 -2
- package/dist/{profiles-DUfdHCax.js → profiles-C4AS-UkT.js} +2 -2
- package/dist/research-UCqjqHBo.js +1 -0
- package/dist/response-language-BFyduoeN.js +1 -0
- package/dist/{response-language-VmMLChlE.js → response-language-DgK4p10V.js} +1 -1
- package/dist/{sentry-CHIEyp_Y.js → sentry-ClkRpQLz.js} +1 -1
- package/dist/tag-management-BvgwEfuM.js +1 -0
- package/dist/{task-manager-CE8uULez.js → task-manager-CLxydZZN.js} +1 -1
- package/dist/task-master.js +1 -1
- package/dist/update-subtask-by-id-B3lz3TnC.js +1 -0
- package/dist/update-task-by-id-YhPa_LeH.js +1 -0
- package/dist/{utils-DcGaEZ8q.js → utils-WVKuuSql.js} +1 -1
- package/package.json +1 -1
- package/dist/ai-services-unified-DPaFvytz.js +0 -1
- package/dist/research-DzoY8bIq.js +0 -1
- package/dist/response-language-DGZfLa0U.js +0 -1
- package/dist/tag-management-CAdsc1gS.js +0 -1
- package/dist/update-subtask-by-id-CwjDlaos.js +0 -1
- package/dist/update-task-by-id-B6aOeOTS.js +0 -1
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{a as e,i as t,n,r,t as i}from"./ai-services-unified-DtYBHWxu.js";import"./config-manager-Bj2cZEwZ.js";import"./git-utils-DllbRE35.js";import"./sentry-ClkRpQLz.js";export{i as generateObjectService,n as generateTextService,r as logAiUsage,t as streamObjectService,e as streamTextService};
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import{C as e,E as t,Et as n,F as r,H as i,I as a,J as o,L as s,M as c,N as l,O as u,P as d,a as f,f as p,ht as m,j as h,l as g,m as _,o as ee,s as te,ut as v,v as y,w as b,x,y as S,yt as C}from"./config-manager-C6naCnWC.js";import{n as w,t as T}from"./sentry-CHIEyp_Y.js";import{createRequire as E}from"node:module";import D,{promises as O}from"fs";import k,{join as A}from"path";import{homedir as j}from"os";import{execSync as M,spawn as N}from"child_process";import*as P from"ai";import{jsonrepair as F}from"jsonrepair";import{EnvHttpProxyAgent as I}from"undici";import{createAnthropic as ne}from"@ai-sdk/anthropic";import{createPerplexity as re}from"@ai-sdk/perplexity";import{createGoogleGenerativeAI as ie}from"@ai-sdk/google";import{createOpenAI as ae}from"@ai-sdk/openai";import{createXai as oe}from"@ai-sdk/xai";import{createGroq as se}from"@ai-sdk/groq";import{createOpenRouter as ce}from"@openrouter/ai-sdk-provider";import{createOllama as le}from"ollama-ai-provider-v2";import{createAmazonBedrock as ue}from"@ai-sdk/amazon-bedrock";import{fromNodeProviderChain as de}from"@aws-sdk/credential-providers";import{createAzure as fe}from"@ai-sdk/azure";import{createVertex as pe}from"@ai-sdk/google-vertex";import{createClaudeCode as me}from"ai-sdk-provider-claude-code";import{createGeminiProvider as he}from"ai-sdk-provider-gemini-cli";import{APICallError as L,LoadAPIKeyError as ge,NoSuchModelError as R}from"@ai-sdk/provider";import{generateId as z}from"@ai-sdk/provider-utils";import{parse as _e}from"jsonc-parser";import{createCodexCli as ve}from"ai-sdk-provider-codex-cli";import{createOpenAICompatible as ye}from"@ai-sdk/openai-compatible";var be=Object.defineProperty,xe=e=>{let t={};for(var n in e)be(t,n,{get:e[n],enumerable:!0});return t},B=E(import.meta.url);let V=null;var H=class e{constructor(){this._providers=new Map,this._initialized=!1}static getInstance(){return V||=new e,V}initialize(){return this._initialized||=!0,this}registerProvider(e,t,n={}){if(!e||typeof e!=`string`)throw Error(`Provider name must be a non-empty string`);if(!t)throw Error(`Provider instance is required`);if(typeof t.generateText!=`function`||typeof t.streamText!=`function`||typeof t.generateObject!=`function`)throw Error(`Provider must implement BaseAIProvider interface`);return this._providers.set(e,{instance:t,options:n,registeredAt:new Date}),this}hasProvider(e){return this._providers.has(e)}getProvider(e){let t=this._providers.get(e);return t?t.instance:null}getAllProviders(){return new Map(this._providers)}unregisterProvider(e){return this._providers.has(e)?(this._providers.delete(e),!0):!1}reset(){this._providers.clear(),this._initialized=!1}};H.getInstance().initialize();var U=H;const{JSONParseError:Se,NoObjectGeneratedError:Ce,generateObject:we,generateText:Te,streamObject:Ee,streamText:De,zodSchema:Oe}=P,W=P.jsonSchema,ke=new Set([`minimum`,`maximum`,`exclusiveMinimum`,`exclusiveMaximum`]),Ae=[`additionalProperties`,`contains`,`if`,`then`,`else`,`not`,`propertyNames`],je=[`allOf`,`anyOf`,`oneOf`,`prefixItems`],Me=[`definitions`,`$defs`,`dependentSchemas`,`patternProperties`,`properties`],Ne=e=>e?Array.isArray(e)?e.includes(`integer`):e===`integer`:!1,G=e=>{if(!e||typeof e!=`object`)return e;if(Array.isArray(e))return e.map(G);let t={...e};if(Ne(t.type))for(let e of ke)e in t&&delete t[e];for(let e of Ae)t[e]&&(t[e]=G(t[e]));for(let e of je)Array.isArray(t[e])&&(t[e]=t[e].map(G));for(let e of Me)if(t[e]&&typeof t[e]==`object`){let n={};for(let[r,i]of Object.entries(t[e]))n[r]=G(i);t[e]=n}return t.items&&=G(t.items),t},K=e=>{if(!e||typeof e!=`object`)return e;if(Array.isArray(e))return e.map(K);let t={};for(let[n,r]of Object.entries(e))t[n]=K(r);let n=t.type===`object`,r=t.properties&&typeof t.properties==`object`&&!Array.isArray(t.properties),i=Object.prototype.hasOwnProperty.call(t,`additionalProperties`),a=r?Object.keys(t.properties):[],o=Array.isArray(t.required),s=o?new Set(t.required):new Set,c=o&&a.every(e=>s.has(e))&&t.required.length===a.length;return n&&r&&!i&&(t.additionalProperties=!1),n&&r&&!c&&(t.required=a),t},q=e=>{let t=Oe(e);if(!t||typeof t!=`object`||!t.jsonSchema)return t;let n=K(G(t.jsonSchema));return typeof W==`function`?W(n,{validate:t.validate}):{...t,jsonSchema:n}};var J=class e{constructor(){if(this.constructor===e)throw Error(`BaseAIProvider cannot be instantiated directly`);this.name=this.constructor.name,this._proxyAgent=null,this.needsExplicitJsonSchema=!1,this.supportsTemperature=!0}validateAuth(e){if(!e.apiKey)throw Error(`${this.name} API key is required`)}createProxyFetch(){this._projectRoot||=v();let e=this._projectRoot;if(i(null,e))return this._proxyAgent||=new I,(e,t={})=>fetch(e,{...t,dispatcher:this._proxyAgent})}validateParams(e){if(this.validateAuth(e),!e.modelId)throw Error(`${this.name} Model ID is required`);this.validateOptionalParams(e)}validateOptionalParams(e){if(e.temperature!==void 0&&(e.temperature<0||e.temperature>1))throw Error(`Temperature must be between 0 and 1`);if(e.maxTokens!==void 0){let t=Number(e.maxTokens);if(!Number.isFinite(t)||t<=0)throw Error(`maxTokens must be a finite number greater than 0`)}}validateMessages(e){if(!e||!Array.isArray(e)||e.length===0)throw Error(`Invalid or empty messages array provided`);for(let t of e)if(!t.role||!t.content)throw Error(`Invalid message format. Each message must have role and content`)}handleError(e,t){let n=t.message||`Unknown error occurred`;throw C(`error`,`${this.name} ${e} failed: ${n}`,{error:t}),Error(`${this.name} API error during ${e}: ${n}`)}getClient(e){throw Error(`getClient must be implemented by provider`)}isRequiredApiKey(){return!0}getRequiredApiKeyName(){throw Error(`getRequiredApiKeyName must be implemented by provider`)}prepareTokenParam(e,t){return t===void 0?{}:{maxOutputTokens:Math.floor(Number(t))}}async generateText(e){try{this.validateParams(e),this.validateMessages(e.messages),C(`debug`,`Generating ${this.name} text with model: ${e.modelId}`);let t=await this.getClient(e),n=e.commandName||`unknown`,r=T(`${this.name}.${e.modelId}.${n}.generateText`,{command:n,outputType:e.outputType,tag:e.tag,projectHash:w(e.projectRoot),userId:e.userId,briefId:e.briefId}),i=await Te({model:t(e.modelId),messages:e.messages,...this.prepareTokenParam(e.modelId,e.maxTokens),...this.supportsTemperature&&e.temperature!==void 0?{temperature:e.temperature}:{},...r&&{experimental_telemetry:r}});C(`debug`,`${this.name} generateText completed successfully for model: ${e.modelId}`);let a=i.usage?.inputTokens??i.usage?.promptTokens??0,o=i.usage?.outputTokens??i.usage?.completionTokens??0,s=i.usage?.totalTokens??a+o;return{text:i.text,usage:{inputTokens:a,outputTokens:o,totalTokens:s}}}catch(e){this.handleError(`text generation`,e)}}async streamText(e){try{this.validateParams(e),this.validateMessages(e.messages),C(`debug`,`Streaming ${this.name} text with model: ${e.modelId}`);let t=await this.getClient(e),n=e.commandName||`unknown`,r=T(`${this.name}.${e.modelId}.${n}.streamText`,{command:n,outputType:e.outputType,tag:e.tag,projectHash:w(e.projectRoot),userId:e.userId,briefId:e.briefId}),i=await De({model:t(e.modelId),messages:e.messages,...this.prepareTokenParam(e.modelId,e.maxTokens),...this.supportsTemperature&&e.temperature!==void 0?{temperature:e.temperature}:{},...r&&{experimental_telemetry:r},...e.experimental_transform&&{experimental_transform:e.experimental_transform}});return C(`debug`,`${this.name} streamText initiated successfully for model: ${e.modelId}`),i}catch(e){this.handleError(`text streaming`,e)}}async streamObject(e){try{if(this.validateParams(e),this.validateMessages(e.messages),!e.schema)throw Error(`Schema is required for object streaming`);C(`debug`,`Streaming ${this.name} object with model: ${e.modelId}`);let t=await this.getClient(e),n=e.commandName||`unknown`,r=T(`${this.name}.${e.modelId}.${n}.streamObject`,{command:n,outputType:e.outputType,tag:e.tag,projectHash:w(e.projectRoot),userId:e.userId,briefId:e.briefId}),i=q(e.schema),a=await Ee({model:t(e.modelId),messages:e.messages,schema:i,mode:e.mode||`auto`,maxOutputTokens:e.maxTokens,...this.supportsTemperature&&e.temperature!==void 0?{temperature:e.temperature}:{},...r&&{experimental_telemetry:r}});return C(`debug`,`${this.name} streamObject initiated successfully for model: ${e.modelId}`),a}catch(e){this.handleError(`object streaming`,e)}}async generateObject(e){try{if(this.validateParams(e),this.validateMessages(e.messages),!e.schema)throw Error(`Schema is required for object generation`);if(!e.objectName)throw Error(`Object name is required for object generation`);C(`debug`,`Generating ${this.name} object ('${e.objectName}') with model: ${e.modelId}`);let t=await this.getClient(e),n=e.commandName||`unknown`,r=T(`${this.name}.${e.modelId}.${n}.generateObject.${e.objectName}`,{command:n,outputType:e.outputType,tag:e.tag,projectHash:w(e.projectRoot),userId:e.userId,briefId:e.briefId}),i=q(e.schema),a=await we({model:t(e.modelId),messages:e.messages,schema:i,mode:this.needsExplicitJsonSchema?`json`:`auto`,schemaName:e.objectName,schemaDescription:`Generate a valid JSON object for ${e.objectName}`,maxTokens:e.maxTokens,...this.supportsTemperature&&e.temperature!==void 0?{temperature:e.temperature}:{},...r&&{experimental_telemetry:r}});C(`debug`,`${this.name} generateObject completed successfully for model: ${e.modelId}`);let o=a.usage?.inputTokens??a.usage?.promptTokens??0,s=a.usage?.outputTokens??a.usage?.completionTokens??0,c=a.usage?.totalTokens??o+s;return{object:a.object,usage:{inputTokens:o,outputTokens:s,totalTokens:c}}}catch(e){if(Ce.isInstance(e)&&e.cause instanceof Se&&e.cause.text){C(`warn`,`${this.name} generated malformed JSON, attempting to repair...`);try{let t=F(e.cause.text),n=JSON.parse(t);return C(`info`,`Successfully repaired ${this.name} JSON output`),{object:n,usage:{inputTokens:e.usage?.promptTokens||e.usage?.inputTokens||0,outputTokens:e.usage?.completionTokens||e.usage?.outputTokens||0,totalTokens:e.usage?.totalTokens||0}}}catch(e){C(`error`,`Failed to repair ${this.name} JSON: ${e.message}`)}}this.handleError(`object generation`,e)}}},Pe=class extends J{constructor(){super(),this.name=`Anthropic`}getRequiredApiKeyName(){return`ANTHROPIC_API_KEY`}getClient(e){try{let{apiKey:t,baseURL:n}=e,r=this.createProxyFetch();return ne({apiKey:t,...n&&{baseURL:n},headers:{"anthropic-beta":`output-128k-2025-02-19`},...r&&{fetch:r}})}catch(e){this.handleError(`client initialization`,e)}}},Fe=class extends J{constructor(){super(),this.name=`Perplexity`}getRequiredApiKeyName(){return`PERPLEXITY_API_KEY`}getClient(e){try{let{apiKey:t,baseURL:n}=e,r=this.createProxyFetch();return re({apiKey:t,baseURL:n||`https://api.perplexity.ai`,...r&&{fetch:r}})}catch(e){this.handleError(`client initialization`,e)}}async generateObject(e){return super.generateObject({...e,mode:`json`})}},Ie=class extends J{constructor(){super(),this.name=`Google`}getRequiredApiKeyName(){return`GOOGLE_API_KEY`}getClient(e){try{let{apiKey:t,baseURL:n}=e,r=this.createProxyFetch();return ie({apiKey:t,...n&&{baseURL:n},...r&&{fetch:r}})}catch(e){this.handleError(`client initialization`,e)}}},Le=class extends J{constructor(){super(),this.name=`OpenAI`}getRequiredApiKeyName(){return`OPENAI_API_KEY`}getClient(e){try{let{apiKey:t,baseURL:n}=e,r=this.createProxyFetch();return ae({apiKey:t,...n&&{baseURL:n},...r&&{fetch:r}})}catch(e){this.handleError(`client initialization`,e)}}},Re=class extends J{constructor(){super(),this.name=`xAI`}getRequiredApiKeyName(){return`XAI_API_KEY`}getClient(e){try{let{apiKey:t,baseURL:n}=e;return oe({apiKey:t,baseURL:n||`https://api.x.ai/v1`})}catch(e){this.handleError(`client initialization`,e)}}},ze=class extends J{constructor(){super(),this.name=`Groq`}getRequiredApiKeyName(){return`GROQ_API_KEY`}getClient(e){try{let{apiKey:t,baseURL:n}=e;return se({apiKey:t,...n&&{baseURL:n}})}catch(e){this.handleError(`client initialization`,e)}}},Be=class extends J{constructor(){super(),this.name=`OpenRouter`}getRequiredApiKeyName(){return`OPENROUTER_API_KEY`}getClient(e){try{let{apiKey:t,baseURL:n}=e;return ce({apiKey:t,...n&&{baseURL:n}})}catch(e){this.handleError(`client initialization`,e)}}},Ve=class extends J{constructor(){super(),this.name=`Ollama`}validateAuth(e){}getClient(e){try{let{baseURL:t}=e;return le({...t&&{baseURL:t}})}catch(e){this.handleError(`client initialization`,e)}}isRequiredApiKey(){return!1}getRequiredApiKeyName(){return`OLLAMA_API_KEY`}},He=class extends J{constructor(){super(),this.name=`Bedrock`}isRequiredApiKey(){return!1}getRequiredApiKeyName(){return`AWS_ACCESS_KEY_ID`}validateAuth(e){}getClient(e){try{let e=de(),t=this.createProxyFetch();return ue({credentialProvider:e,...t&&{fetch:t}})}catch(e){this.handleError(`client initialization`,e)}}},Ue=class extends J{constructor(){super(),this.name=`Azure OpenAI`}getRequiredApiKeyName(){return`AZURE_OPENAI_API_KEY`}validateAuth(e){if(!e.apiKey)throw Error(`Azure API key is required`);if(!e.baseURL)throw Error(`Azure endpoint URL is required. Set it in .taskmasterconfig global.azureBaseURL or models.[role].baseURL`)}normalizeBaseURL(e){if(!e)return e;try{let t=new URL(e),n=t.pathname.replace(/\/+$/,``);return n.endsWith(`/openai`)||(n=`${n}/openai`),t.pathname=n,t.toString()}catch{let t=e.replace(/\/+$/,``);return t.endsWith(`/openai`)?t:`${t}/openai`}}getClient(e){try{let{apiKey:t,baseURL:n}=e,r=this.normalizeBaseURL(n),i=this.createProxyFetch();return fe({apiKey:t,baseURL:r,...i&&{fetch:i}})}catch(e){this.handleError(`client initialization`,e)}}},Y=class extends Error{constructor(e){super(e),this.name=`VertexAuthError`,this.code=`vertex_auth_error`}},X=class extends Error{constructor(e){super(e),this.name=`VertexConfigError`,this.code=`vertex_config_error`}},We=class extends Error{constructor(e,t){super(e),this.name=`VertexApiError`,this.code=`vertex_api_error`,this.statusCode=t}},Ge=class extends J{constructor(){super(),this.name=`Google Vertex AI`}getRequiredApiKeyName(){return`GOOGLE_API_KEY`}isRequiredApiKey(){return!1}isAuthenticationRequired(){return!0}isValidCredential(e){return e?typeof e==`string`?e.trim().length>0:typeof e==`object`:!1}validateAuth(e){let{apiKey:t,projectId:n,location:r,credentials:i}=e,a=this.isValidCredential(t),o=this.isValidCredential(i);if(!a&&!o)throw new Y(`Vertex AI requires authentication. Provide one of the following:
|
|
1
|
+
import{C as e,E as t,Et as n,F as r,H as i,I as a,J as o,L as s,M as c,N as l,O as u,P as d,a as f,f as p,ht as m,j as h,l as g,m as _,o as ee,s as te,ut as v,v as y,w as b,x,y as S,yt as C}from"./config-manager-Bj2cZEwZ.js";import{n as w,t as T}from"./sentry-ClkRpQLz.js";import{createRequire as E}from"node:module";import D,{promises as O}from"fs";import k,{join as A}from"path";import{homedir as j}from"os";import{execSync as M,spawn as N}from"child_process";import*as P from"ai";import{jsonrepair as F}from"jsonrepair";import{EnvHttpProxyAgent as I}from"undici";import{createAnthropic as ne}from"@ai-sdk/anthropic";import{createPerplexity as re}from"@ai-sdk/perplexity";import{createGoogleGenerativeAI as ie}from"@ai-sdk/google";import{createOpenAI as ae}from"@ai-sdk/openai";import{createXai as oe}from"@ai-sdk/xai";import{createGroq as se}from"@ai-sdk/groq";import{createOpenRouter as ce}from"@openrouter/ai-sdk-provider";import{createOllama as le}from"ollama-ai-provider-v2";import{createAmazonBedrock as ue}from"@ai-sdk/amazon-bedrock";import{fromNodeProviderChain as de}from"@aws-sdk/credential-providers";import{createAzure as fe}from"@ai-sdk/azure";import{createVertex as pe}from"@ai-sdk/google-vertex";import{createClaudeCode as me}from"ai-sdk-provider-claude-code";import{createGeminiProvider as he}from"ai-sdk-provider-gemini-cli";import{APICallError as L,LoadAPIKeyError as ge,NoSuchModelError as R}from"@ai-sdk/provider";import{generateId as z}from"@ai-sdk/provider-utils";import{parse as _e}from"jsonc-parser";import{createCodexCli as ve}from"ai-sdk-provider-codex-cli";import{createOpenAICompatible as ye}from"@ai-sdk/openai-compatible";var be=Object.defineProperty,xe=e=>{let t={};for(var n in e)be(t,n,{get:e[n],enumerable:!0});return t},B=E(import.meta.url);let V=null;var H=class e{constructor(){this._providers=new Map,this._initialized=!1}static getInstance(){return V||=new e,V}initialize(){return this._initialized||=!0,this}registerProvider(e,t,n={}){if(!e||typeof e!=`string`)throw Error(`Provider name must be a non-empty string`);if(!t)throw Error(`Provider instance is required`);if(typeof t.generateText!=`function`||typeof t.streamText!=`function`||typeof t.generateObject!=`function`)throw Error(`Provider must implement BaseAIProvider interface`);return this._providers.set(e,{instance:t,options:n,registeredAt:new Date}),this}hasProvider(e){return this._providers.has(e)}getProvider(e){let t=this._providers.get(e);return t?t.instance:null}getAllProviders(){return new Map(this._providers)}unregisterProvider(e){return this._providers.has(e)?(this._providers.delete(e),!0):!1}reset(){this._providers.clear(),this._initialized=!1}};H.getInstance().initialize();var U=H;const{JSONParseError:Se,NoObjectGeneratedError:Ce,generateObject:we,generateText:Te,streamObject:Ee,streamText:De,zodSchema:Oe}=P,W=P.jsonSchema,ke=new Set([`minimum`,`maximum`,`exclusiveMinimum`,`exclusiveMaximum`]),Ae=[`additionalProperties`,`contains`,`if`,`then`,`else`,`not`,`propertyNames`],je=[`allOf`,`anyOf`,`oneOf`,`prefixItems`],Me=[`definitions`,`$defs`,`dependentSchemas`,`patternProperties`,`properties`],Ne=e=>e?Array.isArray(e)?e.includes(`integer`):e===`integer`:!1,G=e=>{if(!e||typeof e!=`object`)return e;if(Array.isArray(e))return e.map(G);let t={...e};if(Ne(t.type))for(let e of ke)e in t&&delete t[e];for(let e of Ae)t[e]&&(t[e]=G(t[e]));for(let e of je)Array.isArray(t[e])&&(t[e]=t[e].map(G));for(let e of Me)if(t[e]&&typeof t[e]==`object`){let n={};for(let[r,i]of Object.entries(t[e]))n[r]=G(i);t[e]=n}return t.items&&=G(t.items),t},K=e=>{if(!e||typeof e!=`object`)return e;if(Array.isArray(e))return e.map(K);let t={};for(let[n,r]of Object.entries(e))t[n]=K(r);let n=t.type===`object`,r=t.properties&&typeof t.properties==`object`&&!Array.isArray(t.properties),i=Object.prototype.hasOwnProperty.call(t,`additionalProperties`),a=r?Object.keys(t.properties):[],o=Array.isArray(t.required),s=o?new Set(t.required):new Set,c=o&&a.every(e=>s.has(e))&&t.required.length===a.length;return n&&r&&!i&&(t.additionalProperties=!1),n&&r&&!c&&(t.required=a),t},q=e=>{let t=Oe(e);if(!t||typeof t!=`object`||!t.jsonSchema)return t;let n=K(G(t.jsonSchema));return typeof W==`function`?W(n,{validate:t.validate}):{...t,jsonSchema:n}};var J=class e{constructor(){if(this.constructor===e)throw Error(`BaseAIProvider cannot be instantiated directly`);this.name=this.constructor.name,this._proxyAgent=null,this.needsExplicitJsonSchema=!1,this.supportsTemperature=!0}validateAuth(e){if(!e.apiKey)throw Error(`${this.name} API key is required`)}createProxyFetch(){this._projectRoot||=v();let e=this._projectRoot;if(i(null,e))return this._proxyAgent||=new I,(e,t={})=>fetch(e,{...t,dispatcher:this._proxyAgent})}validateParams(e){if(this.validateAuth(e),!e.modelId)throw Error(`${this.name} Model ID is required`);this.validateOptionalParams(e)}validateOptionalParams(e){if(e.temperature!==void 0&&(e.temperature<0||e.temperature>1))throw Error(`Temperature must be between 0 and 1`);if(e.maxTokens!==void 0){let t=Number(e.maxTokens);if(!Number.isFinite(t)||t<=0)throw Error(`maxTokens must be a finite number greater than 0`)}}validateMessages(e){if(!e||!Array.isArray(e)||e.length===0)throw Error(`Invalid or empty messages array provided`);for(let t of e)if(!t.role||!t.content)throw Error(`Invalid message format. Each message must have role and content`)}handleError(e,t){let n=t.message||`Unknown error occurred`;throw C(`error`,`${this.name} ${e} failed: ${n}`,{error:t}),Error(`${this.name} API error during ${e}: ${n}`)}getClient(e){throw Error(`getClient must be implemented by provider`)}isRequiredApiKey(){return!0}getRequiredApiKeyName(){throw Error(`getRequiredApiKeyName must be implemented by provider`)}prepareTokenParam(e,t){return t===void 0?{}:{maxOutputTokens:Math.floor(Number(t))}}async generateText(e){try{this.validateParams(e),this.validateMessages(e.messages),C(`debug`,`Generating ${this.name} text with model: ${e.modelId}`);let t=await this.getClient(e),n=e.commandName||`unknown`,r=T(`${this.name}.${e.modelId}.${n}.generateText`,{command:n,outputType:e.outputType,tag:e.tag,projectHash:w(e.projectRoot),userId:e.userId,briefId:e.briefId}),i=await Te({model:t(e.modelId),messages:e.messages,...this.prepareTokenParam(e.modelId,e.maxTokens),...this.supportsTemperature&&e.temperature!==void 0?{temperature:e.temperature}:{},...r&&{experimental_telemetry:r}});C(`debug`,`${this.name} generateText completed successfully for model: ${e.modelId}`);let a=i.usage?.inputTokens??i.usage?.promptTokens??0,o=i.usage?.outputTokens??i.usage?.completionTokens??0,s=i.usage?.totalTokens??a+o;return{text:i.text,usage:{inputTokens:a,outputTokens:o,totalTokens:s}}}catch(e){this.handleError(`text generation`,e)}}async streamText(e){try{this.validateParams(e),this.validateMessages(e.messages),C(`debug`,`Streaming ${this.name} text with model: ${e.modelId}`);let t=await this.getClient(e),n=e.commandName||`unknown`,r=T(`${this.name}.${e.modelId}.${n}.streamText`,{command:n,outputType:e.outputType,tag:e.tag,projectHash:w(e.projectRoot),userId:e.userId,briefId:e.briefId}),i=await De({model:t(e.modelId),messages:e.messages,...this.prepareTokenParam(e.modelId,e.maxTokens),...this.supportsTemperature&&e.temperature!==void 0?{temperature:e.temperature}:{},...r&&{experimental_telemetry:r},...e.experimental_transform&&{experimental_transform:e.experimental_transform}});return C(`debug`,`${this.name} streamText initiated successfully for model: ${e.modelId}`),i}catch(e){this.handleError(`text streaming`,e)}}async streamObject(e){try{if(this.validateParams(e),this.validateMessages(e.messages),!e.schema)throw Error(`Schema is required for object streaming`);C(`debug`,`Streaming ${this.name} object with model: ${e.modelId}`);let t=await this.getClient(e),n=e.commandName||`unknown`,r=T(`${this.name}.${e.modelId}.${n}.streamObject`,{command:n,outputType:e.outputType,tag:e.tag,projectHash:w(e.projectRoot),userId:e.userId,briefId:e.briefId}),i=q(e.schema),a=await Ee({model:t(e.modelId),messages:e.messages,schema:i,mode:e.mode||`auto`,maxOutputTokens:e.maxTokens,...this.supportsTemperature&&e.temperature!==void 0?{temperature:e.temperature}:{},...r&&{experimental_telemetry:r}});return C(`debug`,`${this.name} streamObject initiated successfully for model: ${e.modelId}`),a}catch(e){this.handleError(`object streaming`,e)}}async generateObject(e){try{if(this.validateParams(e),this.validateMessages(e.messages),!e.schema)throw Error(`Schema is required for object generation`);if(!e.objectName)throw Error(`Object name is required for object generation`);C(`debug`,`Generating ${this.name} object ('${e.objectName}') with model: ${e.modelId}`);let t=await this.getClient(e),n=e.commandName||`unknown`,r=T(`${this.name}.${e.modelId}.${n}.generateObject.${e.objectName}`,{command:n,outputType:e.outputType,tag:e.tag,projectHash:w(e.projectRoot),userId:e.userId,briefId:e.briefId}),i=q(e.schema),a=await we({model:t(e.modelId),messages:e.messages,schema:i,mode:this.needsExplicitJsonSchema?`json`:`auto`,schemaName:e.objectName,schemaDescription:`Generate a valid JSON object for ${e.objectName}`,maxTokens:e.maxTokens,...this.supportsTemperature&&e.temperature!==void 0?{temperature:e.temperature}:{},...r&&{experimental_telemetry:r}});C(`debug`,`${this.name} generateObject completed successfully for model: ${e.modelId}`);let o=a.usage?.inputTokens??a.usage?.promptTokens??0,s=a.usage?.outputTokens??a.usage?.completionTokens??0,c=a.usage?.totalTokens??o+s;return{object:a.object,usage:{inputTokens:o,outputTokens:s,totalTokens:c}}}catch(e){if(Ce.isInstance(e)&&e.cause instanceof Se&&e.cause.text){C(`warn`,`${this.name} generated malformed JSON, attempting to repair...`);try{let t=F(e.cause.text),n=JSON.parse(t);return C(`info`,`Successfully repaired ${this.name} JSON output`),{object:n,usage:{inputTokens:e.usage?.promptTokens||e.usage?.inputTokens||0,outputTokens:e.usage?.completionTokens||e.usage?.outputTokens||0,totalTokens:e.usage?.totalTokens||0}}}catch(e){C(`error`,`Failed to repair ${this.name} JSON: ${e.message}`)}}this.handleError(`object generation`,e)}}},Pe=class extends J{constructor(){super(),this.name=`Anthropic`}getRequiredApiKeyName(){return`ANTHROPIC_API_KEY`}getClient(e){try{let{apiKey:t,baseURL:n}=e,r=this.createProxyFetch();return ne({apiKey:t,...n&&{baseURL:n},headers:{"anthropic-beta":`output-128k-2025-02-19`},...r&&{fetch:r}})}catch(e){this.handleError(`client initialization`,e)}}},Fe=class extends J{constructor(){super(),this.name=`Perplexity`}getRequiredApiKeyName(){return`PERPLEXITY_API_KEY`}getClient(e){try{let{apiKey:t,baseURL:n}=e,r=this.createProxyFetch();return re({apiKey:t,baseURL:n||`https://api.perplexity.ai`,...r&&{fetch:r}})}catch(e){this.handleError(`client initialization`,e)}}async generateObject(e){return super.generateObject({...e,mode:`json`})}},Ie=class extends J{constructor(){super(),this.name=`Google`}getRequiredApiKeyName(){return`GOOGLE_API_KEY`}getClient(e){try{let{apiKey:t,baseURL:n}=e,r=this.createProxyFetch();return ie({apiKey:t,...n&&{baseURL:n},...r&&{fetch:r}})}catch(e){this.handleError(`client initialization`,e)}}},Le=class extends J{constructor(){super(),this.name=`OpenAI`}getRequiredApiKeyName(){return`OPENAI_API_KEY`}getClient(e){try{let{apiKey:t,baseURL:n}=e,r=this.createProxyFetch();return ae({apiKey:t,...n&&{baseURL:n},...r&&{fetch:r}})}catch(e){this.handleError(`client initialization`,e)}}},Re=class extends J{constructor(){super(),this.name=`xAI`}getRequiredApiKeyName(){return`XAI_API_KEY`}getClient(e){try{let{apiKey:t,baseURL:n}=e;return oe({apiKey:t,baseURL:n||`https://api.x.ai/v1`})}catch(e){this.handleError(`client initialization`,e)}}},ze=class extends J{constructor(){super(),this.name=`Groq`}getRequiredApiKeyName(){return`GROQ_API_KEY`}getClient(e){try{let{apiKey:t,baseURL:n}=e;return se({apiKey:t,...n&&{baseURL:n}})}catch(e){this.handleError(`client initialization`,e)}}},Be=class extends J{constructor(){super(),this.name=`OpenRouter`}getRequiredApiKeyName(){return`OPENROUTER_API_KEY`}getClient(e){try{let{apiKey:t,baseURL:n}=e;return ce({apiKey:t,...n&&{baseURL:n}})}catch(e){this.handleError(`client initialization`,e)}}},Ve=class extends J{constructor(){super(),this.name=`Ollama`}validateAuth(e){}getClient(e){try{let{baseURL:t}=e;return le({...t&&{baseURL:t}})}catch(e){this.handleError(`client initialization`,e)}}isRequiredApiKey(){return!1}getRequiredApiKeyName(){return`OLLAMA_API_KEY`}},He=class extends J{constructor(){super(),this.name=`Bedrock`}isRequiredApiKey(){return!1}getRequiredApiKeyName(){return`AWS_ACCESS_KEY_ID`}validateAuth(e){}getClient(e){try{let e=de(),t=this.createProxyFetch();return ue({credentialProvider:e,...t&&{fetch:t}})}catch(e){this.handleError(`client initialization`,e)}}},Ue=class extends J{constructor(){super(),this.name=`Azure OpenAI`}getRequiredApiKeyName(){return`AZURE_OPENAI_API_KEY`}validateAuth(e){if(!e.apiKey)throw Error(`Azure API key is required`);if(!e.baseURL)throw Error(`Azure endpoint URL is required. Set it in .taskmasterconfig global.azureBaseURL or models.[role].baseURL`)}normalizeBaseURL(e){if(!e)return e;try{let t=new URL(e),n=t.pathname.replace(/\/+$/,``);return n.endsWith(`/openai`)||(n=`${n}/openai`),t.pathname=n,t.toString()}catch{let t=e.replace(/\/+$/,``);return t.endsWith(`/openai`)?t:`${t}/openai`}}getClient(e){try{let{apiKey:t,baseURL:n}=e,r=this.normalizeBaseURL(n),i=this.createProxyFetch();return fe({apiKey:t,baseURL:r,...i&&{fetch:i}})}catch(e){this.handleError(`client initialization`,e)}}},Y=class extends Error{constructor(e){super(e),this.name=`VertexAuthError`,this.code=`vertex_auth_error`}},X=class extends Error{constructor(e){super(e),this.name=`VertexConfigError`,this.code=`vertex_config_error`}},We=class extends Error{constructor(e,t){super(e),this.name=`VertexApiError`,this.code=`vertex_api_error`,this.statusCode=t}},Ge=class extends J{constructor(){super(),this.name=`Google Vertex AI`}getRequiredApiKeyName(){return`GOOGLE_API_KEY`}isRequiredApiKey(){return!1}isAuthenticationRequired(){return!0}isValidCredential(e){return e?typeof e==`string`?e.trim().length>0:typeof e==`object`:!1}validateAuth(e){let{apiKey:t,projectId:n,location:r,credentials:i}=e,a=this.isValidCredential(t),o=this.isValidCredential(i);if(!a&&!o)throw new Y(`Vertex AI requires authentication. Provide one of the following:
|
|
2
2
|
• GOOGLE_API_KEY environment variable (typical for API-based auth), OR
|
|
3
3
|
• GOOGLE_APPLICATION_CREDENTIALS pointing to a service account JSON file (recommended for production)`);if(!n||typeof n==`string`&&n.trim().length===0)throw new X(`Google Cloud project ID is required for Vertex AI. Set VERTEX_PROJECT_ID environment variable.`);if(!r||typeof r==`string`&&r.trim().length===0)throw new X(`Google Cloud location is required for Vertex AI. Set VERTEX_LOCATION environment variable (e.g., "us-central1").`)}getClient(e){try{let{apiKey:t,projectId:n,location:r,credentials:i,baseURL:a}=e,o=this.createProxyFetch(),s={};return t?s.googleAuthOptions={...i,apiKey:t}:i&&(s.googleAuthOptions=i),pe({...s,project:n,location:r,...a&&{baseURL:a},...o&&{fetch:o}})}catch(e){this.handleError(`client initialization`,e)}}handleError(e,t){if(C(`error`,`Vertex AI ${e} error:`,t),t.name===`VertexAuthError`||t.name===`VertexConfigError`||t.name===`VertexApiError`)throw t;if(t.response){let e=t.response.status,n=t.response.data?.error?.message||t.message;throw e===401||e===403?new Y(`Authentication failed: ${n}`):e===400?new X(`Invalid request: ${n}`):new We(`API error (${e}): ${n}`,e)}throw Error(`Vertex AI ${e} failed: ${t.message}`)}};let Ke=!1;var qe=class extends J{constructor(){super(),this.name=`Claude Code`,this.supportedModels=d(`claude-code`),this.supportedModels.length===0&&C(`warn`,`No supported models found for claude-code provider. Check supported-models.json configuration.`),this.needsExplicitJsonSchema=!0,this.supportsTemperature=!1}getRequiredApiKeyName(){return`CLAUDE_CODE_API_KEY`}isRequiredApiKey(){return!1}validateAuth(e){if(process.env.NODE_ENV!==`test`&&!Ke&&!process.env.CLAUDE_CODE_OAUTH_TOKEN)try{M(`claude --version`,{stdio:`pipe`,timeout:1e3})}catch{C(`warn`,`Claude Code CLI not detected. Install it with: npm install -g @anthropic-ai/claude-code`)}finally{Ke=!0}}getClient(e={}){try{let t=g(e.commandName)||{},n=process.env.ANTHROPIC_API_KEY,r=process.env.CLAUDE_CODE_API_KEY;try{return r?process.env.ANTHROPIC_API_KEY=r:n&&delete process.env.ANTHROPIC_API_KEY,me({defaultSettings:{systemPrompt:{type:`preset`,preset:`claude_code`},settingSources:[`user`,`project`,`local`],...t}})}finally{n?process.env.ANTHROPIC_API_KEY=n:delete process.env.ANTHROPIC_API_KEY}}catch(e){let t=String(e?.message||``);if(e?.code===`ENOENT`||/claude/i.test(t)){let t=Error(`Claude Code CLI not available. Please install Claude Code CLI first. Original error: ${e.message}`);t.cause=e,this.handleError(`Claude Code CLI initialization`,t)}else this.handleError(`client initialization`,e)}}getSupportedModels(){return this.supportedModels}isModelSupported(e){return e?this.supportedModels.includes(String(e).toLowerCase()):!1}},Je=class extends J{constructor(){super(),this.name=`Gemini CLI`,this.supportsTemperature=!1}validateAuth(e){}async getClient(e){try{let t={};return t=e.apiKey&&e.apiKey!==`gemini-cli-no-key-required`?{authType:`api-key`,apiKey:e.apiKey}:{authType:`oauth-personal`},e.baseURL&&(t.baseURL=e.baseURL),he(t)}catch(e){this.handleError(`client initialization`,e)}}getRequiredApiKeyName(){return`GEMINI_API_KEY`}isRequiredApiKey(){return!1}};function Z({message:e,code:t,exitCode:n,stderr:r,stdout:i,promptExcerpt:a,isRetryable:o=!1}){return new L({message:e,isRetryable:o,url:`grok-cli://command`,requestBodyValues:a?{prompt:a}:void 0,data:{code:t,exitCode:n,stderr:r,stdout:i,promptExcerpt:a}})}function Ye({message:e}){return new ge({message:e||`Authentication failed. Please ensure Grok CLI is properly configured with API key.`})}function Xe({message:e,promptExcerpt:t,timeoutMs:n}){return new L({message:e,isRetryable:!0,url:`grok-cli://command`,requestBodyValues:t?{prompt:t}:void 0,data:{code:`TIMEOUT`,promptExcerpt:t,timeoutMs:n}})}function Ze({message:e}){return new L({message:e||`Grok CLI is not installed or not found in PATH. Please install with: npm install -g @vibe-kit/grok-cli`,isRetryable:!1,url:`grok-cli://installation`,requestBodyValues:void 0})}function Qe(e){let t=e.trim(),n=/```(?:json)?\s*([\s\S]*?)\s*```/i.exec(t);n&&(t=n[1]);let r=/^\s*(?:const|let|var)\s+\w+\s*=\s*([\s\S]*)/i.exec(t);r&&(t=r[1],t.trim().endsWith(`;`)&&(t=t.trim().slice(0,-1)));let i=t.indexOf(`{`),a=t.indexOf(`[`);if(i===-1&&a===-1)return e;let o=a===-1?i:i===-1?a:Math.min(i,a);t=t.slice(o);let s=e=>{let t=[];try{let n=_e(e,t,{allowTrailingComma:!0});if(t.length===0)return JSON.stringify(n,null,2)}catch{}},c=s(t);if(c!==void 0)return c;let l=t[0],u=l===`{`?`}`:`]`,d=[],f=0,p=!1,m=!1;for(let e=0;e<t.length;e++){let n=t[e];if(m){m=!1;continue}if(n===`\\`){m=!0;continue}if(n===`"`&&!p){p=!0;continue}if(n===`"`&&p){p=!1;continue}p||(n===l?f++:n===u&&(f--,f===0&&d.push(e+1)))}for(let e=d.length-1;e>=0;e--){let n=s(t.slice(0,d[e]));if(n!==void 0)return n}let h=Math.max(0,t.length-1e3);for(let e=t.length-1;e>h;e--){let n=s(t.slice(0,e));if(n!==void 0)return n}return e}function $e(e){return e.map(e=>{let t=``;return typeof e.content==`string`?t=e.content:Array.isArray(e.content)?t=e.content.filter(e=>e.type===`text`).map(e=>e.text||``).join(`
|
|
4
4
|
`):e.content&&typeof e.content==`object`&&(t=e.content.text||JSON.stringify(e.content)),{role:e.role,content:t.trim()}})}function et(e){try{let t=e.trim().split(`
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import"./ai-services-unified-
|
|
1
|
+
import"./ai-services-unified-DtYBHWxu.js";import{B as e,Bt as t,D as n,Ht as r,Kt as i,Lt as a,Nt as o,On as s,Q as c,Rt as l,Tt as u,U as d,Ut as f,Vt as p,dt as m,h,hn as g,ln as ee,m as _,mn as te,p as v,t as y,ut as ne,yt as b,z as x}from"./config-manager-Bj2cZEwZ.js";import"./git-utils-DllbRE35.js";import"./sentry-ClkRpQLz.js";import{$ as S,C,D as w,F as T,I as E,J as re,L as ie,M as ae,N as oe,O as se,P as ce,Q as le,S as ue,St as de,X as D,Y as fe,Z as pe,_ as me,_t as he,a as ge,at as O,b as _e,bt as ve,c as ye,ct as be,d as k,dt as xe,et as A,f as Se,g as Ce,h as we,ht as Te,i as Ee,it as De,j as Oe,k as j,l as ke,m as Ae,n as je,nt as Me,o as Ne,ot as Pe,p as M,r as Fe,rt as Ie,s as Le,st as Re,t as ze,tt as Be,u as Ve,ut as He,v as N,vt as Ue,w as We,wt as Ge,xt as Ke,y as qe,yt as Je}from"./dependency-manager-DVN8Tt-x.js";import{t as Ye}from"./response-language-DgK4p10V.js";import{_ as Xe,a as Ze,c as Qe,d as $e,f as et,g as tt,h as nt,i as rt,l as P,m as it,n as at,o as F,p as ot,r as st,s as I,t as L,u as R,v as z}from"./profiles-C4AS-UkT.js";import B from"chalk";import V from"fs";import H from"path";import U from"boxen";import{Command as ct}from"commander";import W from"inquirer";const G={AUTHENTICATION:`authentication`,VALIDATION:`validation`,NETWORK:`network`,API:`api`,FILE_SYSTEM:`file_system`,TASK:`task`,PERMISSION:`permission`,TIMEOUT:`timeout`,GENERIC:`generic`},lt=[/\b[A-Za-z0-9_-]{20,}\b/g,/sk-[A-Za-z0-9]{32,}/g,/api[_-]?key[:\s=]+[^\s]+/gi,/bearer\s+[^\s]+/gi,/token[:\s=]+[^\s]+/gi,/\/Users\/[^/]+/g,/C:\\Users\\[^\\]+/g,/\/home\/[^/]+/g,/[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}/g,/https?:\/\/[^:]+:[^@]+@/g];function K(e){if(!e||typeof e!=`string`)return e;let t=e;for(let e of lt)t=t.replace(e,`***REDACTED***`);return t}function ut(e){if(!e)return G.GENERIC;let t=(e.message||``).toLowerCase(),n=(e.code||``).toLowerCase();return t.includes(`auth`)||t.includes(`unauthorized`)||t.includes(`forbidden`)||t.includes(`api key`)||t.includes(`token`)||n.includes(`auth`)?G.AUTHENTICATION:t.includes(`invalid`)||t.includes(`validation`)||t.includes(`required`)||t.includes(`must be`)||n.includes(`validation`)?G.VALIDATION:t.includes(`network`)||t.includes(`connection`)||t.includes(`econnrefused`)||t.includes(`enotfound`)||n.includes(`network`)||n.includes(`econnrefused`)||n.includes(`enotfound`)?G.NETWORK:t.includes(`timeout`)||t.includes(`timed out`)||n.includes(`timeout`)?G.TIMEOUT:t.includes(`api`)||t.includes(`rate limit`)||t.includes(`quota`)||n.includes(`api`)?G.API:t.includes(`enoent`)||t.includes(`eacces`)||t.includes(`file`)||t.includes(`directory`)||n.includes(`enoent`)||n.includes(`eacces`)?G.FILE_SYSTEM:t.includes(`permission`)||t.includes(`access denied`)||n.includes(`eperm`)?G.PERMISSION:t.includes(`task`)||t.includes(`subtask`)?G.TASK:G.GENERIC}function dt(e,t,n){let r=[],i=(t.message||``).toLowerCase();switch(e){case G.AUTHENTICATION:i.includes(`api key`)?(r.push(`Check that your API key is correctly set in the .env file`),r.push(`Verify the API key has not expired or been revoked`)):i.includes(`token`)?(r.push(`Your authentication token may have expired`),r.push(`Try running: tm auth refresh`)):(r.push(`Verify your credentials are correctly configured`),r.push(`Check the authentication status with: tm auth status`));break;case G.VALIDATION:i.includes(`brief id`)?(r.push(`Brief IDs are case-insensitive (e.g., "ham32" = "HAM-32")`),r.push(`Check the brief ID format: usually LETTERS-NUMBERS`)):i.includes(`task id`)||i.includes(`invalid id`)?(r.push(`Task IDs should be numbers (e.g., 1, 2, 3)`),r.push(`Subtask IDs use dot notation (e.g., 1.1, 2.3)`)):(r.push(`Check that all required parameters are provided`),r.push(`Verify parameter values match expected formats`));break;case G.NETWORK:i.includes(`econnrefused`)?(r.push(`Could not connect to the server`),r.push(`Check your internet connection`),r.push(`Verify the API endpoint URL is correct`)):i.includes(`enotfound`)?(r.push(`Could not resolve the server hostname`),r.push(`Check your internet connection`)):(r.push(`Check your network connection`),r.push(`Verify firewall settings are not blocking the request`));break;case G.TIMEOUT:r.push(`The operation took too long to complete`),r.push(`Try again with a simpler request`),r.push(`Check your network speed and stability`);break;case G.API:i.includes(`rate limit`)?(r.push(`You have exceeded the API rate limit`),r.push(`Wait a few minutes before trying again`)):i.includes(`quota`)?(r.push(`You have reached your API quota`),r.push(`Check your account usage and limits`)):(r.push(`The API returned an error`),r.push(`Try again in a few moments`));break;case G.FILE_SYSTEM:i.includes(`enoent`)?(r.push(`The specified file or directory does not exist`),r.push(`Check the file path and ensure it is correct`),n.includes(`tasks.json`)&&r.push(`Initialize the project with: tm init`)):i.includes(`eacces`)?(r.push(`Permission denied to access the file`),r.push(`Check file permissions or run with appropriate privileges`)):r.push(`Check that the file or directory exists and is accessible`);break;case G.PERMISSION:r.push(`You do not have permission to perform this operation`),r.push(`Check file/directory permissions`),r.push(`You may need elevated privileges (sudo)`);break;case G.TASK:i.includes(`not found`)?(r.push(`The specified task does not exist`),r.push(`Use: tm list to see all available tasks`)):i.includes(`dependency`)||i.includes(`circular`)?(r.push(`Task dependencies form a circular reference`),r.push(`Use: tm validate-dependencies to identify issues`)):(r.push(`Check that the task ID is correct`),r.push(`Use: tm show <id> to view task details`));break;default:r.push(`Check the error message for specific details`),n&&r.push(`Operation failed while: ${n}`)}return r.slice(0,2)}function ft(e,t={}){let{context:n=``,debug:r=!1,command:i=``}=t;typeof e==`string`&&(e=Error(e)),(!e||typeof e!=`object`)&&(e=Error(`An unknown error occurred`));let a=K(e.message||`Unknown error`),o=ut(e),s=dt(o,e,n);return{type:o,message:a,context:n||`Unknown operation`,hints:s,command:i||null,code:e.code||null,stack:r?K(e.stack):null}}function q(e,t={}){let n=ft(e,t),r=B.red.bold(`✗ Error
|
|
2
2
|
|
|
3
3
|
`);r+=B.white(n.message)+`
|
|
4
4
|
|
|
@@ -106,7 +106,7 @@ Subtask update was not completed. Review the messages above for details.`))}catc
|
|
|
106
106
|
To fix this issue:`)),console.log(` 1. Run task-master list --with-subtasks to see all available subtask IDs`),console.log(` 2. Use a valid subtask ID with the --id parameter in format "parentId.subtaskId"`)):e.message.includes(`API key`)&&console.log(B.yellow(`
|
|
107
107
|
This error is related to API keys. Check your environment variables.`)),_()&&console.error(e),process.exit(1)}}),t.command(`scope-up`).description(`Increase task complexity with AI assistance`).option(`-f, --file <file>`,`Path to the tasks file`,i).option(`-i, --id <ids>`,`Comma-separated task/subtask IDs to scope up (required)`).option(`-s, --strength <level>`,`Complexity increase strength: light, regular, heavy`,`regular`).option(`-p, --prompt <text>`,`Custom instructions for targeted scope adjustments`).option(`-r, --research`,`Use research AI for more informed adjustments`).option(`--tag <tag>`,`Specify tag context for task operations`).action(async e=>{try{let t=J({tasksPath:e.file||!0,tag:e.tag}),n=t.getTasksPath(),r=t.getCurrentTag();await k(r),e.id||(console.error(B.red(`Error: --id parameter is required`)),console.log(B.yellow(`Usage example: task-master scope-up --id=1,2,3 --strength=regular`)),process.exit(1));let i=e.id.split(`,`).map(e=>{let t=parseInt(e.trim(),10);return(Number.isNaN(t)||t<=0)&&(console.error(B.red(`Error: Invalid task ID: ${e.trim()}`)),process.exit(1)),t});j(e.strength)||(console.error(B.red(`Error: Invalid strength level: ${e.strength}. Must be one of: light, regular, heavy`)),process.exit(1)),V.existsSync(n)||(console.error(B.red(`Error: Tasks file not found at path: ${n}`)),process.exit(1)),console.log(B.blue(`Scoping up ${i.length} task(s): ${i.join(`, `)}`)),console.log(B.blue(`Strength level: ${e.strength}`)),e.prompt&&console.log(B.blue(`Custom instructions: ${e.prompt}`));let a={projectRoot:t.getProjectRoot(),tag:r,commandName:`scope-up`,outputType:`cli`,research:e.research||!1},o=await se(n,i,e.strength,e.prompt||null,a,`text`);console.log(B.green(`✅ Successfully scoped up ${o.updatedTasks.length} task(s)`))}catch(e){console.error(B.red(`Error: ${e.message}`)),e.message.includes(`not found`)&&(console.log(B.yellow(`
|
|
108
108
|
To fix this issue:`)),console.log(` 1. Run task-master list to see all available task IDs`),console.log(` 2. Use valid task IDs with the --id parameter`)),_()&&console.error(e),process.exit(1)}}),t.command(`scope-down`).description(`Decrease task complexity with AI assistance`).option(`-f, --file <file>`,`Path to the tasks file`,i).option(`-i, --id <ids>`,`Comma-separated task/subtask IDs to scope down (required)`).option(`-s, --strength <level>`,`Complexity decrease strength: light, regular, heavy`,`regular`).option(`-p, --prompt <text>`,`Custom instructions for targeted scope adjustments`).option(`-r, --research`,`Use research AI for more informed adjustments`).option(`--tag <tag>`,`Specify tag context for task operations`).action(async e=>{try{let t=J({tasksPath:e.file||!0,tag:e.tag}),n=t.getTasksPath(),r=t.getCurrentTag();await k(r),e.id||(console.error(B.red(`Error: --id parameter is required`)),console.log(B.yellow(`Usage example: task-master scope-down --id=1,2,3 --strength=regular`)),process.exit(1));let i=e.id.split(`,`).map(e=>{let t=parseInt(e.trim(),10);return(Number.isNaN(t)||t<=0)&&(console.error(B.red(`Error: Invalid task ID: ${e.trim()}`)),process.exit(1)),t});j(e.strength)||(console.error(B.red(`Error: Invalid strength level: ${e.strength}. Must be one of: light, regular, heavy`)),process.exit(1)),V.existsSync(n)||(console.error(B.red(`Error: Tasks file not found at path: ${n}`)),process.exit(1)),console.log(B.blue(`Scoping down ${i.length} task(s): ${i.join(`, `)}`)),console.log(B.blue(`Strength level: ${e.strength}`)),e.prompt&&console.log(B.blue(`Custom instructions: ${e.prompt}`));let a={projectRoot:t.getProjectRoot(),tag:r,commandName:`scope-down`,outputType:`cli`,research:e.research||!1},o=await w(n,i,e.strength,e.prompt||null,a,`text`);console.log(B.green(`✅ Successfully scoped down ${o.updatedTasks.length} task(s)`))}catch(e){console.error(B.red(`Error: ${e.message}`)),e.message.includes(`not found`)&&(console.log(B.yellow(`
|
|
109
|
-
To fix this issue:`)),console.log(` 1. Run task-master list to see all available task IDs`),console.log(` 2. Use valid task IDs with the --id parameter`)),_()&&console.error(e),process.exit(1)}}),Pe(t),t.command(`expand`).description(`Expand a task into subtasks using AI`).option(`-i, --id <id>`,`ID of the task to expand`).option(`-a, --all`,`Expand all pending tasks based on complexity analysis`).option(`-n, --num <number>`,`Number of subtasks to generate (uses complexity analysis by default if available)`).option(`-r, --research`,`Enable research-backed generation (e.g., using Perplexity)`,!1).option(`-p, --prompt <text>`,`Additional context for subtask generation`).option(`-f, --force`,`Force expansion even if subtasks exist`,!1).option(`--file <file>`,`Path to the tasks file (relative to project root)`,i).option(`-cr, --complexity-report <file>`,`Path to the complexity report file (use this to specify the complexity report, not --file)`).option(`--tag <tag>`,`Specify tag context for task operations`).action(async e=>{let n={tasksPath:e.file||!0,tag:e.tag};e.complexityReport&&(n.complexityReportPath=e.complexityReport);let r=J(n),i=r.getCurrentTag();if(await k(i),e.all){console.log(B.blue(`Expanding all pending tasks...`));try{await re(r.getTasksPath(),e.num,e.research,e.prompt,e.force,{projectRoot:r.getProjectRoot(),tag:i,complexityReportPath:r.getComplexityReportPath()})}catch(e){console.error(B.red(`Error expanding all tasks: ${e.message}`)),process.exit(1)}}else if(e.id){e.id||(console.error(B.red(`Error: Task ID is required unless using --all.`)),process.exit(1)),console.log(B.blue(`Expanding task ${e.id}...`));try{await fe(r.getTasksPath(),e.id,e.num,e.research,e.prompt,{projectRoot:r.getProjectRoot(),tag:i,complexityReportPath:r.getComplexityReportPath()},e.force)}catch(t){console.error(B.red(`Error expanding task ${e.id}: ${t.message}`)),process.exit(1)}}else console.error(B.red(`Error: You must specify either a task ID (--id) or --all.`)),t.help()}),t.command(`analyze-complexity`).description(`Analyze tasks and generate expansion recommendations${B.reset(``)}`).option(`-o, --output <file>`,`Output file path for the report`).option(`-m, --model <model>`,`LLM model to use for analysis (defaults to configured model)`).option(`-t, --threshold <number>`,`Minimum complexity score to recommend expansion (1-10)`,`5`).option(`-f, --file <file>`,`Path to the tasks file`,i).option(`-r, --research`,`Use configured research model for research-backed complexity analysis`).option(`-i, --id <ids>`,`Comma-separated list of specific task IDs to analyze (e.g., "1,3,5")`).option(`--from <id>`,`Starting task ID in a range to analyze`).option(`--to <id>`,`Ending task ID in a range to analyze`).option(`--tag <tag>`,`Specify tag context for task operations`).action(async e=>{let t={tasksPath:e.file||!0,tag:e.tag};e.output&&(t.complexityReportPath=e.output);let n=J(t);e.model,parseFloat(e.threshold);let r=e.research||!1,i=n.getCurrentTag();await k(i);let a=n.getComplexityReportPath();if(console.log(B.blue(`Analyzing task complexity from: ${n.getTasksPath()}`)),console.log(B.blue(`Output report will be saved to: ${a}`)),e.id)console.log(B.blue(`Analyzing specific task IDs: ${e.id}`));else if(e.from||e.to){let t=e.from?e.from:`first`,n=e.to?e.to:`last`;console.log(B.blue(`Analyzing tasks in range: ${t} to ${n}`))}r&&console.log(B.blue(`Using Perplexity AI for research-backed complexity analysis`)),await pe({...e,output:a,tag:i,projectRoot:n.getProjectRoot(),file:n.getTasksPath()})}),t.command(`research`).description(`Perform AI-powered research queries with project context`).argument(`[prompt]`,`Research prompt to investigate`).option(`--file <file>`,`Path to the tasks file`).option(`-i, --id <ids>`,`Comma-separated task/subtask IDs to include as context (e.g., "15,16.2")`).option(`-f, --files <paths>`,`Comma-separated file paths to include as context`).option(`-c, --context <text>`,`Additional custom context to include in the research prompt`).option(`-t, --tree`,`Include project file tree structure in the research context`).option(`-s, --save <file>`,`Save research results to the specified task/subtask(s)`).option(`-d, --detail <level>`,`Output detail level: low, medium, high`,`medium`).option(`--save-to <id>`,`Automatically save research results to specified task/subtask ID (e.g., "15" or "15.2")`).option(`--save-file`,`Save research results to .taskmaster/docs/research/ directory`).option(`--tag <tag>`,`Specify tag context for task operations`).action(async(e,t)=>{let n=J({tasksPath:t.file||!0,tag:t.tag});(!e||typeof e!=`string`||e.trim().length===0)&&(console.error(B.red(`Error: Research prompt is required and cannot be empty`)),p(),process.exit(1));let r=[`low`,`medium`,`high`];t.detail&&!r.includes(t.detail.toLowerCase())&&(console.error(B.red(`Error: Detail level must be one of: ${r.join(`, `)}`)),process.exit(1));let i=[];if(t.id)try{i=t.id.split(`,`).map(e=>{let t=e.trim();if(!/^\d+(\.\d+)?$/.test(t))throw Error(`Invalid task ID format: "${t}". Expected format: "15" or "15.2"`);return t})}catch(e){console.error(B.red(`Error parsing task IDs: ${e.message}`)),process.exit(1)}let a=[];if(t.files)try{a=t.files.split(`,`).map(e=>{let t=e.trim();if(t.length===0)throw Error(`Empty file path provided`);return t})}catch(e){console.error(B.red(`Error parsing file paths: ${e.message}`)),process.exit(1)}if(t.saveTo){let e=t.saveTo.trim();e.length===0&&(console.error(B.red(`Error: Save-to ID cannot be empty`)),process.exit(1)),/^\d+(\.\d+)?$/.test(e)||(console.error(B.red(`Error: Save-to ID must be in format "15" for task or "15.2" for subtask`)),process.exit(1))}if(t.save){let e=t.save.trim();e.length===0&&(console.error(B.red(`Error: Save target cannot be empty`)),process.exit(1)),(e.includes(`..`)||e.startsWith(`/`))&&(console.error(B.red(`Error: Save path must be relative and cannot contain ".."`)),process.exit(1))}let o=n.getCurrentTag();if(await k(o),i.length>0)try{let e=u(n.getTasksPath(),n.getProjectRoot(),o);(!e||!e.tasks)&&(console.error(B.red(`Error: No valid tasks found in ${n.getTasksPath()} for tag '${o}'`)),process.exit(1))}catch(e){console.error(B.red(`Error reading tasks file: ${e.message}`)),process.exit(1)}if(a.length>0)for(let e of a){let t=H.isAbsolute(e)?e:H.join(n.getProjectRoot(),e);V.existsSync(t)||(console.error(B.red(`Error: File not found: ${e}`)),process.exit(1))}let s={prompt:e.trim(),taskIds:i,filePaths:a,customContext:t.context?t.context.trim():null,includeProjectTree:!!t.tree,saveTarget:t.save?t.save.trim():null,saveToId:t.saveTo?t.saveTo.trim():null,allowFollowUp:!0,detailLevel:t.detail?t.detail.toLowerCase():`medium`,tasksPath:n.getTasksPath(),projectRoot:n.getProjectRoot()};console.log(B.blue(`Researching: "${s.prompt}"`)),s.taskIds.length>0&&console.log(B.gray(`Task context: ${s.taskIds.join(`, `)}`)),s.filePaths.length>0&&console.log(B.gray(`File context: ${s.filePaths.join(`, `)}`)),s.customContext&&console.log(B.gray(`Custom context: ${s.customContext.substring(0,50)}${s.customContext.length>50?`...`:``}`)),s.includeProjectTree&&console.log(B.gray(`Including project file tree`)),console.log(B.gray(`Detail level: ${s.detailLevel}`));try{let{performResearch:e}=await import(`./research-
|
|
109
|
+
To fix this issue:`)),console.log(` 1. Run task-master list to see all available task IDs`),console.log(` 2. Use valid task IDs with the --id parameter`)),_()&&console.error(e),process.exit(1)}}),Pe(t),t.command(`expand`).description(`Expand a task into subtasks using AI`).option(`-i, --id <id>`,`ID of the task to expand`).option(`-a, --all`,`Expand all pending tasks based on complexity analysis`).option(`-n, --num <number>`,`Number of subtasks to generate (uses complexity analysis by default if available)`).option(`-r, --research`,`Enable research-backed generation (e.g., using Perplexity)`,!1).option(`-p, --prompt <text>`,`Additional context for subtask generation`).option(`-f, --force`,`Force expansion even if subtasks exist`,!1).option(`--file <file>`,`Path to the tasks file (relative to project root)`,i).option(`-cr, --complexity-report <file>`,`Path to the complexity report file (use this to specify the complexity report, not --file)`).option(`--tag <tag>`,`Specify tag context for task operations`).action(async e=>{let n={tasksPath:e.file||!0,tag:e.tag};e.complexityReport&&(n.complexityReportPath=e.complexityReport);let r=J(n),i=r.getCurrentTag();if(await k(i),e.all){console.log(B.blue(`Expanding all pending tasks...`));try{await re(r.getTasksPath(),e.num,e.research,e.prompt,e.force,{projectRoot:r.getProjectRoot(),tag:i,complexityReportPath:r.getComplexityReportPath()})}catch(e){console.error(B.red(`Error expanding all tasks: ${e.message}`)),process.exit(1)}}else if(e.id){e.id||(console.error(B.red(`Error: Task ID is required unless using --all.`)),process.exit(1)),console.log(B.blue(`Expanding task ${e.id}...`));try{await fe(r.getTasksPath(),e.id,e.num,e.research,e.prompt,{projectRoot:r.getProjectRoot(),tag:i,complexityReportPath:r.getComplexityReportPath()},e.force)}catch(t){console.error(B.red(`Error expanding task ${e.id}: ${t.message}`)),process.exit(1)}}else console.error(B.red(`Error: You must specify either a task ID (--id) or --all.`)),t.help()}),t.command(`analyze-complexity`).description(`Analyze tasks and generate expansion recommendations${B.reset(``)}`).option(`-o, --output <file>`,`Output file path for the report`).option(`-m, --model <model>`,`LLM model to use for analysis (defaults to configured model)`).option(`-t, --threshold <number>`,`Minimum complexity score to recommend expansion (1-10)`,`5`).option(`-f, --file <file>`,`Path to the tasks file`,i).option(`-r, --research`,`Use configured research model for research-backed complexity analysis`).option(`-i, --id <ids>`,`Comma-separated list of specific task IDs to analyze (e.g., "1,3,5")`).option(`--from <id>`,`Starting task ID in a range to analyze`).option(`--to <id>`,`Ending task ID in a range to analyze`).option(`--tag <tag>`,`Specify tag context for task operations`).action(async e=>{let t={tasksPath:e.file||!0,tag:e.tag};e.output&&(t.complexityReportPath=e.output);let n=J(t);e.model,parseFloat(e.threshold);let r=e.research||!1,i=n.getCurrentTag();await k(i);let a=n.getComplexityReportPath();if(console.log(B.blue(`Analyzing task complexity from: ${n.getTasksPath()}`)),console.log(B.blue(`Output report will be saved to: ${a}`)),e.id)console.log(B.blue(`Analyzing specific task IDs: ${e.id}`));else if(e.from||e.to){let t=e.from?e.from:`first`,n=e.to?e.to:`last`;console.log(B.blue(`Analyzing tasks in range: ${t} to ${n}`))}r&&console.log(B.blue(`Using Perplexity AI for research-backed complexity analysis`)),await pe({...e,output:a,tag:i,projectRoot:n.getProjectRoot(),file:n.getTasksPath()})}),t.command(`research`).description(`Perform AI-powered research queries with project context`).argument(`[prompt]`,`Research prompt to investigate`).option(`--file <file>`,`Path to the tasks file`).option(`-i, --id <ids>`,`Comma-separated task/subtask IDs to include as context (e.g., "15,16.2")`).option(`-f, --files <paths>`,`Comma-separated file paths to include as context`).option(`-c, --context <text>`,`Additional custom context to include in the research prompt`).option(`-t, --tree`,`Include project file tree structure in the research context`).option(`-s, --save <file>`,`Save research results to the specified task/subtask(s)`).option(`-d, --detail <level>`,`Output detail level: low, medium, high`,`medium`).option(`--save-to <id>`,`Automatically save research results to specified task/subtask ID (e.g., "15" or "15.2")`).option(`--save-file`,`Save research results to .taskmaster/docs/research/ directory`).option(`--tag <tag>`,`Specify tag context for task operations`).action(async(e,t)=>{let n=J({tasksPath:t.file||!0,tag:t.tag});(!e||typeof e!=`string`||e.trim().length===0)&&(console.error(B.red(`Error: Research prompt is required and cannot be empty`)),p(),process.exit(1));let r=[`low`,`medium`,`high`];t.detail&&!r.includes(t.detail.toLowerCase())&&(console.error(B.red(`Error: Detail level must be one of: ${r.join(`, `)}`)),process.exit(1));let i=[];if(t.id)try{i=t.id.split(`,`).map(e=>{let t=e.trim();if(!/^\d+(\.\d+)?$/.test(t))throw Error(`Invalid task ID format: "${t}". Expected format: "15" or "15.2"`);return t})}catch(e){console.error(B.red(`Error parsing task IDs: ${e.message}`)),process.exit(1)}let a=[];if(t.files)try{a=t.files.split(`,`).map(e=>{let t=e.trim();if(t.length===0)throw Error(`Empty file path provided`);return t})}catch(e){console.error(B.red(`Error parsing file paths: ${e.message}`)),process.exit(1)}if(t.saveTo){let e=t.saveTo.trim();e.length===0&&(console.error(B.red(`Error: Save-to ID cannot be empty`)),process.exit(1)),/^\d+(\.\d+)?$/.test(e)||(console.error(B.red(`Error: Save-to ID must be in format "15" for task or "15.2" for subtask`)),process.exit(1))}if(t.save){let e=t.save.trim();e.length===0&&(console.error(B.red(`Error: Save target cannot be empty`)),process.exit(1)),(e.includes(`..`)||e.startsWith(`/`))&&(console.error(B.red(`Error: Save path must be relative and cannot contain ".."`)),process.exit(1))}let o=n.getCurrentTag();if(await k(o),i.length>0)try{let e=u(n.getTasksPath(),n.getProjectRoot(),o);(!e||!e.tasks)&&(console.error(B.red(`Error: No valid tasks found in ${n.getTasksPath()} for tag '${o}'`)),process.exit(1))}catch(e){console.error(B.red(`Error reading tasks file: ${e.message}`)),process.exit(1)}if(a.length>0)for(let e of a){let t=H.isAbsolute(e)?e:H.join(n.getProjectRoot(),e);V.existsSync(t)||(console.error(B.red(`Error: File not found: ${e}`)),process.exit(1))}let s={prompt:e.trim(),taskIds:i,filePaths:a,customContext:t.context?t.context.trim():null,includeProjectTree:!!t.tree,saveTarget:t.save?t.save.trim():null,saveToId:t.saveTo?t.saveTo.trim():null,allowFollowUp:!0,detailLevel:t.detail?t.detail.toLowerCase():`medium`,tasksPath:n.getTasksPath(),projectRoot:n.getProjectRoot()};console.log(B.blue(`Researching: "${s.prompt}"`)),s.taskIds.length>0&&console.log(B.gray(`Task context: ${s.taskIds.join(`, `)}`)),s.filePaths.length>0&&console.log(B.gray(`File context: ${s.filePaths.join(`, `)}`)),s.customContext&&console.log(B.gray(`Custom context: ${s.customContext.substring(0,50)}${s.customContext.length>50?`...`:``}`)),s.includeProjectTree&&console.log(B.gray(`Including project file tree`)),console.log(B.gray(`Detail level: ${s.detailLevel}`));try{let{performResearch:e}=await import(`./research-UCqjqHBo.js`),n={taskIds:s.taskIds,filePaths:s.filePaths,customContext:s.customContext||``,includeProjectTree:s.includeProjectTree,detailLevel:s.detailLevel,projectRoot:s.projectRoot,saveToFile:!!t.saveFile,tag:o},r=await e(s.prompt,n,{commandName:`research`,outputType:`cli`,tag:o},`text`,s.allowFollowUp);if(s.saveToId&&!r.interactiveSaveOccurred)try{let e=s.saveToId.includes(`.`),t=`## Research Query: ${s.prompt}
|
|
110
110
|
|
|
111
111
|
**Detail Level:** ${r.detailLevel}
|
|
112
112
|
**Context Size:** ${r.contextSize} characters
|
|
@@ -114,7 +114,7 @@ To fix this issue:`)),console.log(` 1. Run task-master list to see all availabl
|
|
|
114
114
|
|
|
115
115
|
### Results
|
|
116
116
|
|
|
117
|
-
${r.result}`;if(e){let{updateSubtaskById:e}=await import(`./update-subtask-by-id-
|
|
117
|
+
${r.result}`;if(e){let{updateSubtaskById:e}=await import(`./update-subtask-by-id-B3lz3TnC.js`);await e(s.tasksPath,s.saveToId,t,!1,{commandName:`research-save`,outputType:`cli`,projectRoot:s.projectRoot,tag:o},`text`),console.log(B.green(`✅ Research saved to subtask ${s.saveToId}`))}else{let e=(await import(`./update-task-by-id-YhPa_LeH.js`)).default,n=parseInt(s.saveToId,10);await e(s.tasksPath,n,t,!1,{commandName:`research-save`,outputType:`cli`,projectRoot:s.projectRoot,tag:o},`text`,!0),console.log(B.green(`✅ Research saved to task ${s.saveToId}`))}}catch(e){console.log(B.red(`❌ Error saving to task/subtask: ${e.message}`))}if(s.saveTarget){let e=`# Research Query: ${s.prompt}
|
|
118
118
|
|
|
119
119
|
**Detail Level:** ${r.detailLevel}
|
|
120
120
|
**Context Size:** ${r.contextSize} characters
|
|
@@ -309,7 +309,7 @@ Or specify profiles directly:
|
|
|
309
309
|
`));for(let e of t)console.log(` • ${e.displayName} ${B.gray(`(${e.markerPath})`)}`);console.log(``),e=t.map(e=>e.profileName)}else e=await I(i);if(!e||e.length===0){console.log(B.yellow(`No profiles selected. Exiting.`));return}console.log(B.blue(`Installing ${e.length} selected profile(s)...`));let{allSuccessfulProfiles:t,totalSuccess:n,totalFailed:a}=L(await F(e,i,r.mode));console.log(B.green(`\n✓ Successfully installed ${t.length} profile(s)`)),n>0&&console.log(B.gray(` ${n} files processed, ${a} failed`));return}(!t||t.length===0)&&(console.error(`Please specify at least one rule profile (e.g., windsurf, roo).`),process.exit(1));let a=t.flatMap(e=>e.split(`,`).map(e=>e.trim())).filter(Boolean);if(e===P.REMOVE){let e=!0;if(r.force||(e=Qe(i,a)?await gt(a,Ze(i)):await ht(a)),!e){console.log(B.yellow(`Aborted: No rules were removed.`));return}}let o=[],s=[];for(let t of a){if(!nt(t)){console.warn(`Rule profile for "${t}" not found. Valid profiles: ${z.join(`, `)}. Skipping.`);continue}let a=it(t);if(e===P.ADD){console.log(B.blue(`Adding rules for profile: ${t}...`));let e=ot(i,a,{mode:await n(r.mode)});console.log(B.blue(`Completed adding rules for profile: ${t}`)),s.push({profileName:t,success:e.success,failed:e.failed}),console.log(B.green(rt(t,e)))}else if(e===P.REMOVE){console.log(B.blue(`Removing rules for profile: ${t}...`));let e=tt(i,a);o.push(e),console.log(B.green(st(t,e)))}else console.error(`Unknown action. Use "${P.ADD}" or "${P.REMOVE}".`),process.exit(1)}if(e===P.ADD&&s.length>0){let{allSuccessfulProfiles:e,totalSuccess:t,totalFailed:n}=L(s);e.length>0&&(console.log(B.green(`\nSuccessfully processed profiles: ${e.join(`, `)}`)),t>0?console.log(B.green(`Total: ${t} files processed, ${n} failed.`)):console.log(B.green(`Total: ${e.length} profile(s) set up successfully.`)))}if(e===P.REMOVE&&o.length>0){let{successfulRemovals:e,skippedRemovals:t,failedRemovals:n,removalsWithNotices:r}=at(o);e.length>0&&console.log(B.green(`\nSuccessfully removed profiles for: ${e.join(`, `)}`)),t.length>0&&console.log(B.yellow(`Skipped (default or protected): ${t.join(`, `)}`)),n.length>0&&(console.log(B.red(`
|
|
310
310
|
Errors occurred:`)),n.forEach(e=>{console.log(B.red(` ${e.profileName}: ${e.error}`))})),r.length>0&&(console.log(B.cyan(`
|
|
311
311
|
Notices:`)),r.forEach(e=>{console.log(B.cyan(` ${e.profileName}: ${e.notice}`))}));let i=o.length,a=e.length,s=t.length,c=n.length;console.log(B.blue(`\nTotal: ${i} profile(s) processed - ${a} removed, ${s} skipped, ${c} failed.`))}}),t.command(`migrate`).description(`Migrate existing project to use the new .taskmaster directory structure`).option(`-f, --force`,`Force migration even if .taskmaster directory already exists`).option(`--backup`,`Create backup of old files before migration (default: false)`,!1).option(`--cleanup`,`Remove old files after successful migration (default: true)`,!0).option(`-y, --yes`,`Skip confirmation prompts`).option(`--dry-run`,`Show what would be migrated without actually moving files`).action(async e=>{try{await ie(e)}catch(e){console.error(B.red(`Error during migration:`),e.message),process.exit(1)}}),t.command(`sync-readme`).description(`Sync the current task list to README.md in the project root`).option(`-f, --file <file>`,`Path to the tasks file`,i).option(`--with-subtasks`,`Include subtasks in the README output`).option(`-s, --status <status>`,`Show only tasks matching this status (e.g., pending, done)`).option(`-t, --tag <tag>`,`Tag to use for the task list (default: master)`).action(async e=>{let t=J({tasksPath:e.file||!0,tag:e.tag}),n=e.withSubtasks||!1,r=e.status||null,i=t.getCurrentTag();console.log(B.blue(`📝 Syncing tasks to README.md${n?` (with subtasks)`:``}${r?` (status: ${r})`:``}...`)),await syncTasksToReadme(t.getProjectRoot(),{withSubtasks:n,status:r,tasksPath:t.getTasksPath(),tag:i})||(console.error(B.red(`❌ Failed to sync tasks to README.md`)),process.exit(1))}),t.command(`add-tag`).description(`[DEPRECATED] Create a new tag context for organizing tasks (use "tm tags add" instead)`).argument(`[tagName]`,`Name of the new tag to create (optional when using --from-branch)`).option(`-f, --file <file>`,`Path to the tasks file`,i).option(`--copy-from-current`,`Copy tasks from the current tag to the new tag`).option(`--copy-from <tag>`,`Copy tasks from the specified tag to the new tag`).option(`--from-branch`,`Create tag name from current git branch (ignores tagName argument)`).option(`-d, --description <text>`,`Optional description for the tag`).action(async(e,t)=>{console.warn(B.yellow(`⚠ Warning: "tm add-tag" is deprecated. Use "tm tags add" instead.`)),console.log(B.gray(` This command will be removed in a future version.
|
|
312
|
-
`));try{let n=J({tasksPath:t.file||!0}),r=n.getTasksPath();V.existsSync(r)||(console.error(B.red(`Error: Tasks file not found at path: ${r}`)),console.log(B.yellow(`Hint: Run task-master init or task-master parse-prd to create tasks.json first`)),process.exit(1)),!e&&!t.fromBranch&&(console.error(B.red(`Error: Either tagName argument or --from-branch option is required.`)),console.log(B.yellow(`Usage examples:`)),console.log(B.cyan(` task-master add-tag my-tag`)),console.log(B.cyan(` task-master add-tag --from-branch`)),process.exit(1));let i={projectRoot:n.getProjectRoot(),commandName:`add-tag`,outputType:`cli`};if(t.fromBranch){let{createTagFromBranch:e}=await import(`./tag-management-
|
|
312
|
+
`));try{let n=J({tasksPath:t.file||!0}),r=n.getTasksPath();V.existsSync(r)||(console.error(B.red(`Error: Tasks file not found at path: ${r}`)),console.log(B.yellow(`Hint: Run task-master init or task-master parse-prd to create tasks.json first`)),process.exit(1)),!e&&!t.fromBranch&&(console.error(B.red(`Error: Either tagName argument or --from-branch option is required.`)),console.log(B.yellow(`Usage examples:`)),console.log(B.cyan(` task-master add-tag my-tag`)),console.log(B.cyan(` task-master add-tag --from-branch`)),process.exit(1));let i={projectRoot:n.getProjectRoot(),commandName:`add-tag`,outputType:`cli`};if(t.fromBranch){let{createTagFromBranch:e}=await import(`./tag-management-BvgwEfuM.js`),r=await import(`./git-utils-PBP1PRVP.js`);await r.isGitRepository(i.projectRoot)||(console.error(B.red(`Error: Not in a git repository. Cannot use --from-branch option.`)),process.exit(1));let a=await r.getCurrentBranch(i.projectRoot);a||(console.error(B.red(`Error: Could not determine current git branch.`)),process.exit(1));let o={copyFromCurrent:t.copyFromCurrent||!1,copyFromTag:t.copyFrom,description:t.description||`Tag created from git branch "${a}"`};await e(n.getTasksPath(),a,o,i,`text`)}else{let r={copyFromCurrent:t.copyFromCurrent||!1,copyFromTag:t.copyFrom,description:t.description};await be(n.getTasksPath(),e,r,i,`text`)}if(t.autoSwitch){let{useTag:r}=await import(`./tag-management-BvgwEfuM.js`),a=t.fromBranch?(await import(`./git-utils-PBP1PRVP.js`)).sanitizeBranchNameForTag(await(await import(`./git-utils-PBP1PRVP.js`)).getCurrentBranch(projectRoot)):e;await r(n.getTasksPath(),a,{},i,`text`)}}catch(e){console.error(B.red(`Error creating tag: ${e.message}`)),l(),process.exit(1)}}).on(`error`,function(e){console.error(B.red(`Error: ${e.message}`)),l(),process.exit(1)}),t.command(`delete-tag`).description(`[DEPRECATED] Delete an existing tag and all its tasks (use "tm tags remove" instead)`).argument(`<tagName>`,`Name of the tag to delete`).option(`-f, --file <file>`,`Path to the tasks file`,i).option(`-y, --yes`,`Skip confirmation prompts`).action(async(e,t)=>{console.warn(B.yellow(`⚠ Warning: "tm delete-tag" is deprecated. Use "tm tags remove" instead.`)),console.log(B.gray(` This command will be removed in a future version.
|
|
313
313
|
`));try{let n=J({tasksPath:t.file||!0}),r=n.getTasksPath();V.existsSync(r)||(console.error(B.red(`Error: Tasks file not found at path: ${r}`)),process.exit(1));let i={yes:t.yes||!1},a={projectRoot:n.getProjectRoot(),commandName:`delete-tag`,outputType:`cli`};await He(n.getTasksPath(),e,i,a,`text`)}catch(e){console.error(B.red(`Error deleting tag: ${e.message}`)),d(),process.exit(1)}}).on(`error`,function(e){console.error(B.red(`Error: ${e.message}`)),d(),process.exit(1)}),t.command(`use-tag`).description(`[DEPRECATED] Switch to a different tag context (use "tm tags use" instead)`).argument(`<tagName>`,`Name of the tag to switch to`).option(`-f, --file <file>`,`Path to the tasks file`,i).action(async(e,t)=>{console.warn(B.yellow(`⚠ Warning: "tm use-tag" is deprecated. Use "tm tags use" instead.`)),console.log(B.gray(` This command will be removed in a future version.
|
|
314
314
|
`));try{let n=J({tasksPath:t.file||!0}),r=n.getTasksPath();V.existsSync(r)||(console.error(B.red(`Error: Tasks file not found at path: ${r}`)),process.exit(1));let i={projectRoot:n.getProjectRoot(),commandName:`use-tag`,outputType:`cli`};await Te(n.getTasksPath(),e,{},i,`text`)}catch(e){console.error(B.red(`Error switching tag: ${e.message}`)),f(),process.exit(1)}}).on(`error`,function(e){console.error(B.red(`Error: ${e.message}`)),f(),process.exit(1)}),t.command(`rename-tag`).description(`[DEPRECATED] Rename an existing tag (use "tm tags rename" instead)`).argument(`<oldName>`,`Current name of the tag`).argument(`<newName>`,`New name for the tag`).option(`-f, --file <file>`,`Path to the tasks file`,i).action(async(e,t,n)=>{console.warn(B.yellow(`⚠ Warning: "tm rename-tag" is deprecated. Use "tm tags rename" instead.`)),console.log(B.gray(` This command will be removed in a future version.
|
|
315
315
|
`));try{let r=J({tasksPath:n.file||!0}),i=r.getTasksPath();V.existsSync(i)||(console.error(B.red(`Error: Tasks file not found at path: ${i}`)),process.exit(1));let a={projectRoot:r.getProjectRoot(),commandName:`rename-tag`,outputType:`cli`};await xe(r.getTasksPath(),e,t,{},a,`text`)}catch(e){console.error(B.red(`Error renaming tag: ${e.message}`)),process.exit(1)}}).on(`error`,function(e){console.error(B.red(`Error: ${e.message}`)),process.exit(1)}),t.command(`copy-tag`).description(`[DEPRECATED] Copy an existing tag to create a new tag with the same tasks (use "tm tags copy" instead)`).argument(`<sourceName>`,`Name of the source tag to copy from`).argument(`<targetName>`,`Name of the new tag to create`).option(`-f, --file <file>`,`Path to the tasks file`,i).option(`-d, --description <text>`,`Optional description for the new tag`).action(async(e,t,n)=>{console.warn(B.yellow(`⚠ Warning: "tm copy-tag" is deprecated. Use "tm tags copy" instead.`)),console.log(B.gray(` This command will be removed in a future version.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{A as e,B as t,C as n,Cn as r,D as i,E as a,F as o,G as s,H as c,I as l,J as u,K as d,L as f,M as p,N as m,O as h,P as g,R as _,S as v,T as y,U as b,V as x,W as S,_ as C,a as w,b as T,bn as E,c as D,d as O,f as k,g as A,h as j,i as M,j as N,k as P,l as F,m as I,n as L,o as R,p as z,q as B,r as V,s as H,t as U,u as W,v as G,w as K,x as q,xn as J,y as Y,z as X}from"./config-manager-
|
|
1
|
+
import{A as e,B as t,C as n,Cn as r,D as i,E as a,F as o,G as s,H as c,I as l,J as u,K as d,L as f,M as p,N as m,O as h,P as g,R as _,S as v,T as y,U as b,V as x,W as S,_ as C,a as w,b as T,bn as E,c as D,d as O,f as k,g as A,h as j,i as M,j as N,k as P,l as F,m as I,n as L,o as R,p as z,q as B,r as V,s as H,t as U,u as W,v as G,w as K,x as q,xn as J,y as Y,z as X}from"./config-manager-Bj2cZEwZ.js";import"./git-utils-DllbRE35.js";export{E as ALL_PROVIDERS,J as CUSTOM_PROVIDERS,U as ConfigurationError,u as MODEL_MAP,r as VALIDATED_PROVIDERS,L as getAllProviders,V as getAnonymousTelemetryEnabled,M as getAvailableModels,w as getAzureBaseURL,R as getBaseUrlForRole,H as getBedrockBaseURL,D as getClaudeCodeSettings,F as getClaudeCodeSettingsForCommand,W as getCodebaseAnalysisMode,O as getCodexCliSettings,k as getCodexCliSettingsForCommand,z as getConfig,I as getDebugFlag,j as getDefaultNumTasks,A as getDefaultPriority,C as getDefaultSubtasks,G as getFallbackModelId,Y as getFallbackProvider,T as getGrokCliSettings,q as getGrokCliSettingsForCommand,v as getLogLevel,n as getMainModelId,K as getMainProvider,y as getMcpApiKeyStatus,a as getOllamaBaseURL,i as getOperatingMode,h as getParametersForRole,P as getProjectName,e as getProxyEnabled,N as getResearchModelId,p as getResearchProvider,m as getResponseLanguage,g as getSupportedModelsForProvider,o as getUserId,l as getVertexLocation,f as getVertexProjectId,_ as hasCodebaseAnalysis,X as isApiKeySet,t as isConfigFilePresent,x as isConfigWarningSuppressed,c as isProxyEnabled,b as setSuppressConfigWarnings,S as validateClaudeCodeSettings,s as validateCodexCliSettings,d as validateProvider,B as writeConfig};
|
|
@@ -311,7 +311,7 @@ Default to Chinese in user-facing replies unless the user explicitly requests an
|
|
|
311
311
|
`,`utf-8`),r.includes(`!.gitignore`)||await b(n,`!.gitignore
|
|
312
312
|
`,`utf-8`)}async syncTodoAndMap(e,t,n,r){let i=await this.tasksDomain.list({tag:e}),a=[],o=[],s=1;for(let e of i.tasks){a.push(this.toCsvRow(e,String(e.id),t,e.dependencies||[])),o.push({rowId:s,taskId:String(e.id),title:e.title,dependencies:e.dependencies||[]}),s++;for(let n of e.subtasks||[]){let r=`${e.id}.${n.id}`,i=(n.dependencies||[]).map(t=>{let n=String(t);return n.includes(`.`)?n:`${e.id}.${n}`});a.push(this.toCsvRow(n,r,t,i)),o.push({rowId:s,taskId:r,title:n.title||`Subtask ${n.id}`,dependencies:i}),s++}}if(await C(n.todoCsvPath,r===`lite`?this.renderLiteCsv(a):this.renderCsv(a),`utf-8`),r===`full`){let e={generatedAt:F(),rows:o};await C(n.mapPath,JSON.stringify(e,null,2),`utf-8`)}}toCsvRow(e,t,n,r){let i=this.mapStatus(e.status||`pending`,n,t);return{taskId:t,title:e.title||`Task ${t}`,status:i,acceptanceCriteria:e.testStrategy||``,validationCommand:`echo SKIP`,completedAt:i===`DONE`?F():``,retryCount:n.attempts[t]??0,notes:n.blockedTaskIds.includes(t)?`blocked by retry limit`:``,dependencies:r}}mapStatus(e,t,n){return t.doneTaskIds.includes(n)?`DONE`:t.blockedTaskIds.includes(n)?`FAILED`:e===`done`||e===`completed`?`DONE`:e===`in-progress`?`IN_PROGRESS`:e===`blocked`||e===`cancelled`||e===`deferred`?`FAILED`:`TODO`}renderCsv(e){return`id,task,status,acceptance_criteria,validation_command,completed_at,retry_count,notes\n${e.map((e,t)=>[t+1,I(`[${e.taskId}] ${e.title}`),e.status,I(e.acceptanceCriteria),I(e.validationCommand),I(e.completedAt),e.retryCount,I(e.notes)].join(`,`)).join(`
|
|
313
313
|
`)}\n`}renderLiteCsv(e){return`id,task,status,completed_at,notes\n${e.map((e,t)=>[t+1,I(`[${e.taskId}] ${e.title}`),this.mapStatusLite(e.status),I(e.completedAt),I(e.notes)].join(`,`)).join(`
|
|
314
|
-
`)}\n`}mapStatusLite(e){return e===`DONE`?`DONE`:`TODO`}async appendLedger(e,t){await b(e,`${JSON.stringify(t)}\n`,`utf-8`)}async loadCheckpoint(e){if(!await this.fileExists(e))return{updatedAt:F(),attempts:{},doneTaskIds:[],blockedTaskIds:[]};let t=await S(e,`utf-8`),n=JSON.parse(t);return{updatedAt:n.updatedAt||F(),attempts:n.attempts||{},doneTaskIds:n.doneTaskIds||[],blockedTaskIds:n.blockedTaskIds||[],lastTaskId:n.lastTaskId}}async saveCheckpoint(e,t){t.updatedAt=F(),await C(e,JSON.stringify(t,null,2),`utf-8`)}async fileExists(e){try{return await re(e),!0}catch{return!1}}pushUnique(e,t){return e.includes(t)?e:[...e,t]}resolveDefaultAgentsPath(){let e=t.join(this.projectRoot,`AGENTS.md`);return g(e),e}},hn=class{service=null;tasksDomain=null;projectRoot;constructor(e){this.projectRoot=e.getProjectRoot()}setTasksDomain(e){this.tasksDomain=e,this.service=new mn(this.projectRoot,this.tasksDomain)}async initAssets(e={}){return this.getService().initAssets(e)}async run(e={}){return this.getService().run(e)}getService(){if(!this.tasksDomain)throw Error(`SkillRunDomain is not initialized with TasksDomain`);return this.service||=new mn(this.projectRoot,this.tasksDomain),this.service}},gn=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 E(`Brief "${t}" not found in organization`,T.NOT_FOUND)}},_n=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 E(`Organization slug could not be extracted from input`,T.VALIDATION_ERROR);if(t.requireBrief&&!e.briefId)throw new E(`Brief identifier could not be extracted from input`,T.VALIDATION_ERROR)}},vn=class{briefService;authManager;constructor(){this.briefService=new gn,this.authManager=M.getInstance()}async resolveBrief(e,t){let n=_n.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 E(`No organization selected. Run "tm context org" first.`,T.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 E(`No organization context available`,T.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)}},yn=class{repository;projectId;apiClient;authManager;logger=O(`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 E(`Task ${e} not found`,T.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 E(`Task ${e} is missing a database ID. Task expansion requires tasks to be synced with the remote database.`,T.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(!w.uuid().safeParse(r.databaseId).success)throw new E(`Task ${e} has an invalid database ID format: ${r.databaseId}`,T.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 E?n.withContext({operation:`expandTask`,taskId:e,numSubtasks:t?.numSubtasks,useResearch:t?.useResearch}):new E(n instanceof Error?n.message:String(n),T.STORAGE_ERROR,{operation:`expandTask`,taskId:e,numSubtasks:t?.numSubtasks,useResearch:t?.useResearch},n)}}},bn=class{repository;projectId;apiClient;authManager;logger=O(`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 E(`Task ${e} not found`,T.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 E?t.withContext({operation:`getTask`,taskId:e}):new E(t instanceof Error?t.message:String(t),T.STORAGE_ERROR,{operation:`getTask`,taskId:e},t)}}},xn=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))}},Sn=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(`
|
|
314
|
+
`)}\n`}mapStatusLite(e){return e===`DONE`?`DONE`:`TODO`}async appendLedger(e,t){await b(e,`${JSON.stringify(t)}\n`,`utf-8`)}async loadCheckpoint(e){if(!await this.fileExists(e))return{updatedAt:F(),attempts:{},doneTaskIds:[],blockedTaskIds:[]};let t=await S(e,`utf-8`),n=JSON.parse(t);return{updatedAt:n.updatedAt||F(),attempts:n.attempts||{},doneTaskIds:n.doneTaskIds||[],blockedTaskIds:n.blockedTaskIds||[],lastTaskId:n.lastTaskId}}async saveCheckpoint(e,t){t.updatedAt=F(),await C(e,JSON.stringify(t,null,2),`utf-8`)}async fileExists(e){try{return await re(e),!0}catch{return!1}}pushUnique(e,t){return e.includes(t)?e:[...e,t]}resolveDefaultAgentsPath(){let e=t.join(this.projectRoot,`AGENTS.md`);return g(e),e}},hn=class{service=null;tasksDomain=null;projectRoot;constructor(e){this.projectRoot=e.getProjectRoot()}setTasksDomain(e){this.tasksDomain=e,this.service=new mn(this.projectRoot,this.tasksDomain)}async initAssets(e={}){return this.getService().initAssets(e)}async run(e={}){return this.getService().run(e)}getService(){if(!this.tasksDomain)throw Error(`SkillRunDomain is not initialized with TasksDomain`);return this.service||=new mn(this.projectRoot,this.tasksDomain),this.service}},gn=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 E(`Brief "${t}" not found in organization`,T.NOT_FOUND)}},_n=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 E(`Organization slug could not be extracted from input`,T.VALIDATION_ERROR);if(t.requireBrief&&!e.briefId)throw new E(`Brief identifier could not be extracted from input`,T.VALIDATION_ERROR)}},vn=class{briefService;authManager;constructor(){this.briefService=new gn,this.authManager=M.getInstance()}async resolveBrief(e,t){let n=_n.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 E(`No organization selected. Run "tm context org" first.`,T.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 E(`No organization context available`,T.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)}},yn=class{repository;projectId;apiClient;authManager;logger=O(`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 E(`Task ${e} not found`,T.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 E(`Task ${e} is missing a database ID. Task expansion requires tasks to be synced with the remote database.`,T.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(!w.uuid().safeParse(r.databaseId).success)throw new E(`Task ${e} has an invalid database ID format: ${r.databaseId}`,T.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 E?n.withContext({operation:`expandTask`,taskId:e,numSubtasks:t?.numSubtasks,useResearch:t?.useResearch}):new E(n instanceof Error?n.message:String(n),T.STORAGE_ERROR,{operation:`expandTask`,taskId:e,numSubtasks:t?.numSubtasks,useResearch:t?.useResearch},n)}}},bn=class{repository;projectId;apiClient;authManager;logger=O(`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 E(`Task ${e} not found`,T.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 E?t.withContext({operation:`getTask`,taskId:e}):new E(t instanceof Error?t.message:String(t),T.STORAGE_ERROR,{operation:`getTask`,taskId:e},t)}}},xn=class{static TASK_STATUS_OVERRIDES=new Set([`pending`,`in-progress`,`done`,`deferred`,`cancelled`,`blocked`,`review`,`completed`]);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),a=this.extractTaskMasterStatus(t.metadata)||this.mapStatus(t.status);return{id:t.display_id||String(r+1),parentId:e.id,title:t.title,description:t.description||``,status:a,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),a=this.extractTaskMasterStatus(e.metadata)||this.mapStatus(e.status);return{id:e.display_id||e.id,databaseId:e.id,title:e.title,description:e.description||``,status:a,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 extractTaskMasterStatus(e){let t=this.extractOptionalString(e,`taskMasterStatus`);if(t&&this.TASK_STATUS_OVERRIDES.has(t))return t}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))}},Sn=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(`
|
|
315
315
|
task_id,
|
|
316
316
|
depends_on_task:tasks!task_dependencies_depends_on_task_id_fkey (
|
|
317
317
|
display_id
|
|
@@ -331,7 +331,7 @@ Default to Chinese in user-facing replies unless the user explicitly requests an
|
|
|
331
331
|
title,
|
|
332
332
|
description
|
|
333
333
|
)
|
|
334
|
-
`).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{wn.parse(n)}catch(e){if(e instanceof w.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`)}}},En=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 E(`Not authenticated`,T.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 E?t:new E(t instanceof Error?t.message:String(t),T.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 E(n,T.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`})}},Dn=class{repository;projectId;enableRetry;maxRetries;initialized=!1;tagsCache=new Map;apiClient;expansionService;retrievalService;logger=O(`ApiStorage`);constructor(e){if(this.validateConfig(e),e.repository)this.repository=e.repository;else if(e.supabaseClient)this.repository=new Tn(e.supabaseClient);else throw new E(`Either repository or supabaseClient must be provided`,T.MISSING_CONFIGURATION);this.projectId=e.projectId,this.enableRetry=e.enableRetry??!0,this.maxRetries=e.maxRetries??3}validateConfig(e){if(!e.projectId)throw new E(`Project ID is required for API storage`,T.MISSING_CONFIGURATION);if(!e.repository&&!e.supabaseClient)throw new E(`Either repository or supabaseClient must be provided`,T.MISSING_CONFIGURATION)}async initialize(){if(!this.initialized)try{await this.loadTagsIntoCache(),this.initialized=!0}catch(e){throw new E(`Failed to initialize API storage`,T.STORAGE_ERROR,{operation:`initialize`},e)}}getStorageType(){return`api`}getCurrentBriefName(){return M.getInstance().getContext()?.briefName||null}async getTagsWithStats(){await this.ensureInitialized();try{return await new vn().getBriefsWithStats(this.repository,this.projectId)}catch(e){throw new E(`Failed to get tags with stats from API`,T.STORAGE_ERROR,{operation:`getTagsWithStats`},e)}}async loadTagsIntoCache(){try{let e=M.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=M.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 E(`Failed to save tasks to API`,T.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 E(`Failed to save task to API`,T.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 E(`Failed to delete task from API`,T.STORAGE_ERROR,{operation:`deleteTask`,taskId:e,tag:t},n)}}async listTags(){await this.ensureInitialized();try{let e=M.getInstance().getContext();return e?.briefId?(await this.loadTagsIntoCache(),[e.briefId]):[]}catch(e){throw new E(`Failed to list tags from API`,T.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 E(`Failed to load metadata from API`,T.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 E(`Failed to save metadata to API`,T.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 E(`Failed to append tasks to API`,T.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 E(`Failed to update task via API`,T.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 E?r.withContext({operation:`updateTaskWithPrompt`,taskId:e,tag:n,promptLength:t.length,mode:i}):new E(r instanceof Error?r.message:String(r),T.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{M.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 E(`Tag creation is not supported with API storage. Please create briefs through Hamster Studio.`,T.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 E(`Failed to delete tag via API`,T.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 E(`Failed to rename tag via API`,T.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 E(`Failed to copy tag via API`,T.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 E(`Failed to get stats from API`,T.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 E(`Failed to create backup via API`,T.STORAGE_ERROR,{operation:`backup`},e)}}async restore(e){throw await this.ensureInitialized(),new E(`Restore not implemented for API storage`,T.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 E(`Failed to clear data via API`,T.STORAGE_ERROR,{operation:`clear`},e)}}async close(){this.initialized=!1,this.tagsCache.clear()}async watch(e,t){await this.ensureInitialized();let n=M.getInstance(),r=n.getContext();if(!r?.briefId)throw new E(`No brief context found for watching. Please connect to a brief first.`,T.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 E(`API endpoint not configured. Please set TM_PUBLIC_BASE_DOMAIN environment variable.`,T.MISSING_CONFIGURATION,{operation:`getApiClient`});let t=M.getInstance().ensureBriefSelected(`getApiClient`);this.apiClient=new En({baseUrl:e,authManager:M.getInstance(),accountId:t.orgId})}return this.apiClient}getExpansionService(){if(!this.expansionService){let e=this.getApiClient(),t=M.getInstance();this.expansionService=new yn(this.repository,this.projectId,e,t)}return this.expansionService}getRetrievalService(){if(!this.retrievalService){let e=this.getApiClient(),t=M.getInstance();this.retrievalService=new bn(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 E&&e.is(T.NO_BRIEF_SELECTED)?e:new E(t,T.STORAGE_ERROR,n,e)}},On=class e{static normalizeStorageType(e){return e===`local`?`file`:typeof e==`string`&&e.length>0?e:`auto`}static async createFromStorageConfig(t,n){return e.create({storage:t,projectPath:n},n)}static async create(t,n){let r=e.normalizeStorageType(t.storage?.type),i=O(`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=M.getInstance();if(!await n.hasValidSession())throw new E(`API storage not fully configured (${e.join(`, `)||`credentials missing`}). Run: tm auth login, or set the missing field(s).`,T.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 E(`API endpoint could not be determined.`,T.MISSING_CONFIGURATION,{storageType:`api`});t.storage=e}}return i.info(`☁️ Using API storage`),e.createApiStorage(t);case`auto`:let a=M.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 E(`Unknown storage type: ${r}`,T.INVALID_INPUT,{storageType:r})}}static createFileStorage(e,t){return new Mt(t.storage?.basePath||e)}static createApiStorage(e){return new Dn({supabaseClient:Pe.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(t){let n=[],r=e.normalizeStorageType(t.storage?.type);if(!r)return n.push(`Storage type is not specified`),{isValid:!1,errors:n};switch(r){case`api`:t.storage?.apiEndpoint||n.push(`API endpoint is required for API storage`),t.storage?.apiAccessToken||n.push(`API access token is required for API storage`);break;case`file`:break;case`auto`:break;default:n.push(`Unknown storage type: ${r}`)}return{isValid:n.length===0,errors:n}}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){O(`StorageFactory`).warn(`Failed to initialize API storage, falling back to file storage:`,e)}return e.createFileStorage(n,t)}},kn=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 E(`Task ID is required and must be a string or number`,T.VALIDATION_ERROR);if(!e.title||e.title.trim().length===0)throw new E(`Task title is required`,T.VALIDATION_ERROR);if(!e.description||e.description.trim().length===0)throw new E(`Task description is required`,T.VALIDATION_ERROR);if(!this.isValidStatus(e.status))throw new E(`Invalid task status: ${e.status}`,T.VALIDATION_ERROR);if(!this.isValidPriority(e.priority))throw new E(`Invalid task priority: ${e.priority}`,T.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 E(`Task cannot be marked as complete`,T.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 E(`Invalid status: ${e}`,T.VALIDATION_ERROR);if(this.status===`done`&&e===`pending`)throw new E(`Cannot move completed task back to pending`,T.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))}},An=class{configManager;storage;initialized=!1;logger=O(`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 On.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=kn.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 E?t:(this.logger.error(`Failed to get task list`,t),new E(`Failed to get task list`,T.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 E?t:new E(`Failed to get task ${e}`,T.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 E(`Storage not initialized`,T.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 E?t:new E(`Failed to update task ${e}`,T.STORAGE_ERROR,{operation:`updateTask`,resource:`task`,taskId:i,tag:r},t)}}async updateTaskWithPrompt(e,t,n,r){if(!this.storage)throw new E(`Storage not initialized`,T.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 E?n:new E(`Failed to update task ${e} with prompt`,T.STORAGE_ERROR,{operation:`updateTaskWithPrompt`,resource:`task`,taskId:a,tag:i,promptLength:t.length},n)}}async expandTaskWithPrompt(e,t,n){if(!this.storage)throw new E(`Storage not initialized`,T.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 E?t:new E(`Failed to expand task ${e}`,T.STORAGE_ERROR,{operation:`expandTaskWithPrompt`,resource:`task`,taskId:i,tag:r,numSubtasks:n?.numSubtasks},t)}}async updateTaskStatus(e,t,n){if(!this.storage)throw new E(`Storage not initialized`,T.STORAGE_ERROR);let r=n||this.getActiveTag(),i=String(e);try{return await this.storage.updateTaskStatus(i,t,r)}catch(e){throw e instanceof E?e:new E(`Failed to update task status for ${i}`,T.STORAGE_ERROR,{operation:`updateTaskStatus`,resource:`task`,taskId:i,newStatus:t,tag:r},e)}}async getTagsWithStats(){if(!this.storage)throw new E(`Storage not initialized`,T.STORAGE_ERROR);this.initialized||await this.initialize();try{return await this.storage.getTagsWithStats()}catch(e){throw e instanceof E?e:new E(`Failed to get tags with stats`,T.STORAGE_ERROR,{operation:`getTagsWithStats`,resource:`tags`},e)}}async close(){this.storage&&await this.storage.close(),this.initialized=!1}},jn=class{constructor(e,t=process.cwd()){this.taskService=e,this.projectRoot=t}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;r&&i.subtasks&&(a=i.subtasks.find(e=>String(e.id)===r));let o=this.normalizeExecutor(t.executor);if(!t.dryRun&&o===`codex`){let e=Zt(this.projectRoot);if(!e.success)return{task:i,found:!0,started:!1,subtaskId:r,subtask:a,error:this.formatCodexPreflightError(e.errors)}}if(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 s=!1,c=`Task ready to execute`,l;return t.dryRun?(s=!0,c=`Dry run - task would be executed`,l=await this.prepareExecutionCommand(i,a,o)):(l=await this.prepareExecutionCommand(i,a,o),s=!!l,c=l?`Command prepared: ${l.executable} ${l.args.join(` `)}`:`Failed to prepare execution command`),{task:i,found:!0,started:s,subtaskId:r,subtask:a,executionOutput:c,command:l||void 0}}catch(e){return{task:null,found:!1,started:!1,error:e instanceof Error?e.message:String(e)}}}formatCodexPreflightError(e){return`Codex execution blocked by permission preflight checks:\n${e.map(e=>`- ${e}`).join(`
|
|
334
|
+
`).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(),i;try{wn.parse(n)}catch(e){if(e instanceof w.ZodError){let t=e.issues.map(e=>`${e.path.join(`.`)}: ${e.message}`).join(`, `);throw Error(`Invalid task update data: ${t}`)}throw e}let a={};n.title!==void 0&&(a.title=n.title),n.description!==void 0&&(a.description=n.description),n.status!==void 0&&(a.status=this.mapStatusToDatabase(n.status),i=this.getStatusOverrideForMetadata(n.status)),n.priority!==void 0&&(a.priority=this.mapPriorityToDatabase(n.priority));let{data:o,error:s}=await this.supabase.from(`tasks`).select(`metadata`).eq(`brief_id`,r).eq(`display_id`,t.toUpperCase()).single();if(s)throw Error(`Failed to load existing task metadata: ${s.message}`);let c={...o?.metadata??{}};n.status!==void 0&&(i?c.taskMasterStatus=i:delete c.taskMasterStatus),n.details!==void 0&&(c.details=n.details),n.testStrategy!==void 0&&(c.testStrategy=n.testStrategy),Object.keys(c).length>0&&(a.metadata=c);let{error:l}=await this.supabase.from(`tasks`).update(a).eq(`brief_id`,r).eq(`display_id`,t.toUpperCase());if(l)throw Error(`Failed to update task: ${l.message}`);let u=await this.getTask(e,t);if(!u)throw Error(`Failed to retrieve updated task ${t}`);return u}mapStatusToDatabase(e){switch(e){case`pending`:case`deferred`:return`todo`;case`in-progress`:case`in_progress`:case`review`:case`blocked`:return`in_progress`;case`done`:case`completed`:case`cancelled`:return`done`;default:throw Error(`Invalid task status: ${e}. Valid statuses are: pending, in-progress, done, review, deferred, cancelled, blocked`)}}getStatusOverrideForMetadata(e){switch(e){case`review`:case`deferred`:case`cancelled`:case`blocked`:return e;default:return}}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`)}}},En=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 E(`Not authenticated`,T.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 E?t:new E(t instanceof Error?t.message:String(t),T.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 E(n,T.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`})}},Dn=class{repository;projectId;enableRetry;maxRetries;initialized=!1;tagsCache=new Map;apiClient;expansionService;retrievalService;logger=O(`ApiStorage`);constructor(e){if(this.validateConfig(e),e.repository)this.repository=e.repository;else if(e.supabaseClient)this.repository=new Tn(e.supabaseClient);else throw new E(`Either repository or supabaseClient must be provided`,T.MISSING_CONFIGURATION);this.projectId=e.projectId,this.enableRetry=e.enableRetry??!0,this.maxRetries=e.maxRetries??3}validateConfig(e){if(!e.projectId)throw new E(`Project ID is required for API storage`,T.MISSING_CONFIGURATION);if(!e.repository&&!e.supabaseClient)throw new E(`Either repository or supabaseClient must be provided`,T.MISSING_CONFIGURATION)}async initialize(){if(!this.initialized)try{await this.loadTagsIntoCache(),this.initialized=!0}catch(e){throw new E(`Failed to initialize API storage`,T.STORAGE_ERROR,{operation:`initialize`},e)}}getStorageType(){return`api`}getCurrentBriefName(){return M.getInstance().getContext()?.briefName||null}async getTagsWithStats(){await this.ensureInitialized();try{return await new vn().getBriefsWithStats(this.repository,this.projectId)}catch(e){throw new E(`Failed to get tags with stats from API`,T.STORAGE_ERROR,{operation:`getTagsWithStats`},e)}}async loadTagsIntoCache(){try{let e=M.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=M.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 E(`Failed to save tasks to API`,T.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 E(`Failed to save task to API`,T.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 E(`Failed to delete task from API`,T.STORAGE_ERROR,{operation:`deleteTask`,taskId:e,tag:t},n)}}async listTags(){await this.ensureInitialized();try{let e=M.getInstance().getContext();return e?.briefId?(await this.loadTagsIntoCache(),[e.briefId]):[]}catch(e){throw new E(`Failed to list tags from API`,T.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 E(`Failed to load metadata from API`,T.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 E(`Failed to save metadata to API`,T.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 E(`Failed to append tasks to API`,T.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 E(`Failed to update task via API`,T.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 E?r.withContext({operation:`updateTaskWithPrompt`,taskId:e,tag:n,promptLength:t.length,mode:i}):new E(r instanceof Error?r.message:String(r),T.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{M.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 E(`Tag creation is not supported with API storage. Please create briefs through Hamster Studio.`,T.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 E(`Failed to delete tag via API`,T.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 E(`Failed to rename tag via API`,T.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 E(`Failed to copy tag via API`,T.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 E(`Failed to get stats from API`,T.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 E(`Failed to create backup via API`,T.STORAGE_ERROR,{operation:`backup`},e)}}async restore(e){throw await this.ensureInitialized(),new E(`Restore not implemented for API storage`,T.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 E(`Failed to clear data via API`,T.STORAGE_ERROR,{operation:`clear`},e)}}async close(){this.initialized=!1,this.tagsCache.clear()}async watch(e,t){await this.ensureInitialized();let n=M.getInstance(),r=n.getContext();if(!r?.briefId)throw new E(`No brief context found for watching. Please connect to a brief first.`,T.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 E(`API endpoint not configured. Please set TM_PUBLIC_BASE_DOMAIN environment variable.`,T.MISSING_CONFIGURATION,{operation:`getApiClient`});let t=M.getInstance().ensureBriefSelected(`getApiClient`);this.apiClient=new En({baseUrl:e,authManager:M.getInstance(),accountId:t.orgId})}return this.apiClient}getExpansionService(){if(!this.expansionService){let e=this.getApiClient(),t=M.getInstance();this.expansionService=new yn(this.repository,this.projectId,e,t)}return this.expansionService}getRetrievalService(){if(!this.retrievalService){let e=this.getApiClient(),t=M.getInstance();this.retrievalService=new bn(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 E&&e.is(T.NO_BRIEF_SELECTED)?e:new E(t,T.STORAGE_ERROR,n,e)}},On=class e{static normalizeStorageType(e){return e===`local`?`file`:typeof e==`string`&&e.length>0?e:`auto`}static async createFromStorageConfig(t,n){return e.create({storage:t,projectPath:n},n)}static async create(t,n){let r=e.normalizeStorageType(t.storage?.type),i=O(`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=M.getInstance();if(!await n.hasValidSession())throw new E(`API storage not fully configured (${e.join(`, `)||`credentials missing`}). Run: tm auth login, or set the missing field(s).`,T.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 E(`API endpoint could not be determined.`,T.MISSING_CONFIGURATION,{storageType:`api`});t.storage=e}}return i.info(`☁️ Using API storage`),e.createApiStorage(t);case`auto`:let a=M.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 E(`Unknown storage type: ${r}`,T.INVALID_INPUT,{storageType:r})}}static createFileStorage(e,t){return new Mt(t.storage?.basePath||e)}static createApiStorage(e){return new Dn({supabaseClient:Pe.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(t){let n=[],r=e.normalizeStorageType(t.storage?.type);if(!r)return n.push(`Storage type is not specified`),{isValid:!1,errors:n};switch(r){case`api`:t.storage?.apiEndpoint||n.push(`API endpoint is required for API storage`),t.storage?.apiAccessToken||n.push(`API access token is required for API storage`);break;case`file`:break;case`auto`:break;default:n.push(`Unknown storage type: ${r}`)}return{isValid:n.length===0,errors:n}}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){O(`StorageFactory`).warn(`Failed to initialize API storage, falling back to file storage:`,e)}return e.createFileStorage(n,t)}},kn=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 E(`Task ID is required and must be a string or number`,T.VALIDATION_ERROR);if(!e.title||e.title.trim().length===0)throw new E(`Task title is required`,T.VALIDATION_ERROR);if(!e.description||e.description.trim().length===0)throw new E(`Task description is required`,T.VALIDATION_ERROR);if(!this.isValidStatus(e.status))throw new E(`Invalid task status: ${e.status}`,T.VALIDATION_ERROR);if(!this.isValidPriority(e.priority))throw new E(`Invalid task priority: ${e.priority}`,T.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 E(`Task cannot be marked as complete`,T.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 E(`Invalid status: ${e}`,T.VALIDATION_ERROR);if(this.status===`done`&&e===`pending`)throw new E(`Cannot move completed task back to pending`,T.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))}},An=class{configManager;storage;initialized=!1;logger=O(`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 On.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=kn.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 E?t:(this.logger.error(`Failed to get task list`,t),new E(`Failed to get task list`,T.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 E?t:new E(`Failed to get task ${e}`,T.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 E(`Storage not initialized`,T.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 E?t:new E(`Failed to update task ${e}`,T.STORAGE_ERROR,{operation:`updateTask`,resource:`task`,taskId:i,tag:r},t)}}async updateTaskWithPrompt(e,t,n,r){if(!this.storage)throw new E(`Storage not initialized`,T.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 E?n:new E(`Failed to update task ${e} with prompt`,T.STORAGE_ERROR,{operation:`updateTaskWithPrompt`,resource:`task`,taskId:a,tag:i,promptLength:t.length},n)}}async expandTaskWithPrompt(e,t,n){if(!this.storage)throw new E(`Storage not initialized`,T.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 E?t:new E(`Failed to expand task ${e}`,T.STORAGE_ERROR,{operation:`expandTaskWithPrompt`,resource:`task`,taskId:i,tag:r,numSubtasks:n?.numSubtasks},t)}}async updateTaskStatus(e,t,n){if(!this.storage)throw new E(`Storage not initialized`,T.STORAGE_ERROR);let r=n||this.getActiveTag(),i=String(e);try{return await this.storage.updateTaskStatus(i,t,r)}catch(e){throw e instanceof E?e:new E(`Failed to update task status for ${i}`,T.STORAGE_ERROR,{operation:`updateTaskStatus`,resource:`task`,taskId:i,newStatus:t,tag:r},e)}}async getTagsWithStats(){if(!this.storage)throw new E(`Storage not initialized`,T.STORAGE_ERROR);this.initialized||await this.initialize();try{return await this.storage.getTagsWithStats()}catch(e){throw e instanceof E?e:new E(`Failed to get tags with stats`,T.STORAGE_ERROR,{operation:`getTagsWithStats`,resource:`tags`},e)}}async close(){this.storage&&await this.storage.close(),this.initialized=!1}},jn=class{constructor(e,t=process.cwd()){this.taskService=e,this.projectRoot=t}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;r&&i.subtasks&&(a=i.subtasks.find(e=>String(e.id)===r));let o=this.normalizeExecutor(t.executor);if(!t.dryRun&&o===`codex`){let e=Zt(this.projectRoot);if(!e.success)return{task:i,found:!0,started:!1,subtaskId:r,subtask:a,error:this.formatCodexPreflightError(e.errors)}}if(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 s=!1,c=`Task ready to execute`,l;return t.dryRun?(s=!0,c=`Dry run - task would be executed`,l=await this.prepareExecutionCommand(i,a,o)):(l=await this.prepareExecutionCommand(i,a,o),s=!!l,c=l?`Command prepared: ${l.executable} ${l.args.join(` `)}`:`Failed to prepare execution command`),{task:i,found:!0,started:s,subtaskId:r,subtask:a,executionOutput:c,command:l||void 0}}catch(e){return{task:null,found:!1,started:!1,error:e instanceof Error?e.message:String(e)}}}formatCodexPreflightError(e){return`Codex execution blocked by permission preflight checks:\n${e.map(e=>`- ${e}`).join(`
|
|
335
335
|
`)}`}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:this.projectRoot}}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 Mn=O(`TaskLoader`);var Nn=class{taskService;constructor(e){if(!e)throw Error(`taskService is required for TaskLoaderService`);this.taskService=e}async loadAndValidateTask(e){Mn.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?(Mn.info(`Task ${e} validated successfully`),{success:!0,task:t}):a}async loadTask(e){try{return await this.taskService.getTask(e)}catch(t){return Mn.error(`Failed to load task ${e}:`,t),null}}validateTaskStatus(e){return et(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(`
|
|
336
336
|
Expand this task using:`),t.push(` task-master expand --id=${e.id}`),e.complexity||e.recommendedSubtasks?(t.push(`
|
|
337
337
|
This task has complexity analysis available. Consider reviewing it first:`),t.push(` task-master show ${e.id}`)):(t.push(`
|