taskgraph-ai 0.52.11 → 0.52.12

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.
Files changed (31) hide show
  1. package/README.md +1 -1
  2. package/dist/ai-services-unified-BuoDs5zU.js +1 -0
  3. package/dist/ai-services-unified-D8LfWQ4S.js +3 -0
  4. package/dist/commands-Brsl3ZyL.js +210 -0
  5. package/dist/config-manager-BxNrtquR.js +1 -0
  6. package/dist/config-manager-CkwCWw53.js +1 -0
  7. package/dist/{dependency-manager-BNuzpRxe.js → dependency-manager-DRkIU6DR.js} +250 -259
  8. package/dist/{init-Br1q26E_.js → init-Cp1ZIvlh.js} +2 -2
  9. package/dist/mcp-server.js +2 -2
  10. package/dist/research-Cf8YeyqJ.js +1 -0
  11. package/dist/{response-language-CqZN1IYx.js → response-language-BhegpO-l.js} +1 -1
  12. package/dist/response-language-CvMcnuEd.js +1 -0
  13. package/dist/src-BaM893RS.js +207 -0
  14. package/dist/{tag-management-CkNrbDLJ.js → tag-management-DILdqQSS.js} +1 -1
  15. package/dist/{task-manager-BLj8tYbK.js → task-manager-L39eOUEz.js} +1 -1
  16. package/dist/taskgraph.js +1 -1
  17. package/dist/update-subtask-by-id-Dlk8IQru.js +1 -0
  18. package/dist/update-task-by-id-C1xnfWPp.js +1 -0
  19. package/dist/utils-CvXyXTNj.js +1 -0
  20. package/package.json +1 -1
  21. package/dist/ai-services-unified-BqZ9r6Q8.js +0 -3
  22. package/dist/ai-services-unified-l4nu72xN.js +0 -1
  23. package/dist/commands-Yp9dzlw9.js +0 -231
  24. package/dist/config-manager-B1nHXTtI.js +0 -1
  25. package/dist/config-manager-IVQuG97S.js +0 -1
  26. package/dist/research-B4CJNeH-.js +0 -1
  27. package/dist/response-language-Cw_fpdcD.js +0 -1
  28. package/dist/src-BU-pXNlJ.js +0 -207
  29. package/dist/update-subtask-by-id-10dvm_d3.js +0 -1
  30. package/dist/update-task-by-id-C-cp0e4c.js +0 -1
  31. package/dist/utils-B1bWwygv.js +0 -1
package/README.md CHANGED
@@ -71,7 +71,7 @@ TaskGraph turns a product requirements document (PRD) into a dependency-aware ta
71
71
 
72
72
  ## Set up in Claude Code
73
73
 
74
- You need [Claude Code](https://docs.claude.com/en/docs/claude-code) installed and signed in (run `claude` once) and Node.js 22 or later.
74
+ You need [Claude Code](https://docs.claude.com/en/docs/claude-code) installed and signed in (run `claude` once) and Node.js 22.13 or later.
75
75
 
76
76
  ### 1. Install
77
77
 
@@ -0,0 +1 @@
1
+ export{r as logAiUsage}from"./ai-services-unified-D8LfWQ4S.js";
@@ -0,0 +1,3 @@
1
+ import{D as e,Q as t,S as n,b as r,d as i,h as a,i as o,j as s,lt as c,m as l,nt as u,o as d,p as f,q as p,u as m,v as h,x as g,y as _}from"./config-manager-BxNrtquR.js";import{createRequire as v}from"node:module";import{execSync as y}from"child_process";import{createClaudeCode as b}from"ai-sdk-provider-claude-code";import*as x from"ai";import{jsonrepair as S}from"jsonrepair";import{EnvHttpProxyAgent as C}from"undici";var w=Object.defineProperty,T=(e,t)=>{let n={};for(var r in e)w(n,r,{get:e[r],enumerable:!0});return t||w(n,Symbol.toStringTag,{value:`Module`}),n},E=/* @__PURE__ */ v(import.meta.url);const{JSONParseError:D,NoObjectGeneratedError:O,generateObject:k,generateText:A,streamObject:j,streamText:ee,zodSchema:te}=x,M=x.jsonSchema,N=/* @__PURE__ */ new Set([`minimum`,`maximum`,`exclusiveMinimum`,`exclusiveMaximum`]),P=[`additionalProperties`,`contains`,`if`,`then`,`else`,`not`,`propertyNames`],F=[`allOf`,`anyOf`,`oneOf`,`prefixItems`],I=[`definitions`,`$defs`,`dependentSchemas`,`patternProperties`,`properties`],ne=e=>e?Array.isArray(e)?e.includes(`integer`):e===`integer`:!1,L=e=>{if(!e||typeof e!=`object`)return e;if(Array.isArray(e))return e.map(L);let t={...e};if(ne(t.type))for(let e of N)e in t&&delete t[e];for(let e of P)t[e]&&(t[e]=L(t[e]));for(let e of F)Array.isArray(t[e])&&(t[e]=t[e].map(L));for(let e of I)if(t[e]&&typeof t[e]==`object`){let n={};for(let[r,i]of Object.entries(t[e]))n[r]=L(i);t[e]=n}return t.items&&=L(t.items),t},R=e=>{let t=te(e);if(!t||typeof t!=`object`||!t.jsonSchema)return t;let n=L(t.jsonSchema);return typeof M==`function`?M(n,{validate:t.validate}):{...t,jsonSchema:n}};var z=class t{constructor(){if(this.constructor===t)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||=p();let t=this._projectRoot;if(e(null,t))return this._proxyAgent||=new C,(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 u(`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))}}prepareMessages(e){let t=e.filter(e=>e.role===`system`);return t.length===0?{messages:e}:{instructions:t.map(e=>typeof e.content==`string`?e.content:e.content.map(e=>e.text??``).join(``)).join(`
2
+
3
+ `),messages:e.filter(e=>e.role!==`system`)}}async generateText(e){try{this.validateParams(e),this.validateMessages(e.messages),u(`debug`,`Generating ${this.name} text with model: ${e.modelId}`);let t=await this.getClient(e),n=await A({model:t(e.modelId),...this.prepareMessages(e.messages),...this.prepareTokenParam(e.modelId,e.maxTokens),...this.supportsTemperature&&e.temperature!==void 0?{temperature:e.temperature}:{}});u(`debug`,`${this.name} generateText completed successfully for model: ${e.modelId}`);let r=n.usage?.inputTokens??n.usage?.promptTokens??0,i=n.usage?.outputTokens??n.usage?.completionTokens??0,a=n.usage?.totalTokens??r+i,o=n.usage?.inputTokenDetails?.cacheReadTokens??n.usage?.cachedInputTokens??0;return{text:n.text,usage:{inputTokens:r,outputTokens:i,totalTokens:a,cachedInputTokens:o}}}catch(e){this.handleError(`text generation`,e)}}async streamText(e){try{this.validateParams(e),this.validateMessages(e.messages),u(`debug`,`Streaming ${this.name} text with model: ${e.modelId}`);let t=await this.getClient(e),n=await ee({model:t(e.modelId),...this.prepareMessages(e.messages),...this.prepareTokenParam(e.modelId,e.maxTokens),...this.supportsTemperature&&e.temperature!==void 0?{temperature:e.temperature}:{},...e.experimental_transform&&{experimental_transform:e.experimental_transform}});return u(`debug`,`${this.name} streamText initiated successfully for model: ${e.modelId}`),n}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`);u(`debug`,`Streaming ${this.name} object with model: ${e.modelId}`);let t=await this.getClient(e),n=R(e.schema),r=await j({model:t(e.modelId),...this.prepareMessages(e.messages),schema:n,mode:this.needsExplicitJsonSchema?`json`:`auto`,...e.objectName&&{schemaName:e.objectName,schemaDescription:`Generate a valid JSON object for ${e.objectName}`},maxTokens:e.maxTokens,...this.supportsTemperature&&e.temperature!==void 0?{temperature:e.temperature}:{},onError:({error:e})=>u(`debug`,`${this.name} stream error: ${e?.message??e}`)});return u(`debug`,`${this.name} streamObject initiated successfully for model: ${e.modelId}`),r}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`);u(`debug`,`Generating ${this.name} object ('${e.objectName}') with model: ${e.modelId}`);let t=await this.getClient(e),n=R(e.schema),r=await k({model:t(e.modelId),...this.prepareMessages(e.messages),schema:n,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}:{}});u(`debug`,`${this.name} generateObject completed successfully for model: ${e.modelId}`);let i=r.usage?.inputTokens??r.usage?.promptTokens??0,a=r.usage?.outputTokens??r.usage?.completionTokens??0,o=r.usage?.totalTokens??i+a,s=r.usage?.inputTokenDetails?.cacheReadTokens??r.usage?.cachedInputTokens??0;return{object:r.object,usage:{inputTokens:i,outputTokens:a,totalTokens:o,cachedInputTokens:s}}}catch(e){if(O.isInstance(e)&&e.cause instanceof D&&e.cause.text){u(`warn`,`${this.name} generated malformed JSON, attempting to repair...`);try{let t=S(e.cause.text),n=JSON.parse(t);return u(`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){u(`error`,`Failed to repair ${this.name} JSON: ${e.message}`)}}this.handleError(`object generation`,e)}}};let B=!1;const V=[`WebSearch`,`WebFetch`],H=[`Read`,`Grep`,`Glob`];function U(e,t){let n=e===`research`,r=n?V:H;return{tools:[...r],allowedTools:[...r],permissionMode:`dontAsk`,permissionPrompts:`none`,strictMcpConfig:!0,mcpServers:{},...n&&{settingSources:[],maxTurns:t.maxTurns??8}}}var W=class extends z{constructor(){super(),this.name=`Claude Code`,this.supportedModels=g(`claude-code`),this.supportedModels.length===0&&u(`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`&&!B&&!process.env.CLAUDE_CODE_OAUTH_TOKEN)try{y(`claude --version`,{stdio:`pipe`,timeout:1e3})}catch{u(`debug`,"No `claude` on PATH; using the Claude Code bundled with the Agent SDK")}finally{B=!0}}getClient(e={}){try{let t=o(e.commandName)||{},n={...process.env};return process.env.CLAUDE_CODE_API_KEY?n.ANTHROPIC_API_KEY=process.env.CLAUDE_CODE_API_KEY:delete n.ANTHROPIC_API_KEY,b({defaultSettings:{systemPrompt:{type:`preset`,preset:`claude_code`},settingSources:[`user`,`project`,`local`],env:n,logger:{debug:e=>u(`debug`,e),info:e=>u(`debug`,e),warn:e=>u(`debug`,e),error:e=>u(`error`,e)},...t,...U(e.role,t)}})}catch(e){let t=String(e?.message||``);if(e?.code===`ENOENT`||/claude/i.test(t)){let t=/* @__PURE__ */ 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}};let G=null;var K=class e{constructor(){this._providers=/* @__PURE__ */ new Map,this._initialized=!1}static getInstance(){return G||=new e,G}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:/* @__PURE__ */ 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}};K.getInstance().initialize(),globalThis.AI_SDK_LOG_WARNINGS===void 0&&(globalThis.AI_SDK_LOG_WARNINGS=({warnings:e,provider:t,model:n})=>{for(let r of e){let e=r.message||r.feature||r.setting||r.type;u(`debug`,`AI SDK warning (${t??`?`}/${n??`?`}): ${e}`)}});const q={"claude-code":new W};function J(e){if(q[e])return q[e];let t=K.getInstance();return t.hasProvider(e)?(u(`debug`,`Provider "${e}" found in dynamic registry`),t.getProvider(e)):null}function Y(e,t){let n={inputCost:0,outputCost:0,currency:`USD`,isUnknown:!1};if(!s||!s[e])return u(`warn`,`Provider "${e}" not found in MODEL_MAP. Cannot determine cost for model ${t}.`),{...n,isUnknown:!0};let r=s[e].find(e=>e.id===t);if(!r)return u(`debug`,`Model "${t}" not found under provider "${e}". Assuming unknown cost.`),{...n,isUnknown:!0};if(r.cost_per_1m_tokens===null)return u(`debug`,`Cost data is null for model "${t}" under provider "${e}". Pricing unknown.`),{...n,isUnknown:!0};if(r.cost_per_1m_tokens===void 0)return u(`debug`,`Cost data not found for model "${t}" under provider "${e}". Pricing unknown.`),{...n,isUnknown:!0};let i=r.cost_per_1m_tokens;return{inputCost:i.input||0,outputCost:i.output||0,currency:i.currency||`USD`,isUnknown:!1}}function X(e,t,n,r){let i=(e||0)/1e6*n+(t||0)/1e6*r;return parseFloat(i.toFixed(6))}function re(e){let n={currentTag:`master`,availableTags:[`master`]};try{return e?{currentTag:t(e)||`master`,availableTags:ie(e)}:n}catch(e){return d()&&u(`debug`,`Error getting tag information: ${e.message}`),n}}function ie(e){let t=[`master`];try{let n=E(`path`),r=E(`fs`),i=n.join(e,`.taskgraph`,`tasks`,`tasks.json`);if(!r.existsSync(i))return t;let a=JSON.parse(r.readFileSync(i,`utf8`));if(!a||typeof a!=`object`)return t;let o=Object.keys(a).filter(e=>ae(a[e]));return o.length>0?o:t}catch(e){return d()&&u(`debug`,`Could not read tasks file for available tags: ${e.message}`),t}}function ae(e){return e&&typeof e==`object`&&Array.isArray(e.tasks)}function oe(e){let t=e.message?.toLowerCase()||``;return t.includes(`rate limit`)||t.includes(`overloaded`)||t.includes(`service temporarily unavailable`)||t.includes(`timeout`)||t.includes(`network error`)||e.status===429||e.status>=500}function se(e){try{if(e?.data?.error?.message)return e.data.error.message;if(e?.error?.message)return e.error.message;if(typeof e?.responseBody==`string`)try{let t=JSON.parse(e.responseBody);if(t?.error?.message)return t.error.message}catch{}return typeof e?.message==`string`&&e.message?e.message:typeof e==`string`?e:`An unknown AI service error occurred.`}catch{return`Failed to extract error message.`}}function ce(e,t){return{main:{provider:l(t),modelId:f(t)},research:{provider:_(t),modelId:h(t)},fallback:{provider:i(t),modelId:m(t)}}[e]||null}function Z(e,t,n=null){let r=J(e);if(!r)throw Error(`Unknown provider '${e}' for API key resolution.`);let i=r.getRequiredApiKeyName();if(i===null)return null;let a=c(i,t,n);if(!r.isRequiredApiKey())return a||null;if(!a)throw Error(`Required API key ${i} for provider '${e}' is not set in environment, session, or .env file.`);return a}async function le(e,t,n,r,i,a){let o=0,s=t;for(;o<=2;)try{d()&&u(`info`,`Attempt ${o+1}/3 calling ${s} (Provider: ${r}, Model: ${i}, Role: ${a})`);let c=await e[t](n);return d()&&u(`info`,`${s} succeeded for role ${a} (Provider: ${r}) on attempt ${o+1}`),c}catch(e){if(u(`warn`,`Attempt ${o+1} failed for role ${a} (${s} / ${r}): ${e.message}`),oe(e)&&o<2){o++;let e=1e3*2**(o-1);u(`info`,`Something went wrong on the provider side. Retrying in ${e/1e3}s...`),await new Promise(t=>setTimeout(t,e))}else throw u(`error`,`Something went wrong on the provider side. Max retries reached for role ${a} (${s} / ${r}).`),e}throw Error(`Exhausted all retries for role ${a} (${s} / ${r})`)}async function Q(e,t){let{role:i,session:o,projectRoot:s,systemPrompt:c,prompt:l,schema:f,objectName:m,commandName:h,outputType:g,experimental_transform:_,...v}=t;d()&&u(`info`,`${e}Service called`,{role:i,commandName:h,outputType:g,projectRoot:s});let y=s||p(),b=n(y),x;i===`main`?x=[`main`,`fallback`,`research`]:i===`research`?x=[`research`,`fallback`,`main`]:i===`fallback`?x=[`fallback`,`main`,`research`]:(u(`warn`,`Unknown initial role: ${i}. Defaulting to main -> fallback -> research sequence.`),x=[`main`,`fallback`,`research`]);let S=/* @__PURE__ */ new Set,C=null,w=`AI service call failed for all configured roles.`;for(let t of x){let n,i,s,d,p,x,T=null;try{u(`debug`,`New AI service call with role: ${t}`);let w=ce(t,y);if(!w){u(`error`,`Unknown role encountered in _unifiedServiceRunner: ${t}`),C||=/* @__PURE__ */ Error(`Unknown AI role specified: ${t}`);continue}if(n=w.provider,i=w.modelId,!n||!i){u(`warn`,`Skipping role '${t}': Provider or Model ID not configured.`),C||=/* @__PURE__ */ Error(`Configuration missing for role '${t}'. Provider: ${n}, Model: ${i}`);continue}if(S.has(`${n}/${i}`)){u(`debug`,`Skipping role '${t}': ${n}/${i} already failed for this request.`);continue}if(p=J(n?.toLowerCase()),!p){u(`warn`,`Skipping role '${t}': Provider '${n}' not supported.`),C||=/* @__PURE__ */ Error(`Unsupported provider configured: ${n}`);continue}d=a(t,y),s=Z(n?.toLowerCase(),o,y);let E=[],D=`${c} \n\n Always respond in ${r(y)}.`;if(E.push({role:`system`,content:D.trim()}),l)E.push({role:`user`,content:l});else throw Error(`User prompt content is missing.`);let O={apiKey:s,modelId:i,maxTokens:d.maxTokens,temperature:d.temperature,messages:E,...(e===`generateObject`||e===`streamObject`)&&{schema:f,objectName:m},role:t,...h&&{commandName:h},..._&&{experimental_transform:_},...v};if(x=await le(p,e,O,n,i,t),b&&x&&x.usage)try{T=await $({userId:b,commandName:h,providerName:n,modelId:i,inputTokens:x.usage.inputTokens,outputTokens:x.usage.outputTokens,cachedInputTokens:x.usage.cachedInputTokens,outputType:g})}catch{}else b&&x&&!x.usage&&u(`warn`,`Cannot log telemetry for ${h} (${n}/${i}): AI result missing 'usage' data. (May be expected for streams)`);let k;e===`generateText`?k=x.text:e===`generateObject`?k=x.object:(e===`streamText`||e===`streamObject`||u(`error`,`Unknown serviceType in _unifiedServiceRunner: ${e}`),k=x);let A=re(y);return{mainResult:k,telemetryData:T,tagInfo:A,providerName:n,modelId:i}}catch(r){let a=se(r);if(u(`error`,`Service call failed for role ${t} (Provider: ${n||`unknown`}, Model: ${i||`unknown`}): ${a}`),C=r,w=a,n&&i&&S.add(`${n}/${i}`),e===`generateObject`){let e=a.toLowerCase();if(e.includes(`no endpoints found that support tool use`)||e.includes(`does not support tool_use`)||e.includes(`tool use is not supported`)||e.includes(`tools are not supported`)||e.includes(`function calling is not supported`)||e.includes(`tool use is not supported`)){let e=`Model '${i||`unknown`}' via provider '${n||`unknown`}' does not support the 'tool use' required by generateObjectService. Please configure a model that supports tool/function calling for the '${t}' role, or use generateTextService if structured output is not strictly required.`;throw u(`error`,`[Tool Support Error] ${e}`),Error(e)}}}}throw u(`error`,`All roles in the sequence [${x.join(`, `)}] failed.`),Error(w)}async function ue(e){return Q(`generateText`,{outputType:`cli`,...e})}async function de(e){return Q(`streamText`,{outputType:`cli`,...e})}async function fe(e){let t={outputType:`cli`,...e};if(!t.schema)throw Error(`streamObjectService requires a schema parameter`);return Q(`streamObject`,t)}async function pe(e){return Q(`generateObject`,{objectName:`generated_object`,maxRetries:3,outputType:`cli`,...e})}async function $({userId:e,commandName:t,providerName:n,modelId:r,inputTokens:i,outputTokens:a,cachedInputTokens:o,outputType:s}){try{let s=(/* @__PURE__ */ new Date()).toISOString(),c=(i||0)+(a||0),{inputCost:l,outputCost:f,currency:p,isUnknown:m}=Y(n,r),h=X(i,a,l,f),g={timestamp:s,userId:e,commandName:t,modelUsed:r,providerName:n,inputTokens:i||0,outputTokens:a||0,totalTokens:c,...o>0?{cachedInputTokens:o}:{},totalCost:h,currency:p,isUnknownCost:m};return d()&&u(`info`,`AI Usage Telemetry:`,g),g}catch(e){return u(`error`,`Failed to log AI usage telemetry: ${e.message}`,{error:e}),null}}export{de as a,fe as i,ue as n,T as o,$ as r,pe as t};
@@ -0,0 +1,210 @@
1
+ import"./src-BaM893RS.js";import{At as e,Dt as t,F as n,J as r,Nt as i,Ot as a,St as o,T as s,_t as c,ct as l,kt as u,nt as d,s as f,t as p,xt as m}from"./config-manager-BxNrtquR.js";import{$ as h,A as ee,B as g,C as _,D as v,E as te,F as ne,G as re,H as ie,J as ae,K as oe,M as y,N as se,O as b,P as x,R as S,S as ce,U as C,V as le,W as w,X as ue,Y as de,Z as fe,_ as pe,b as me,c as he,ct as ge,d as T,et as _e,f as E,ft as D,g as O,h as k,i as A,it as j,j as M,l as N,lt as P,m as F,mt as I,n as ve,o as ye,ot as be,p as L,pt as xe,q as Se,r as Ce,s as we,st as Te,t as Ee,u as De,ut as Oe,v as R,x as ke,y as Ae,z as je}from"./dependency-manager-DRkIU6DR.js";import{t as Me}from"./response-language-BhegpO-l.js";import{n as z,r as Ne,t as Pe}from"./init-Cp1ZIvlh.js";import B from"chalk";import Fe from"node:path";import V from"path";import H from"node:fs";import Ie from"node:os";import U from"fs";import W from"boxen";import{Command as Le,Option as G}from"commander";import Re from"process";import K from"https";import q from"inquirer";function ze(){let e=Re.env.TM_PUBLIC_VERSION;return e&&e!==`unknown`?e:(console.warn(`Could not read version from TM_PUBLIC_VERSION, using fallback`),`0.0.0`)}function J(e,t){let n=e=>{let[t,n=``]=e.split(`-`,2);return{nums:t.split(`.`).map(e=>Number.parseInt(e,10)||0),pre:n}},r=n(e),i=n(t),a=Math.max(r.nums.length,i.nums.length);for(let e=0;e<a;e++){let t=(r.nums[e]||0)-(i.nums[e]||0);if(t!==0)return t<0?-1:1}return r.pre&&!i.pre?-1:!r.pre&&i.pre?1:r.pre===i.pre?0:r.pre<i.pre?-1:1}async function Be(e){return new Promise(t=>{let n={hostname:`raw.githubusercontent.com`,path:`/${Oe}/main/CHANGELOG.md`,method:`GET`,headers:{"User-Agent":`${P}/${e}`}},r=K.request(n,n=>{let r=``;n.on(`data`,e=>{r+=e}),n.on(`end`,()=>{try{if(n.statusCode!==200){t([]);return}t(Ve(r,e))}catch{t([])}})});r.on(`error`,()=>{t([])}),r.setTimeout(3e3,()=>{r.destroy(),t([])}),r.end()})}function Ve(e,t){try{if(!/^\d+\.\d+\.\d+(-[a-zA-Z0-9.-]+)?$/.test(t))return[];let n=RegExp(`## ${t.replace(/\./g,`\\.`)}\\s*\\n`,`i`),r=e.match(n);if(!r)return[];let i=r.index+r[0].length,a=e.indexOf(`
2
+ ## `,i),o=(a>0?e.slice(i,a):e.slice(i)).match(/### Minor Changes\s*\n([\s\S]*?)(?=\n###|\n##|$)/i);if(!o)return[];let s=o[1],c=[],l=/^-\s+\[#\d+\][^\n]*?!\s+-\s+(.+?)$/gm,u;for(;(u=l.exec(s))!==null;){let e=u[1].trim();c.push(e)}return c}catch{return[]}}const Y=()=>Fe.join(Ie.tmpdir(),`taskgraph-update-cache.json`);function He(){try{let e=Y();if(!H.existsSync(e))return null;let t=JSON.parse(H.readFileSync(e,`utf-8`));return Date.now()-t.timestamp>36e5?null:t}catch{return null}}function Ue(e,t){try{H.writeFileSync(Y(),JSON.stringify({timestamp:Date.now(),latestVersion:e,highlights:t},null,2))}catch{}}function We(e){return new Promise(t=>{let n=K.request({hostname:`registry.npmjs.org`,path:`/${P}`,method:`GET`,headers:{Accept:`application/vnd.npm.install-v1+json`,"User-Agent":`${P}/${e}`}},e=>{let n=``;e.on(`data`,e=>n+=e),e.on(`end`,()=>{try{if(e.statusCode!==200){t(null);return}t(JSON.parse(n)[`dist-tags`]?.latest||null)}catch{t(null)}})});n.on(`error`,()=>t(null)),n.setTimeout(3e3,()=>{n.destroy(),t(null)}),n.end()})}function X(e,t,n){return{currentVersion:e,latestVersion:t,needsUpdate:J(e,t)<0,highlights:n}}async function Ge(e){let t=e||ze(),n=He();if(n)return X(t,n.latestVersion,n.highlights);let r=await We(t);if(!r)return X(t,t);let i=J(t,r)<0?await Be(r):void 0;return Ue(r,i),X(t,r,i)}var Ke=class{#e;#t;constructor(e,t){this.#e=Object.freeze({...e}),this.#t=t}getProjectRoot(){return this.#e.projectRoot}getTaskGraphDir(){return this.#e.taskGraphDir}getTasksPath(){return this.#e.tasksPath}getPrdPath(){return this.#e.prdPath}getComplexityReportPath(){if(this.#e.complexityReportPath)return this.#e.complexityReportPath;let e=this.getCurrentTag()===`master`?o:o.replace(`.json`,`_${this.getCurrentTag()}.json`);return V.join(this.#e.projectRoot,e)}getConfigPath(){return this.#e.configPath}getStatePath(){return this.#e.statePath}getAllPaths(){return this.#e}getCurrentTag(){if(this.#t)return this.#t;try{if(U.existsSync(this.#e.statePath)){let e=U.readFileSync(this.#e.statePath,`utf8`),t=JSON.parse(e);if(t&&t.currentTag)return t.currentTag}}catch{}try{if(U.existsSync(this.#e.configPath)){let e=U.readFileSync(this.#e.configPath,`utf8`),t=JSON.parse(e);if(t&&t.global&&t.global.defaultTag)return t.global.defaultTag}}catch{}return`master`}};function Z(r={}){let o=(e,t,n=[],r=null,i=!1)=>{if(typeof t==`string`){let n=V.isAbsolute(t)?t:V.resolve(r||process.cwd(),t);if(i){let t=V.dirname(n);if(!U.existsSync(t))try{U.mkdirSync(t,{recursive:!0})}catch(n){throw Error(`Could not create directory for ${e}: ${t}. Error: ${n.message}`)}}else if(!U.existsSync(n))throw Error(`${e} override path does not exist: ${n}`);return n}if(t===!0){for(let e of n){let t=V.isAbsolute(e)?e:V.join(r||process.cwd(),e);if(U.existsSync(t))return t}throw Error(`Required ${e} not found. Searched: ${n.join(`, `)}`)}for(let e of n){let t=V.isAbsolute(e)?e:V.join(r||process.cwd(),e);if(U.existsSync(t))return t}return null},s={};if(r.projectRoot){let e=V.resolve(r.projectRoot);if(!U.existsSync(e))throw Error(`Project root override path does not exist: ${e}`);if(!U.existsSync(V.join(e,`.taskgraph`)))throw Error(`Project root override is not a valid taskgraph project: ${e}`);s.projectRoot=e}else s.projectRoot=n();return s.taskGraphDir=`taskGraphDir`in r?o(`taskgraph directory`,r.taskGraphDir,[a],s.projectRoot):o(`taskgraph directory`,!1,[a],s.projectRoot),s.configPath=V.join(s.projectRoot,t),s.statePath=V.join(s.taskGraphDir||V.join(s.projectRoot,`.taskgraph`),`state.json`),s.tasksPath=V.join(s.projectRoot,i),`configPath`in r&&(s.configPath=o(`config file`,r.configPath,[t],s.projectRoot)),`statePath`in r&&(s.statePath=o(`state file`,r.statePath,[`state.json`],s.taskGraphDir)),`tasksPath`in r&&(s.tasksPath=o(`tasks file`,r.tasksPath,[i],s.projectRoot)),`prdPath`in r&&(s.prdPath=o(`PRD file`,r.prdPath,[V.join(u,`PRD.md`),V.join(u,`prd.md`),V.join(u,`PRD.txt`),V.join(u,`prd.txt`)],s.projectRoot)),`complexityReportPath`in r&&(s.complexityReportPath=o(`complexity report`,r.complexityReportPath,[V.join(e,`task-complexity-report.json`),V.join(e,`complexity-report.json`)],s.projectRoot,!0)),new Ke(s,r.tag)}function Q(e){let t=e?.message??``;if(/overloaded|rate limit|\b(429|529)\b/i.test(t))return`Claude is busy. Wait a minute and try again`;if(/empty stream response|did not return a valid/i.test(t))return`Try again, or reword the prompt`}function qe(e){e.on(`option:unknown`,function(e){let t=this._name||`unknown`;I(`Unknown option '${e}'`,`Run \`taskgraph ${t} --help\` to see its options`),process.exit(1)}),e.command(`help`).description(`Show help information`).action(()=>{e.help()}),e.configureHelp({helpWidth:120,sortSubcommands:!1}),e.command(`parse-prd`).description(`Parse a PRD file and generate tasks`).argument(`[file]`,`Path to the PRD file`).option(`-i, --input <file>`,`Path to the PRD file (alternative to positional argument)`).option(`-o, --output <file>`,`Output file path`).option(`-n, --num-tasks <number>`,`Number of tasks to generate`,f()).option(`-f, --force`,`Skip confirmation when overwriting existing tasks`).option(`--append`,`Append new tasks to existing tasks.json instead of overwriting`).option(`-r, --research`,`Use Claude Code web research for research-backed task generation, providing more comprehensive and accurate task breakdown`).option(`--tag <tag>`,`Specify tag context for task operations`).action(async(e,t)=>{let n=t.input||e;n&&!U.existsSync(V.resolve(n))&&(I(`${n} not found`,`Check the spelling; paths are relative to this folder`),process.exit(1));let r;try{let e={prdPath:n||!0,tag:t.tag};t.output&&(e.tasksPath=t.output),r=Z(e)}catch(e){D(e,{hint:n?void 0:"Try `taskgraph parse-prd prd.md`"}),process.exit(1)}let i=parseInt(t.numTasks,10),a=t.force||!1,o=t.append||!1,s=t.research||!1,c=a,l=o,u=r.getCurrentTag();await T(u);async function f(){let e=!1,t=r.getTasksPath();if(U.existsSync(t))try{let n=U.readFileSync(t,`utf8`),r=JSON.parse(n);r[u]&&Array.isArray(r[u].tasks)&&r[u].tasks.length>0&&(e=!0)}catch{e=!1}if(e&&!c&&!l){if(!await ye(t))return d(`info`,`Operation cancelled.`),!1;c=!0}return!0}try{if(!await f())return;o&&console.log(m.brand(`Appending to existing tasks...`)),s&&console.log(m.brand(`Using Claude Code web research for research-backed task generation`));let e=r.getTasksPath()||V.join(r.getProjectRoot(),`.taskgraph/tasks/tasks.json`);await se(r.getPrdPath(),e,i,{append:l,force:c,research:s,projectRoot:r.getProjectRoot(),tag:u})}catch(e){console.error(B.red(`Error parsing PRD: ${e.message}`)),process.exit(1)}}),e.command(`update`).description(`Update multiple tasks with ID >= "from" based on new information or implementation changes`).option(`-f, --file <file>`,`Path to the tasks file`,i).option(`--from <id>`,`Task ID to start updating from (tasks with ID >= this value will be updated)`,`1`).option(`-p, --prompt <text>`,`Prompt explaining the changes or new context (required)`).option(`-r, --research`,`Use Claude Code web research for research-backed task updates`).option(`--tag <tag>`,`Specify tag context for task operations`).action(async e=>{let t=Z({tasksPath:e.file||!0,tag:e.tag}),n=parseInt(e.from,10),r=e.prompt,i=e.research||!1,a=t.getTasksPath(),o=t.getCurrentTag();await T(o),(process.argv.includes(`--id`)||process.argv.some(e=>e.startsWith(`--id=`)))&&(console.error(B.red(`Error: The update command uses --from=<id>, not --id=<id>`)),console.log(B.yellow(`
3
+ To update multiple tasks:`)),console.log(` taskgraph update --from=${n} --prompt="Your prompt here"`),console.log(B.yellow(`
4
+ To update a single specific task, use the update-task command instead:`)),console.log(` taskgraph update-task --id=<id> --prompt="Your prompt here"`),process.exit(1)),r||(console.error(B.red(`Error: --prompt parameter is required. Please provide information about the changes.`)),process.exit(1)),console.log(m.brand(`Updating tasks from ID >= ${n} with prompt: "${r}"`)),console.log(m.brand(`Tasks file: ${a}`)),i&&console.log(m.brand(`Using Claude Code web research for research-backed task updates`)),await ke(t.getTasksPath(),n,r,i,{projectRoot:t.getProjectRoot(),tag:o})}),e.command(`update-task`).description(`Update a single specific task by ID with new information`).argument(`[id]`,`Task ID to update (e.g., 1, 1.1, TAS-123)`).argument(`[prompt...]`,`Update prompt - multiple words, no quotes needed`).option(`-f, --file <file>`,`Path to the tasks file`,i).option(`-i, --id <id>`,`Task ID to update (fallback if not using positional)`).option(`-p, --prompt <text>`,`Prompt (fallback if not using positional)`).option(`-r, --research`,`Use Claude Code web research for research-backed task updates`).option(`--append`,`Append timestamped information to task details instead of full update`).option(`--tag <tag>`,`Specify tag context for task operations`).action(async(e,t,n)=>{try{let r=Z({tasksPath:n.file||!0,tag:n.tag}),i=r.getTasksPath(),a=r.getCurrentTag();await T(a);let o=e||n.id,s=t.length>0?t.join(` `):n.prompt;o||(console.error(B.red(`Error: Task ID is required`)),console.log(B.yellow(`Usage examples:
5
+ tm update-task 1 Added implementation details
6
+ tm update-task TAS-123 Fixed the auth bug
7
+ tm update-task --id=23 --prompt="Update with new information"`)),process.exit(1)),/^\d+$/.test(o)||(console.error(B.red(`Error: Invalid task ID: ${o}. Task ID must be a positive integer.`)),console.log(B.yellow(`Usage examples:
8
+ tm update-task 1 Added implementation details
9
+ tm update-task 7 Fixed the auth bug`)),process.exit(1)),s||(console.error(B.red(`Error: Prompt is required. Please provide information about the changes.`)),console.log(B.yellow(`Usage examples:
10
+ tm update-task 1 Added implementation details
11
+ tm update-task 23 "Update with new information"`)),process.exit(1));let c=n.research||!1;U.existsSync(i)||(console.error(B.red(`Error: Tasks file not found at path: ${i}`)),console.log(i===`.taskgraph/tasks/tasks.json`?B.yellow(`Hint: Run taskgraph init or taskgraph parse-prd to create tasks.json first`):B.yellow(`Hint: Check if the file path is correct: ${i}`)),process.exit(1)),console.log(m.brand(`Updating task ${o} with prompt: "${s}"`)),console.log(m.brand(`Tasks file: ${i}`)),c&&console.log(m.brand(`Using Claude Code web research for this update`));let l=n.append||!1;await ce(r.getTasksPath(),o,s,c,{projectRoot:r.getProjectRoot(),tag:a},`text`,l)||console.log(B.yellow(`
12
+ Task update was not completed. Review the messages above for details.`))}catch(e){D(e,{hint:Q(e)})}}),e.command(`update-subtask`).description(`Update a subtask by appending additional timestamped information`).option(`-f, --file <file>`,`Path to the tasks file`,i).option(`-i, --id <id>`,`Subtask ID to update (required)`).option(`-p, --prompt <text>`,`Prompt explaining what information to add (required)`).option(`-r, --research`,`Use Claude Code web research for research-backed updates`).option(`--tag <tag>`,`Specify tag context for task operations`).action(async e=>{try{let t=Z({tasksPath:e.file||!0,tag:e.tag}),n=t.getTasksPath(),r=t.getCurrentTag();await T(r),e.id||(console.error(B.red(`Error: --id parameter is required`)),console.log(B.yellow(`Usage example: taskgraph update-subtask --id=5.2 --prompt="Add more details about the API endpoint"`)),process.exit(1));let i=e.id;e.prompt||(console.error(B.red(`Error: --prompt parameter is required. Please provide information to add to the subtask.`)),console.log(B.yellow(`Usage example: taskgraph update-subtask --id=5.2 --prompt="Add more details about the API endpoint"`)),process.exit(1));let a=e.prompt,o=e.research||!1;U.existsSync(n)||(console.error(B.red(`Error: Tasks file not found at path: ${n}`)),console.log(n===`.taskgraph/tasks/tasks.json`?B.yellow(`Hint: Run taskgraph init or taskgraph parse-prd to create tasks.json first`):B.yellow(`Hint: Check if the file path is correct: ${n}`)),process.exit(1)),console.log(m.brand(`Updating subtask ${i} with prompt: "${a}"`)),console.log(m.brand(`Tasks file: ${n}`)),o&&console.log(m.brand(`Using Claude Code web research for this update`)),await _(t.getTasksPath(),i,a,o,{projectRoot:t.getProjectRoot(),tag:r})}catch(e){D(e,{hint:Q(e)})}}),e.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=Z({tasksPath:e.file||!0,tag:e.tag}),n=t.getTasksPath(),r=t.getCurrentTag();await T(r),e.id||(console.error(B.red(`Error: --id parameter is required`)),console.log(B.yellow(`Usage example: taskgraph 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});b(e.strength)||(console.error(B.red(`Error: Invalid strength level: ${e.strength}. Must be one of: light, regular, heavy`)),process.exit(1)),U.existsSync(n)||(console.error(B.red(`Error: Tasks file not found at path: ${n}`)),process.exit(1)),console.log(m.brand(`Scoping up ${i.length} task(s): ${i.join(`, `)}`)),console.log(m.brand(`Strength level: ${e.strength}`)),e.prompt&&console.log(m.brand(`Custom instructions: ${e.prompt}`));let a={projectRoot:t.getProjectRoot(),tag:r,commandName:`scope-up`,outputType:`cli`,research:e.research||!1},o=await v(n,i,e.strength,e.prompt||null,a,`text`);console.log(B.green(`✅ Successfully scoped up ${o.updatedTasks.length} task(s)`))}catch(e){D(e,{hint:Q(e)})}}),e.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=Z({tasksPath:e.file||!0,tag:e.tag}),n=t.getTasksPath(),r=t.getCurrentTag();await T(r),e.id||(console.error(B.red(`Error: --id parameter is required`)),console.log(B.yellow(`Usage example: taskgraph 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});b(e.strength)||(console.error(B.red(`Error: Invalid strength level: ${e.strength}. Must be one of: light, regular, heavy`)),process.exit(1)),U.existsSync(n)||(console.error(B.red(`Error: Tasks file not found at path: ${n}`)),process.exit(1)),console.log(m.brand(`Scoping down ${i.length} task(s): ${i.join(`, `)}`)),console.log(m.brand(`Strength level: ${e.strength}`)),e.prompt&&console.log(m.brand(`Custom instructions: ${e.prompt}`));let a={projectRoot:t.getProjectRoot(),tag:r,commandName:`scope-down`,outputType:`cli`,research:e.research||!1},o=await te(n,i,e.strength,e.prompt||null,a,`text`);console.log(B.green(`✅ Successfully scoped down ${o.updatedTasks.length} task(s)`))}catch(e){D(e,{hint:Q(e)})}}),de(e),e.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 (web research via Claude Code)`,!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(`--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 t={tasksPath:e.file||!0,tag:e.tag};e.complexityReport&&(t.complexityReportPath=e.complexityReport);let n=Z(t),r=n.getCurrentTag();if(await T(r),e.all){console.log(m.brand(`Expanding all pending tasks...`));try{await S(n.getTasksPath(),e.num,e.research,e.prompt,e.force,{projectRoot:n.getProjectRoot(),tag:r,complexityReportPath:n.getComplexityReportPath()})}catch(e){D(e,{hint:Q(e)})}}else if(e.id){e.id||(console.error(B.red(`Error: Task ID is required unless using --all.`)),process.exit(1)),console.log(m.brand(`Expanding task ${e.id}...`));try{await je(n.getTasksPath(),e.id,e.num,e.research,e.prompt,{projectRoot:n.getProjectRoot(),tag:r,complexityReportPath:n.getComplexityReportPath()},e.force)}catch(e){D(e,{hint:Q(e)})}}else I(`Missing task ID`,"Try `taskgraph expand --id=3`, or `--all` for every pending task"),process.exit(1)}),e.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=Z(t);e.model,parseFloat(e.threshold);let r=e.research||!1,i=n.getCurrentTag();await T(i);let a=n.getComplexityReportPath();if(console.log(m.brand(`Analyzing task complexity from: ${n.getTasksPath()}`)),console.log(m.brand(`Output report will be saved to: ${a}`)),e.id)console.log(m.brand(`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(m.brand(`Analyzing tasks in range: ${t} to ${n}`))}r&&console.log(m.brand(`Using Claude Code web research for research-backed complexity analysis`));let o={...e,output:a,tag:i,projectRoot:n.getProjectRoot(),file:n.getTasksPath()};await le(o)}),e.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 .taskgraph/docs/research/ directory`).option(`--tag <tag>`,`Specify tag context for task operations`).action(async(e,t)=>{let n=Z({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`)),w(),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 T(o),i.length>0)try{let e=l(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=V.isAbsolute(e)?e:V.join(n.getProjectRoot(),e);U.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(m.brand(`Researching: "${s.prompt}"`)),s.taskIds.length>0&&console.log(m.muted(`Task context: ${s.taskIds.join(`, `)}`)),s.filePaths.length>0&&console.log(m.muted(`File context: ${s.filePaths.join(`, `)}`)),s.customContext&&console.log(m.muted(`Custom context: ${s.customContext.substring(0,50)}${s.customContext.length>50?`...`:``}`)),s.includeProjectTree&&console.log(m.muted(`Including project file tree`)),console.log(m.muted(`Detail level: ${s.detailLevel}`));try{let{performResearch:e}=await import(`./research-Cf8YeyqJ.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}
13
+
14
+ **Detail Level:** ${r.detailLevel}
15
+ **Context Size:** ${r.contextSize} characters
16
+ **Timestamp:** ${(/* @__PURE__ */ new Date()).toLocaleDateString()} ${(/* @__PURE__ */ new Date()).toLocaleTimeString()}
17
+
18
+ ### Results
19
+
20
+ ${r.result}`;if(e){let{updateSubtaskById:e}=await import(`./update-subtask-by-id-Dlk8IQru.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-C1xnfWPp.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}
21
+
22
+ **Detail Level:** ${r.detailLevel}
23
+ **Context Size:** ${r.contextSize} characters
24
+ **Timestamp:** ${(/* @__PURE__ */ new Date()).toISOString()}
25
+
26
+ ## Results
27
+
28
+ ${r.result}
29
+ `;U.writeFileSync(s.saveTarget,e,`utf-8`),console.log(B.green(`\n💾 Results saved to: ${s.saveTarget}`))}}catch(e){console.error(B.red(`\n❌ Research failed: ${e.message}`)),process.exit(1)}}),e.command(`clear-subtasks`).description(`Clear subtasks from specified tasks`).option(`-f, --file <file>`,`Path to the tasks file`,i).option(`-i, --id <ids>`,`Task IDs (comma-separated) to clear subtasks from`).option(`--all`,`Clear subtasks from all tasks`).option(`--tag <tag>`,`Specify tag context for task operations`).action(async e=>{let t=e.id,n=e.all,r=Z({tasksPath:e.file||!0,tag:e.tag}),i=r.getCurrentTag();if(await T(i),!t&&!n&&(console.error(B.red(`Error: Please specify task IDs with --id=<ids> or use --all to clear all tasks`)),process.exit(1)),n){let e=l(r.getTasksPath(),r.getProjectRoot(),i);(!e||!e.tasks)&&(console.error(B.red(`Error: No valid tasks found`)),process.exit(1));let t=e.tasks.map(e=>e.id).join(`,`);g(r.getTasksPath(),t,{projectRoot:r.getProjectRoot(),tag:i})}else g(r.getTasksPath(),t,{projectRoot:r.getProjectRoot(),tag:i})}),e.command(`add-task`).description(`Add a new task using AI, optionally providing manual details`).option(`-f, --file <file>`,`Path to the tasks file`,i).option(`-p, --prompt <prompt>`,`Description of the task to add (required if not using manual fields)`).option(`-t, --title <title>`,`Task title (for manual task creation)`).option(`-d, --description <description>`,`Task description (for manual task creation)`).option(`--details <details>`,`Implementation details (for manual task creation)`).option(`--dependencies <dependencies>`,`Comma-separated list of task IDs this task depends on`).option(`--priority <priority>`,`Task priority (high, medium, low)`,`medium`).option(`-r, --research`,`Whether to use research capabilities for task creation`).option(`--tag <tag>`,`Specify tag context for task operations`).action(async e=>{let t=e.title&&e.description;!e.prompt&&!t&&(console.error(B.red(`Error: Either --prompt or both --title and --description must be provided`)),process.exit(1));let n=e.file||`.taskgraph/tasks/tasks.json`;U.existsSync(n)||(console.error(`❌ No tasks.json file found. Please run "taskgraph init" or create a tasks.json file at ${i}`),process.exit(1));let r=Z({tasksPath:e.file||!0,tag:e.tag}),a=r.getProjectRoot(),o=r.getCurrentTag();await T(o);let s=null;t?(s={title:e.title,description:e.description,details:e.details||``,testStrategy:e.testStrategy||``},console.log(m.brand(`Creating task manually with title: "${e.title}"`))):console.log(m.brand(`Creating task with AI using prompt: "${e.prompt}"`));let c=e.dependencies?e.dependencies.split(`,`).map(e=>e.trim()):[];c.length>0&&console.log(m.brand(`Dependencies: [${c.join(`, `)}]`)),e.priority&&console.log(m.brand(`Priority: ${e.priority}`));let l={projectRoot:a,tag:o,commandName:`add-task`,outputType:`cli`};try{let{newTaskId:t,telemetryData:n}=await ie(r.getTasksPath(),e.prompt,c,e.priority,l,`text`,s,e.research)}catch(e){D(e,{hint:Q(e)})}}),e.command(`add-dependency`).description(`Add a dependency to a task`).option(`-i, --id <id>`,`Task ID to add dependency to`).option(`-d, --depends-on <id>`,`Task ID that will become a dependency`).option(`-f, --file <file>`,`Path to the tasks file`,i).option(`--tag <tag>`,`Specify tag context for task operations`).action(async e=>{let t=Z({tasksPath:e.file||!0,tag:e.tag}),n=e.id,r=e.dependsOn,i=t.getCurrentTag();await T(i),(!n||!r)&&(console.error(B.red(`Error: Both --id and --depends-on are required`)),process.exit(1));let a=n.includes(`.`)?n:parseInt(n,10),o=r.includes(`.`)?r:parseInt(r,10);await Ee(t.getTasksPath(),a,o,{projectRoot:t.getProjectRoot(),tag:i})}),e.command(`remove-dependency`).description(`Remove a dependency from a task`).option(`-i, --id <id>`,`Task ID to remove dependency from`).option(`-d, --depends-on <id>`,`Task ID to remove as a dependency`).option(`-f, --file <file>`,`Path to the tasks file`,i).option(`--tag <tag>`,`Specify tag context for task operations`).action(async e=>{let t=Z({tasksPath:e.file||!0,tag:e.tag}),n=e.id,r=e.dependsOn,i=t.getCurrentTag();await T(i),(!n||!r)&&(console.error(B.red(`Error: Both --id and --depends-on are required`)),process.exit(1));let a=n.includes(`.`)?n:parseInt(n,10),o=r.includes(`.`)?r:parseInt(r,10);await Ce(t.getTasksPath(),a,o,{projectRoot:t.getProjectRoot(),tag:i})}),e.command(`validate-dependencies`).description(`Identify invalid dependencies without fixing them${B.reset(``)}`).option(`-f, --file <file>`,`Path to the tasks file`,i).option(`--tag <tag>`,`Specify tag context for task operations`).action(async e=>{let t=Z({tasksPath:e.file||!0,tag:e.tag}),n=t.getCurrentTag();await T(n),await A(t.getTasksPath(),{context:{projectRoot:t.getProjectRoot(),tag:n}})}),e.command(`fix-dependencies`).description(`Fix invalid dependencies automatically${B.reset(``)}`).option(`-f, --file <file>`,`Path to the tasks file`,i).option(`--tag <tag>`,`Specify tag context for task operations`).action(async e=>{let t=Z({tasksPath:e.file||!0,tag:e.tag}),n=t.getCurrentTag();await T(n),await ve(t.getTasksPath(),{context:{projectRoot:t.getProjectRoot(),tag:n}})}),e.command(`complexity-report`).description(`Display the complexity analysis report${B.reset(``)}`).option(`-f, --file <file>`,`Path to the report file`,o).option(`--tag <tag>`,`Specify tag context for task operations`).action(async e=>{let t={tag:e.tag};e.file&&e.file!==`.taskgraph/reports/task-complexity-report.json`&&(t.complexityReportPath=e.file);let n=Z(t);await T(n.getCurrentTag()),await N(n.getComplexityReportPath())}),e.command(`add-subtask`).description(`Add a subtask to an existing task`).option(`-f, --file <file>`,`Path to the tasks file`,i).option(`-p, --parent <id>`,`Parent task ID (required)`).option(`-i, --task-id <id>`,`Existing task ID to convert to subtask`).option(`-t, --title <title>`,`Title for the new subtask (when creating a new subtask)`).option(`-d, --description <text>`,`Description for the new subtask`).option(`--details <text>`,`Implementation details for the new subtask`).option(`--dependencies <ids>`,`Comma-separated list of dependency IDs for the new subtask`).option(`-s, --status <status>`,`Status for the new subtask`,`pending`).option(`--generate`,`Regenerate task files after adding subtask`).option(`--tag <tag>`,`Specify tag context for task operations`).action(async e=>{let n=Z({tasksPath:e.file||!0,tag:e.tag}),r=e.parent,i=e.taskId,a=e.generate||!1,o=n.getCurrentTag();await T(o),r||(console.error(B.red(`Error: --parent parameter is required. Please provide a parent task ID.`)),t(),process.exit(1));let s=[];e.dependencies&&(s=e.dependencies.split(`,`).map(e=>e.includes(`.`)?e.trim():parseInt(e.trim(),10)));try{if(i)console.log(m.brand(`Converting task ${i} to a subtask of ${r}...`)),await C(n.getTasksPath(),r,i,null,a,{projectRoot:n.getProjectRoot(),tag:o}),console.log(B.green(`✓ Task ${i} successfully converted to a subtask of task ${r}`));else if(e.title){console.log(m.brand(`Creating new subtask for parent task ${r}...`));let t={title:e.title,description:e.description||``,details:e.details||``,status:e.status||`pending`,dependencies:s},i=await C(n.getTasksPath(),r,null,t,a,{projectRoot:n.getProjectRoot(),tag:o});console.log(B.green(`✓ New subtask ${r}.${i.id} successfully created`)),console.log(W(m.text.bold(`Subtask ${r}.${i.id} Added Successfully`)+`
30
+
31
+ `+m.text(`Title: ${i.title}`)+`
32
+ `+m.text(`Status: ${R(i.status)}`)+`
33
+ `+(s.length>0?m.text(`Dependencies: ${s.join(`, `)}`)+`
34
+ `:``)+`
35
+ `+m.text.bold(`Next Steps:`)+`
36
+ `+B.cyan(`1. Run ${B.yellow(`taskgraph show ${r}`)} to see the parent task with all subtasks`)+`
37
+ `+B.cyan(`2. Run ${B.yellow(`tm set-status ${r}.${i.id} in-progress`)} to start working on it`),{padding:1,borderColor:`green`,borderStyle:`round`,margin:{top:1}}))}else console.error(B.red(`Error: Either --task-id or --title must be provided.`)),console.log(W(m.text.bold(`Usage Examples:`)+`
38
+
39
+ `+m.text(`Convert existing task to subtask:`)+`
40
+ `+B.yellow(` taskgraph add-subtask --parent=5 --task-id=8`)+`
41
+
42
+ `+m.text(`Create new subtask:`)+`
43
+ `+B.yellow(` taskgraph add-subtask --parent=5 --title="Implement login UI" --description="Create the login form"`)+`
44
+
45
+ `,{padding:1,borderColor:c,borderStyle:`round`})),process.exit(1)}catch(e){D(e)}}).on(`error`,function(e){console.error(B.red(`Error: ${e.message}`)),t(),process.exit(1)});function t(){console.log(W(`${m.text.bold(`Add Subtask Command Help`)}\n\n${B.cyan(`Usage:`)}\n taskgraph add-subtask --parent=<id> [options]\n\n${B.cyan(`Options:`)}\n -p, --parent <id> Parent task ID (required)\n -i, --task-id <id> Existing task ID to convert to subtask\n -t, --title <title> Title for the new subtask\n -d, --description <text> Description for the new subtask\n --details <text> Implementation details for the new subtask\n --dependencies <ids> Comma-separated list of dependency IDs\n -s, --status <status> Status for the new subtask (default: "pending")\n -f, --file <file> Path to the tasks file (default: "${i}")\n --generate Regenerate task files after adding subtask\n\n${B.cyan(`Examples:`)}\n taskgraph add-subtask --parent=5 --task-id=8\n taskgraph add-subtask -p 5 -t "Implement login UI" -d "Create the login form" --generate`,{padding:1,borderColor:c,borderStyle:`round`}))}e.command(`remove-subtask`).description(`Remove a subtask from its parent task`).option(`-f, --file <file>`,`Path to the tasks file`,i).option(`-i, --id <id>`,`Subtask ID(s) to remove in format "parentId.subtaskId" (can be comma-separated for multiple subtasks)`).option(`-c, --convert`,`Convert the subtask to a standalone task instead of deleting it`).option(`--generate`,`Regenerate task files after removing subtask`).option(`--tag <tag>`,`Specify tag context for task operations`).action(async e=>{let t=Z({tasksPath:e.file||!0,tag:e.tag}),r=e.id,i=e.convert||!1,a=e.generate||!1,o=t.getCurrentTag();r||(console.error(B.red(`Error: --id parameter is required. Please provide subtask ID(s) in format "parentId.subtaskId".`)),n(),process.exit(1));try{let e=r.split(`,`).map(e=>e.trim());for(let r of e){r.includes(`.`)||(console.error(B.red(`Error: Subtask ID "${r}" must be in format "parentId.subtaskId"`)),n(),process.exit(1)),console.log(m.brand(`Removing subtask ${r}...`)),i&&console.log(m.brand(`The subtask will be converted to a standalone task`));let e=await y(t.getTasksPath(),r,i,a,{projectRoot:t.getProjectRoot(),tag:o});console.log(W(i&&e?m.text.bold(`Subtask ${r} Converted to Task #${e.id}`)+`
46
+
47
+ `+m.text(`Title: ${e.title}`)+`
48
+ `+m.text(`Status: ${R(e.status)}`)+`
49
+ `+m.text(`Dependencies: ${e.dependencies.join(`, `)}`)+`
50
+
51
+ `+m.text.bold(`Next Steps:`)+`
52
+ `+B.cyan(`1. Run ${B.yellow(`taskgraph show ${e.id}`)} to see details of the new task`)+`
53
+ `+B.cyan(`2. Run ${B.yellow(`tm set-status ${e.id} in-progress`)} to start working on it`):m.text.bold(`Subtask ${r} Removed`)+`
54
+
55
+ `+m.text(`The subtask has been successfully deleted.`),{padding:1,borderColor:`green`,borderStyle:`round`,margin:{top:1}}))}}catch(e){D(e)}}).on(`error`,function(e){console.error(B.red(`Error: ${e.message}`)),n(),process.exit(1)});function n(){console.log(W(m.text.bold(`Remove Subtask Command Help`)+`
56
+
57
+ `+B.cyan(`Usage:`)+`
58
+ taskgraph remove-subtask --id=<parentId.subtaskId> [options]
59
+
60
+ `+B.cyan(`Options:`)+`
61
+ -i, --id <id> Subtask ID(s) to remove in format "parentId.subtaskId" (can be comma-separated, required)
62
+ -c, --convert Convert the subtask to a standalone task instead of deleting it
63
+ -f, --file <file> Path to the tasks file (default: "`+i+`")
64
+ --skip-generate Skip regenerating task files
65
+
66
+ `+B.cyan(`Examples:`)+`
67
+ taskgraph remove-subtask --id=5.2
68
+ taskgraph remove-subtask --id=5.2,6.3,7.1
69
+ taskgraph remove-subtask --id=5.2 --convert`,{padding:1,borderColor:c,borderStyle:`round`}))}function a(){console.log(W(m.text.bold(`Add Tag Command Help`)+`
70
+
71
+ `+B.cyan(`Usage:`)+`
72
+ taskgraph add-tag <tagName> [options]
73
+
74
+ `+B.cyan(`Options:`)+`
75
+ -f, --file <file> Path to the tasks file (default: "`+i+`")
76
+ --copy-from-current Copy tasks from the current tag to the new tag
77
+ --copy-from <tag> Copy tasks from the specified tag to the new tag
78
+ -d, --description <text> Optional description for the tag
79
+
80
+ `+B.cyan(`Examples:`)+`
81
+ taskgraph add-tag feature-xyz
82
+ taskgraph add-tag feature-xyz --copy-from-current
83
+ taskgraph add-tag feature-xyz --copy-from master
84
+ taskgraph add-tag feature-xyz -d "Feature XYZ development"`,{padding:1,borderColor:c,borderStyle:`round`}))}function u(){console.log(W(m.text.bold(`Delete Tag Command Help`)+`
85
+
86
+ `+B.cyan(`Usage:`)+`
87
+ taskgraph delete-tag <tagName> [options]
88
+
89
+ `+B.cyan(`Options:`)+`
90
+ -f, --file <file> Path to the tasks file (default: "`+i+`")
91
+ -y, --yes Skip confirmation prompts
92
+
93
+ `+B.cyan(`Examples:`)+`
94
+ taskgraph delete-tag feature-xyz
95
+ taskgraph delete-tag feature-xyz --yes
96
+
97
+ `+B.yellow(`Warning:`)+`
98
+ This will permanently delete the tag and all its tasks!`,{padding:1,borderColor:c,borderStyle:`round`}))}function p(){console.log(W(m.text.bold(`Use Tag Command Help`)+`
99
+
100
+ `+B.cyan(`Usage:`)+`
101
+ taskgraph use-tag <tagName> [options]
102
+
103
+ `+B.cyan(`Options:`)+`
104
+ -f, --file <file> Path to the tasks file (default: "`+i+`")
105
+
106
+ `+B.cyan(`Examples:`)+`
107
+ taskgraph use-tag feature-xyz
108
+ taskgraph use-tag master
109
+
110
+ `+B.cyan(`Related Commands:`)+`
111
+ taskgraph tags List all available tags
112
+ taskgraph add-tag <name> Create a new tag`,{padding:1,borderColor:c,borderStyle:`round`}))}function w(){console.log(W(m.text.bold(`Research Command Help`)+`
113
+
114
+ `+B.cyan(`Usage:`)+`
115
+ taskgraph research "<query>" [options]
116
+
117
+ `+B.cyan(`Required:`)+`
118
+ <query> Research question or prompt (required)
119
+
120
+ `+B.cyan(`Context Options:`)+`
121
+ -i, --id <ids> Comma-separated task/subtask IDs for context (e.g., "15,23.2")
122
+ -f, --files <paths> Comma-separated file paths for context
123
+ -c, --context <text> Additional custom context text
124
+ --tree Include project file tree structure
125
+
126
+ `+B.cyan(`Output Options:`)+`
127
+ -d, --detail <level> Detail level: low, medium, high (default: medium)
128
+ --save-to <id> Auto-save results to task/subtask ID (e.g., "15" or "15.2")
129
+ --tag <tag> Specify tag context for task operations
130
+
131
+ `+B.cyan(`Examples:`)+`
132
+ taskgraph research "How should I implement user authentication?"
133
+ taskgraph research "What's the best approach?" --id=15,23.2
134
+ taskgraph research "How does auth work?" --files=src/auth.js --tree
135
+ taskgraph research "Implementation steps?" --save-to=15.2 --detail=high`,{padding:1,borderColor:c,borderStyle:`round`}))}return e.command(`remove-task`).description(`Remove one or more tasks or subtasks permanently`).option(`-i, --id <ids>`,`ID(s) of the task(s) or subtask(s) to remove (e.g., "5", "5.2", or "5,6.1,7")`).option(`-f, --file <file>`,`Path to the tasks file`,i).option(`-y, --yes`,`Skip confirmation prompt`,!1).option(`--tag <tag>`,`Specify tag context for task operations`).action(async e=>{let t=Z({tasksPath:e.file||!0,tag:e.tag}),n=e.id,i=t.getCurrentTag();await T(i),n||(console.error(B.red(`Error: Task ID(s) are required`)),console.error(B.yellow(`Usage: taskgraph remove-task --id=<taskId1,taskId2...>`)),process.exit(1));let a=n.split(`,`).map(e=>e.trim()).filter(Boolean);a.length===0&&(console.error(B.red(`Error: No valid task IDs provided.`)),process.exit(1));try{let n=t.getTasksPath(),o=l(n,t.getProjectRoot(),i);(!o||!o.tasks)&&(console.error(B.red(`Error: No valid tasks found in ${n}`)),process.exit(1));let s=[],c=[],u=0,d=[];for(let e of a)if(!M(o.tasks,e))c.push(e);else{let t=r(o.tasks,e).task;if(t){if(s.push({id:e,task:t}),!t.isSubtask){t.subtasks&&t.subtasks.length>0&&(u+=t.subtasks.length);let n=o.tasks.filter(t=>t.dependencies&&t.dependencies.includes(parseInt(e,10)));n.length>0&&d.push(` - Task ${e}: ${n.length} dependent tasks (${n.map(e=>e.id).join(`, `)})`)}}else c.push(`${e} (error finding details)`)}let f=`${c.length===1?`Task`:`Tasks`} ${c.join(`, `)} not found`;if(s.length===0&&(I(f,"Run `taskgraph list` to see task IDs"),process.exit(1)),c.length>0&&console.warn(B.yellow(`${f}, skipping`)),!e.yes){console.log(),console.log(B.red.bold(`⚠️ WARNING: This will permanently delete the following ${s.length} item(s):`)),console.log(),s.forEach(({id:e,task:t})=>{t&&(t.isSubtask?(console.log(m.text(` Subtask ${e}: ${t.title||`(no title)`}`)),t.parentTask&&console.log(m.muted(` (Parent: ${t.parentTask.id} - ${t.parentTask.title||`(no title)`})`))):console.log(m.text.bold(` Task ${e}: ${t.title||`(no title)`}`)))}),u>0&&console.log(B.yellow(`⚠️ This will also delete ${u} subtasks associated with the selected main tasks!`)),d.length>0&&(console.log(B.yellow(`⚠️ Warning: Dependencies on the following tasks will be removed:`)),d.forEach(e=>console.log(B.yellow(e)))),console.log();let{confirm:e}=await q.prompt([{type:`confirm`,name:`confirm`,message:B.red.bold(`Are you sure you want to permanently delete these ${s.length} item(s)?`),default:!1}]);e||(console.log(m.brand(`Task deletion cancelled.`)),process.exit(0))}let p=Ae(`Removing ${s.length} task(s)/subtask(s)...`),h=s.map(({id:e})=>e).join(`,`),g=await ee(t.getTasksPath(),h,{projectRoot:t.getProjectRoot(),tag:i});me(p),g.success?console.log(W(B.green(`Successfully removed ${g.removedTasks.length} task(s)/subtask(s).`)+(g.message?`\n\nDetails:\n${g.message}`:``)+(g.error?`\n\nWarnings:\n${B.yellow(g.error)}`:``),{padding:1,borderColor:`green`,borderStyle:`round`})):(console.error(W(B.red(`Operation completed with errors. Removed ${g.removedTasks.length} task(s)/subtask(s).`)+(g.message?`\n\nDetails:\n${g.message}`:``)+(g.error?`\n\nErrors:\n${B.red(g.error)}`:``),{padding:1,borderColor:`red`,borderStyle:`round`})),process.exit(1)),c.length>0&&(console.warn(B.yellow(`Note: The following IDs were not found initially and were skipped: ${c.join(`, `)}`)),g.removedTasks.length===0&&process.exit(1))}catch(e){D(e)}}),e.command(`init`).description(`Initialize a new project with TaskGraph structure`).option(`-y, --yes`,`Skip prompts and use default values`).option(`-n, --name <name>`,`Project name`).option(`-d, --description <description>`,`Project description`).option(`-v, --version <version>`,`Project version`,`0.1.0`).option(`-a, --author <author>`,`Author name`).option(`-r, --rules <rules...>`,`Rule profiles to install (claude). Accepts comma or space separated values.`).option(`--skip-install`,`Skip installing dependencies`).option(`--dry-run`,`Show what would be done without making changes`).option(`--aliases`,`Add shell aliases (tm, taskgraph)`).option(`--no-aliases`,`Skip shell aliases (tm, taskgraph)`).option(`--git`,`Initialize Git repository`).option(`--no-git`,`Skip Git repository initialization`).option(`--git-tasks`,`Store tasks in Git`).option(`--no-git-tasks`,`No Git storage of tasks`).action(async e=>{let t=z,n=!1;if(e.rules&&Array.isArray(e.rules)){let r=e.rules.flatMap(e=>e.split(`,`)).map(e=>e.trim()).filter(Boolean),i=Ne(r);i.length>0&&(console.error(B.red(`Unsupported rule profile(s): ${i.join(`, `)}. TaskGraph supports Claude Code only; valid options: ${z.join(`, `)}`)),process.exit(1)),r.length>0&&(t=r,n=!0)}e.rules=t,e.rulesExplicitlyProvided=n;try{await Pe(e)}catch(e){console.error(B.red(`Error during initialization: ${e.message}`)),process.exit(1)}}),e.command(`models`).description(`Manage AI model configurations (Claude Code models)`).option(`--set-main <model_id>`,`Set the primary model for task generation/updates`).option(`--set-research <model_id>`,`Set the model for research-backed operations`).option(`--set-fallback <model_id>`,`Set the model to use if the primary fails`).option(`--setup`,`Run interactive setup to configure models`).addOption(new G(`--claude-code`).hideHelp()).addOption(new G(`--openrouter`).hideHelp()).addOption(new G(`--ollama`).hideHelp()).addOption(new G(`--bedrock`).hideHelp()).addOption(new G(`--azure`).hideHelp()).addOption(new G(`--vertex`).hideHelp()).addOption(new G(`--gemini-cli`).hideHelp()).addOption(new G(`--codex-cli`).hideHelp()).addOption(new G(`--lmstudio`).hideHelp()).addOption(new G(`--openai-compatible`).hideHelp()).addOption(new G(`--baseURL <url>`).hideHelp()).addHelpText(`after`,`
136
+ TaskGraph uses Claude Code. Available models: opus, sonnet, haiku.
137
+
138
+ Examples:
139
+ $ taskgraph models # View current configuration
140
+ $ taskgraph models --set-main sonnet # Set main model
141
+ $ taskgraph models --set-research opus # Set research model
142
+ $ taskgraph models --set-fallback haiku # Set fallback
143
+ $ taskgraph models --setup # Run interactive setup`).action(async e=>{let t=Z({tasksPath:e.file||!1}).getProjectRoot();if([`openrouter`,`ollama`,`bedrock`,`azure`,`vertex`,`geminiCli`,`codexCli`,`lmstudio`,`openaiCompatible`,`baseURL`].filter(t=>e[t]).length>0&&(console.error(B.red(`Error: TaskGraph now uses Claude Code only, so provider flags such as --ollama, --openrouter and --baseURL are no longer supported.`)),console.error(B.yellow(`Choose one of the Claude Code models: taskgraph models --set-main <opus|sonnet|haiku>`)),process.exit(1)),e.setup){console.log(m.brand(`Starting interactive model setup...`));try{await re(t)}catch(e){console.error(B.red(`
144
+ Interactive setup failed unexpectedly:`),e.message)}return}let n=[[`main`,e.setMain],[`research`,e.setResearch],[`fallback`,e.setFallback]].filter(([,e])=>e);if(n.length>0){let e=!1;for(let[r,i]of n){let n=await ae(r,i,{projectRoot:t});n.success?(console.log(B.green(`✅ ${n.data.message}`)),e=!0):console.error(B.red(`❌ Error setting ${r} model: ${n.error.message}`))}console.log(e?m.brand(`
145
+ Model configuration updated.`):B.yellow(`
146
+ No model configuration changes were made (or errors occurred).`));return}console.log(m.brand(`Fetching current model configuration...`));let r=await Se({projectRoot:t}),i=await oe({projectRoot:t});if(r.success?k(r.data,i.data?.models||[]):console.error(B.red(`❌ Error fetching configuration: ${r.error.message}`)),i.success){let e=r.success?[r.data.activeModels.main.modelId,r.data.activeModels.research.modelId,r.data.activeModels.fallback?.modelId].filter(Boolean):[];he(i.data.models.filter(t=>!e.includes(t.modelId)))}else console.error(B.yellow(`⚠️ Warning: Could not display available models: ${i.error.message}`));s(t)||console.log(B.yellow(`
147
+ Hint: Run 'taskgraph models --setup' to create or update your configuration.`))}),e.command(`lang`).description(`Manage response language settings`).option(`--response <response_language>`,`Set the response language`).option(`--setup`,`Run interactive setup to configure response language`).action(async e=>{let t=Z({}).getProjectRoot(),{response:n,setup:r}=e,i=n===void 0?`English`:n;if(r){console.log(m.brand(`Starting interactive response language setup...`));try{let e=await q.prompt([{type:`input`,name:`responseLanguage`,message:`Input your preferred response language`,default:`English`}]);console.log(m.brand(`Response language set to:`,e.responseLanguage)),i=e.responseLanguage}catch(e){console.error(B.red(`\\nInteractive setup failed unexpectedly:`),e.message)}}let a=Me(i,{projectRoot:t});a.success?console.log(B.green(`✅ ${a.data.message}`)):(console.error(B.red(`❌ Error setting response language: ${a.error.message}`)),process.exit(1))}),e.command(`move`).description(`Move tasks between tags or reorder within tags. Supports cross-tag moves with dependency resolution options.`).option(`-f, --file <file>`,`Path to the tasks file`,i).option(`--from <id>`,`ID of the task/subtask to move (e.g., "5" or "5.2"). Can be comma-separated to move multiple tasks (e.g., "5,6,7")`).option(`--to <id>`,`ID of the destination (e.g., "7" or "7.3"). Must match the number of source IDs if comma-separated`).option(`--tag <tag>`,`Specify tag context for task operations`).option(`--from-tag <tag>`,`Source tag for cross-tag moves`).option(`--to-tag <tag>`,`Target tag for cross-tag moves`).option(`--with-dependencies`,`Move dependent tasks along with main task`).option(`--ignore-dependencies`,`Break cross-tag dependencies during move`).action(async e=>{function t(){console.log(m.text.bold(`Move Command Help`)+`
148
+
149
+ `+B.cyan(`Move tasks between tags or reorder within tags.`)+`
150
+
151
+ `+B.yellow.bold(`Within-Tag Moves:`)+`
152
+ `+m.text(` taskgraph move --from=5 --to=7`)+`
153
+ `+m.text(` taskgraph move --from=5.2 --to=7.3`)+`
154
+ `+m.text(` taskgraph move --from=5,6,7 --to=10,11,12`)+`
155
+
156
+ `+B.yellow.bold(`Cross-Tag Moves:`)+`
157
+ `+m.text(` taskgraph move --from=5 --from-tag=backlog --to-tag=in-progress`)+`
158
+ `+m.text(` taskgraph move --from=5,6 --from-tag=backlog --to-tag=done`)+`
159
+
160
+ `+B.yellow.bold(`Dependency Resolution:`)+`
161
+ `+m.text(` # Move with dependencies`)+`
162
+ `+m.text(` taskgraph move --from=5 --from-tag=backlog --to-tag=in-progress --with-dependencies`)+`
163
+
164
+ `+m.text(` # Break dependencies`)+`
165
+ `+m.text(` taskgraph move --from=5 --from-tag=backlog --to-tag=in-progress --ignore-dependencies`)+`
166
+
167
+
168
+ `+B.yellow.bold(`Best Practices:`)+`
169
+ `+m.text(` • Use --with-dependencies to move dependent tasks together`)+`
170
+ `+m.text(` • Use --ignore-dependencies to break cross-tag dependencies`)+`
171
+ `+m.text(` • Check dependencies first: taskgraph validate-dependencies`)+`
172
+ `+m.text(` • Fix dependency issues: taskgraph fix-dependencies`)+`
173
+
174
+ `+B.yellow.bold(`Error Resolution:`)+`
175
+ `+m.text(` • Cross-tag dependency conflicts: Use --with-dependencies or --ignore-dependencies`)+`
176
+ `+m.text(` • Subtask movement: Promote subtask first with remove-subtask --convert`)+`
177
+ `+m.text(` • Invalid tags: Check available tags with taskgraph tags`)+`
178
+
179
+ `+m.muted(`For more help, run: taskgraph move --help`))}async function n(e,n){let{sourceId:r,sourceTag:i,toTag:a,taskGraph:o}=e;r||(console.error(B.red(`Error: --from parameter is required for cross-tag moves`)),t(),process.exit(1));let s=r.split(`,`).map(e=>e.trim()),c={withDependencies:n.withDependencies||!1,ignoreDependencies:n.ignoreDependencies||!1};console.log(m.brand(`Moving tasks ${s.join(`, `)} from "${i}" to "${a}"...`));let l=await ne(o.getTasksPath(),s,i,a,c,{projectRoot:o.getProjectRoot()});console.log(B.green(`✓ ${l.message}`)),Array.isArray(l.tips)&&l.tips.length>0&&(console.log(`
180
+ `+B.yellow.bold(`Next Steps:`)),l.tips.forEach(e=>console.log(m.text(` • ${e}`))))}async function r(e){let{sourceId:t,destinationId:n,tag:r,taskGraph:i}=e;(!t||!n)&&(console.error(B.red(`Error: Both --from and --to parameters are required for within-tag moves`)),console.log(B.yellow(`Usage: taskgraph move --from=<sourceId> --to=<destinationId>`)),process.exit(1));let a=t.split(`,`).map(e=>e.trim()),o=n.split(`,`).map(e=>e.trim());if(a.length!==o.length&&(console.error(B.red(`Error: The number of source and destination IDs must match`)),console.log(B.yellow(`Example: taskgraph move --from=5,6,7 --to=10,11,12`)),process.exit(1)),a.length>1){console.log(m.brand(`Moving multiple tasks: ${a.join(`, `)} to ${o.join(`, `)}...`));let e=l(i.getTasksPath(),i.getProjectRoot(),r);(!e||!e.tasks)&&(console.error(B.red(`Error: Invalid or missing tasks file at ${i.getTasksPath()}`)),process.exit(1));let t=[],n=[];for(let e=0;e<a.length;e++){let s=a[e],c=o[e];if(s===c)console.log(B.yellow(`Skipping ${s} -> ${c} (same ID)`));else{console.log(m.brand(`Moving task/subtask ${s} to ${c}...`));try{await x(i.getTasksPath(),s,c,e===a.length-1,{projectRoot:i.getProjectRoot(),tag:r}),console.log(B.green(`✓ Successfully moved task/subtask ${s} to ${c}`)),n.push({fromId:s,toId:c})}catch(e){let n={fromId:s,toId:c,error:e.message};t.push(n),console.error(B.red(`Error moving ${s} to ${c}: ${e.message}`))}}}t.length>0?(console.log(B.yellow(`
181
+ --- Move Operation Summary ---`)),console.log(B.green(`✓ Successfully moved: ${n.length} tasks`)),console.log(B.red(`✗ Failed to move: ${t.length} tasks`)),n.length>0&&(console.log(B.cyan(`
182
+ Successful moves:`)),n.forEach(({fromId:e,toId:t})=>{console.log(B.cyan(` ${e} → ${t}`))})),console.log(B.red(`
183
+ Failed moves:`)),t.forEach(({fromId:e,toId:t,error:n})=>{console.log(B.red(` ${e} → ${t}: ${n}`))}),console.log(B.yellow(`
184
+ Note: Some tasks were moved successfully. Check the errors above for failed moves.`))):console.log(B.green(`
185
+ ✓ All tasks moved successfully!`))}else console.log(m.brand(`Moving task/subtask ${t} to ${n}...`)),await x(i.getTasksPath(),t,n,!0,{projectRoot:i.getProjectRoot(),tag:r}),console.log(B.green(`✓ Successfully moved task/subtask ${t} to ${n}`))}function i(e,t){if(/not found/i.test(e.message)&&D(e),console.error(B.red(`Error: ${e.message}`)),e.code===`CROSS_TAG_DEPENDENCY_CONFLICTS`){let n=e.data.conflicts||[],r=e.data.taskIds||[];De(n,t.sourceTag,t.toTag,r.join(`, `))}else if(e.code===`CANNOT_MOVE_SUBTASK`){let n=e.data.taskId||t.sourceId?.split(`,`)[0];O(n,t.sourceTag,t.toTag)}else e.code===`SOURCE_TARGET_TAGS_SAME`||e.code===`SAME_SOURCE_TARGET_TAG`?F(t.sourceTag,t.toTag,`Source and target tags are identical`):E(`after-error`);process.exit(1)}let a=Z({tasksPath:e.file||!0,tag:e.tag}),o=e.from,s=e.to,c=e.fromTag,u=e.toTag,d=a.getCurrentTag(),f=c||a.getCurrentTag(),p=f&&u&&f!==u,h={sourceId:o,destinationId:s,sourceTag:f,toTag:u,tag:d,taskGraph:a};try{p?await n(h,e):await r(h)}catch(e){let t=String(e&&(e.message||e));t.includes(`already exists in target tag`)&&(console.error(B.red(`Error: ${t}`)),console.log(`
186
+ `+B.yellow.bold(`Conflict: ID already exists in target tag`)+`
187
+ `+m.text(` • Choose a different target tag without conflicting IDs`)+`
188
+ `+m.text(` • Move a different set of IDs (avoid existing ones)`)+`
189
+ `+m.text(` • If needed, move within-tag to a new ID first, then cross-tag move`)),process.exit(1)),i(e,h)}}),e.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=Z({tasksPath:e.file||!0,tag:e.tag}),n=e.withSubtasks||!1,r=e.status||null,i=t.getCurrentTag();console.log(m.brand(`📝 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))}),e.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(m.muted(` This command will be removed in a future version.
190
+ `));try{let n=Z({tasksPath:t.file||!0}),r=n.getTasksPath();U.existsSync(r)||(console.error(B.red(`Error: Tasks file not found at path: ${r}`)),console.log(B.yellow(`Hint: Run taskgraph init or taskgraph 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(` taskgraph add-tag my-tag`)),console.log(B.cyan(` taskgraph 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-DILdqQSS.js`),r=await import(`./git-utils-BezpEZd4.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 fe(n.getTasksPath(),e,r,i,`text`)}if(t.autoSwitch){let{useTag:r}=await import(`./tag-management-DILdqQSS.js`),a=t.fromBranch?(await import(`./git-utils-BezpEZd4.js`)).sanitizeBranchNameForTag(await(await import(`./git-utils-BezpEZd4.js`)).getCurrentBranch(projectRoot)):e;await r(n.getTasksPath(),a,{},i,`text`)}}catch(e){console.error(B.red(`Error creating tag: ${e.message}`)),a(),process.exit(1)}}).on(`error`,function(e){console.error(B.red(`Error: ${e.message}`)),a(),process.exit(1)}),e.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(m.muted(` This command will be removed in a future version.
191
+ `));try{let n=Z({tasksPath:t.file||!0}),r=n.getTasksPath();U.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 h(n.getTasksPath(),e,i,a,`text`)}catch(e){console.error(B.red(`Error deleting tag: ${e.message}`)),u(),process.exit(1)}}).on(`error`,function(e){console.error(B.red(`Error: ${e.message}`)),u(),process.exit(1)}),e.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: "taskgraph use-tag" is deprecated. Use "taskgraph tags use" instead.`)),console.log(m.muted(` This command will be removed in a future version.
192
+ `));try{let n=Z({tasksPath:t.file||!0}),r=n.getTasksPath();U.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 j(n.getTasksPath(),e,{},i,`text`)}catch(e){D(e)}}).on(`error`,function(e){console.error(B.red(`Error: ${e.message}`)),p(),process.exit(1)}),e.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(m.muted(` This command will be removed in a future version.
193
+ `));try{let r=Z({tasksPath:n.file||!0}),i=r.getTasksPath();U.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 _e(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)}),e.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(m.muted(` This command will be removed in a future version.
194
+ `));try{let r=Z({tasksPath:n.file||!0}),i=r.getTasksPath();U.existsSync(i)||(console.error(B.red(`Error: Tasks file not found at path: ${i}`)),process.exit(1));let a={description:n.description},o={projectRoot:r.getProjectRoot(),commandName:`copy-tag`,outputType:`cli`};await ue(i,e,t,a,o,`text`)}catch(e){console.error(B.red(`Error copying tag: ${e.message}`)),process.exit(1)}}).on(`error`,function(e){console.error(B.red(`Error: ${e.message}`)),process.exit(1)}),e.command(`tui`).alias(`repl`).description(`Launch the interactive TUI/REPL mode`).action(async()=>{await $()}),e}async function Je(){return null}async function $(){let e=await Je();if(!e){console.log(B.yellow(`TUI mode coming soon!`)),console.log(B.dim(`Showing help instead...
195
+ `)),L();return}let t=await import(`react`),{render:n,Shell:r}=e,i=`master`,a=process.cwd();try{let e=Z({});i=e.getCurrentTag(),a=e.getProjectRoot()||process.cwd()}catch{}let o=process.stdin.isTTY&&typeof process.stdin.setRawMode==`function`;console.clear();let s={showBanner:!0,showSplash:o,initialTag:i,isInteractive:o,projectRoot:a,onExit:()=>{console.log(B.dim(`
196
+ Goodbye! 👋`)),process.exit(0)}},c=n(t.createElement(r,s));o||setTimeout(()=>{c.unmount(),console.log(B.dim(`
197
+ 💡 Run in an interactive terminal for full REPL mode.`)),process.exit(0)},200)}function Ye(){let e=new Le().name(`taskgraph`).description(`AI-driven development task management`).version(`0.52.12`).helpOption(`-h, --help`,`Display help`).addHelpCommand(!1),t=e.helpInformation.bind(e);e.helpInformation=function(){return this.parent&&this.parent!==e?t():(L(),``)},qe(e);let n=(e,t)=>{e.configureOutput({outputError:(e,n)=>n(`\n${xe(e,t||void 0)}\n`)});for(let r of e.commands)n(r,t?`${t} ${r.name()}`:r.name())};return n(e,``),e}async function Xe(e=process.argv){try{if(e.length<=2){await $();return}let t=e.includes(`init`),n=e.includes(`tui`)||e.includes(`repl`),r=e.includes(`--no-banner`);process.stdout.isTTY&&!t&&!n&&!r&&we();let i=e[2]===`completion`,a=process.env.TASKGRAPH_SKIP_AUTO_UPDATE===`1`||process.env.CI||process.env.NODE_ENV===`test`||i,o=w(),s=a?{currentVersion:o,latestVersion:o,needsUpdate:!1}:await Ge(o);if(s.needsUpdate&&(ge(s.currentVersion,s.latestVersion,s.highlights),await Te(s.latestVersion))){be(e);return}let c=Ye(),l=e.filter(e=>e!==`--no-banner`);await c.parseAsync(l);try{if(i)return;let e=Z({}),t=e.getTasksPath(),n=e.getStatePath();if(t&&U.existsSync(t)){let e=U.readFileSync(t,`utf8`),r=JSON.parse(e);if(r&&r.master){let e={migrationNoticeShown:!1};if(n&&U.existsSync(n)){let t=U.readFileSync(n,`utf8`);e=JSON.parse(t)||e}e.migrationNoticeShown||(pe({_migrationHappened:!0}),e.migrationNoticeShown=!0,n&&U.writeFileSync(n,JSON.stringify(e,null,2)))}}}catch{}}catch(e){e instanceof p?console.error(W(B.red.bold(`Configuration Update Required!`)+`
198
+
199
+ `+m.text(`TaskGraph now uses a `)+B.yellow.bold(`configuration file`)+m.text(` in your project for AI model choices and settings.
200
+
201
+ This file appears to be `)+B.red.bold(`missing`)+m.text(`. No worries though.
202
+
203
+ `)+B.cyan.bold(`To create this file, run the interactive setup:`)+`
204
+ `+B.green(` taskgraph models --setup`)+`
205
+
206
+ `+m.text.bold(`Key Points:`)+`
207
+ `+m.text(`* `)+B.yellow.bold(`Configuration file`)+m.text(`: Stores your AI model settings (do not manually edit)
208
+ `)+m.text(`* `)+B.yellow.bold(`.env & .mcp.json`)+m.text(`: Still used `)+B.red.bold(`only`)+m.text(` for your AI provider API keys.
209
+
210
+ `)+B.cyan("`taskgraph models` to check your config & available models\n")+B.cyan("`taskgraph models --setup` to adjust the AI models used by TaskGraph"),{padding:1,margin:{top:1},borderColor:`red`,borderStyle:`round`})):D(e),process.exit(1)}}export{Xe as runCLI};
@@ -0,0 +1 @@
1
+ import{c as e,g as t,h as n,l as r}from"./src-BaM893RS.js";import{t as i}from"./git-utils--i2q96hv.js";import a from"chalk";import o from"path";import{z as s}from"zod";import c from"dotenv";import l from"fs";import{fileURLToPath as u}from"url";const d=[`add-task`,`analyze-complexity`,`expand-task`,`parse-prd`,`research`,`research-save`,`update-subtask`,`update-task`,`update-tasks`],f=`.taskgraph`,ee=`.taskgraph/tasks`,p=`.taskgraph/docs`,m=`.taskgraph/reports`,te=`.taskgraph/templates`,h=`.taskgraph/config.json`,ne=`.taskgraph/state.json`,g=`.taskgraph/reports/task-complexity-report.json`,re=`.taskgraph/docs/prd.txt`,ie=`.taskgraph/templates/example_prd.txt`,_=`.taskgraph/tasks/tasks.json`,ae=`.env.example`,oe=`.gitignore`,v={primary:`#0088CC`,accent:`#0096C7`,deep:`#0080C0`},se=[v.accent,v.primary,v.deep],ce=v.accent,le=[`dim`],ue={dimBorder:!0},y={brand:a.cyan,heading:a.cyan.bold,accent:a.magenta,active:a.cyan.bold,muted:a.dim,text:a};let b=!1;const de={maxRetries:5,retryDelay:100,staleLockAge:1e4};function fe(e){if(typeof SharedArrayBuffer<`u`&&typeof Atomics<`u`&&typeof Atomics.wait==`function`)try{let t=new SharedArrayBuffer(4),n=new Int32Array(t);Atomics.wait(n,0,0,e);return}catch{}let t=Date.now()+e;for(;Date.now()<t;);}function pe(e,t,n={}){let{createIfMissing:r=!1}=n,i=o.dirname(e);if(l.existsSync(i)||l.mkdirSync(i,{recursive:!0}),r)try{l.writeFileSync(e,`{}`,{flag:`wx`})}catch(e){if(e.code!==`EEXIST`)throw e}let a=`${e}.lock`,{maxRetries:s,retryDelay:c,staleLockAge:u}=de,d=!1;for(let e=0;e<s;e++)try{let e=JSON.stringify({pid:process.pid,timestamp:Date.now()});l.writeFileSync(a,e,{flag:`wx`}),d=!0;break}catch(t){if(t.code===`EEXIST`){try{let e=l.statSync(a);if(Date.now()-e.mtimeMs>u){let e=`${a}.stale.${process.pid}.${Date.now()}`;try{l.renameSync(a,e);try{l.unlinkSync(e)}catch{}continue}catch{}}}catch(e){if(e.code===`ENOENT`)continue;throw e}e<s-1&&fe(c*2**e)}else throw t}if(!d)throw Error(`Failed to acquire lock on ${e} after ${s} attempts`);try{return t()}finally{try{l.unlinkSync(a)}catch(t){T(`warn`,`Failed to release lock for ${e}: ${t.message}`)}}}function x(e,t=null,n=null){if(t?.env?.[e])return t.env[e];if(n){let t=o.join(n,`.env`);if(l.existsSync(t))try{let n=l.readFileSync(t,`utf-8`),r=c.parse(n);if(r&&r[e])return r[e]}catch(e){T(`warn`,`Could not read or parse ${t}: ${e.message}`)}}if(process.env[e])return process.env[e]}function S(e=process.cwd(),t=[`package.json`,`pyproject.toml`,`.git`]){let n=o.resolve(e),r=o.parse(n).root;for(;n!==r;){if(t.some(e=>{let t=o.join(n,e);return l.existsSync(t)}))return n;n=o.dirname(n)}return t.some(e=>{let t=o.join(r,e);return l.existsSync(t)})?r:null}const C={debug:0,info:1,warn:2,error:3,success:1};function me(){b=!0}function he(){b=!1}function w(){return b}function T(e,...t){if(w())return;let n=`info`;try{n=Je()||`info`}catch{n=`info`}let r={debug:y.muted(`[DEBUG]`),info:y.brand(`[INFO]`),warn:a.yellow(`[WARN]`),error:a.red(`[ERROR]`),success:a.green(`[SUCCESS]`)},i=C.hasOwnProperty(e)?e:`info`;if(C[i]>=(C[n]??C.info)){let e=r[i]||``,n=t.map(e=>typeof e==`object`?JSON.stringify(e):e).join(` `);console.log(`${e} ${n}`)}}function E(e){if(!e||typeof e!=`object`)return!1;for(let t in e)if(e.hasOwnProperty(t)&&typeof e[t]==`object`&&Array.isArray(e[t].tasks))return!0;return!1}function D(e){Array.isArray(e)&&e.forEach(e=>{if(e.id!==void 0){let t=parseInt(e.id,10);!isNaN(t)&&t>0&&(e.id=t)}Array.isArray(e.subtasks)&&e.subtasks.forEach(e=>{if(e.id!==void 0){if(typeof e.id==`string`&&e.id.includes(`.`)){let t=e.id.split(`.`);e.id=parseInt(t[t.length-1],10)}else{let t=parseInt(e.id,10);!isNaN(t)&&t>0&&(e.id=t)}}})})}function ge(e,t){let n=o.relative(process.cwd(),e),r=n&&!n.startsWith(`..`)&&!o.isAbsolute(n)?n:e,i=/\(line (\d+) column (\d+)\)/.exec(t.message),a=i?` (line ${i[1]}, column ${i[2]})`:``,s=Error(`${r} isn't valid JSON${a}`,{cause:t});return s.code=`JSON_PARSE_ERROR`,s}function O(e,t=null,n=null){let r=!1;try{r=Q()}catch{}if(r&&console.log(`readJSON called with: ${e}, projectRoot: ${t}, tag: ${n}`),!e)return null;let a;try{a=JSON.parse(l.readFileSync(e,`utf8`)),r&&console.log(`Successfully read JSON from ${e}`)}catch(t){if(r&&console.log(`Failed to read JSON from ${e}: ${t.message}`),t instanceof SyntaxError&&o.basename(e)===`tasks.json`)throw ge(e,t);return null}if(!e.includes(`tasks.json`)||!a)return r&&console.log(`File is not tasks.json or data is null, returning as-is`),a;if(Array.isArray(a.tasks)&&!a._rawTaggedData&&!E(a)){r&&console.log(`File is in legacy format, performing migration...`),D(a.tasks);let n={master:{tasks:a.tasks,metadata:a.metadata||{created:(/* @__PURE__ */ new Date()).toISOString(),updated:(/* @__PURE__ */ new Date()).toISOString(),description:`Tasks for master context`}}};try{if(_e(e,n),r&&console.log(`Successfully migrated legacy format to tagged format`),k(e),t)try{i(t,e)}catch{}M(e)}catch(e){r&&console.log(`Error writing migrated data: ${e.message}`)}a=n}if(typeof a==`object`&&!a.tasks){r&&console.log(`File is in tagged format, resolving tag...`);for(let e in a)if(a.hasOwnProperty(e)&&typeof a[e]==`object`&&a[e].tasks)try{I(a[e],{description:`Tasks for ${e} context`,skipUpdate:!0})}catch(t){r&&console.log(`Failed to ensure metadata for tag ${e}: ${t.message}`)}let s=JSON.parse(JSON.stringify(a));for(let e in s)s[e]&&Array.isArray(s[e].tasks)&&D(s[e].tasks);if(t)try{i(t,e)}catch{}try{let i=`master`;try{if(n)i=n;else if(t)i=F({projectRoot:t});else{let t=S(o.dirname(e));t&&(i=F({projectRoot:t}))}}catch(e){r&&console.log(`Tag resolution failed, using master: ${e.message}`)}r&&console.log(`Resolved tag: ${i}`);let c=a[i];if(c&&c.tasks){D(c.tasks);let e={...c,tag:i,_rawTaggedData:s};return r&&console.log(`Returning data for tag '${i}' with ${c.tasks.length} tasks`),e}{let e=a.master;return e&&e.tasks?(D(e.tasks),r&&console.log(`Tag '${i}' not found, falling back to master with ${e.tasks.length} tasks`),{...e,tag:`master`,_rawTaggedData:s}):(r&&console.log(`No valid tag data found, returning empty structure`),{tasks:[],tag:`master`,_rawTaggedData:s})}}catch(e){r&&console.log(`Error during tag resolution: ${e.message}`);let t=a.master;return t&&t.tasks?(D(t.tasks),{...t,_rawTaggedData:s}):{tasks:[],_rawTaggedData:s}}}return r&&console.log(`File format not recognized, returning as-is`),a}function k(e){try{let t=S(o.dirname(e))||o.dirname(e),n=o.join(t,`.taskgraph`,`config.json`);l.existsSync(n)&&A(n);let r=o.join(t,`.taskgraph`,`state.json`);l.existsSync(r)||j(r),Q()&&T(`debug`,`Complete tag migration performed for project: ${t}`)}catch(e){Q()&&T(`warn`,`Error during complete tag migration: ${e.message}`)}}function A(e){try{let t=l.readFileSync(e,`utf8`),n=JSON.parse(t);if(!n)return;let r=!1;n.global||={},n.global.defaultTag||(n.global.defaultTag=`master`,r=!0),r&&(l.writeFileSync(e,JSON.stringify(n,null,2),`utf8`),process.env.TASKGRAPH_DEBUG===`true`&&console.log(`[DEBUG] Updated config.json with tagged task system settings`))}catch(e){process.env.TASKGRAPH_DEBUG===`true`&&console.warn(`[WARN] Error migrating config.json: ${e.message}`)}}function j(e){try{let t={currentTag:`master`,lastSwitched:(/* @__PURE__ */ new Date()).toISOString(),branchTagMapping:{},migrationNoticeShown:!1};l.writeFileSync(e,JSON.stringify(t,null,2),`utf8`),process.env.TASKGRAPH_DEBUG===`true`&&console.log(`[DEBUG] Created initial state.json for tagged task system`)}catch(e){process.env.TASKGRAPH_DEBUG===`true`&&console.warn(`[WARN] Error creating state.json: ${e.message}`)}}function M(e){try{let t=o.dirname(o.dirname(e)),n=o.join(t,`.taskgraph`,`state.json`);l.existsSync(n)||j(n);try{let e=l.readFileSync(n,`utf8`),t=JSON.parse(e)||{};t.migrationNoticeShown===void 0&&(t.migrationNoticeShown=!1,l.writeFileSync(n,JSON.stringify(t,null,2),`utf8`))}catch(e){process.env.TASKGRAPH_DEBUG===`true`&&console.warn(`[WARN] Error updating state for migration notice: ${e.message}`)}}catch(e){process.env.TASKGRAPH_DEBUG===`true`&&console.warn(`[WARN] Error marking migration for notice: ${e.message}`)}}function _e(e,t,n=null,r=null){let i=process.env.TASKGRAPH_DEBUG===`true`;try{pe(e,()=>{let a=t;if(t&&!t._rawTaggedData&&n&&Array.isArray(t.tasks)&&!E(t)){let o=r||P(n);i&&console.log(`writeJSON: Detected resolved tag data missing _rawTaggedData. Re-reading raw data to prevent data loss for tag '${o}'.`);let s={};try{s=JSON.parse(l.readFileSync(e,`utf8`))}catch(e){i&&console.log(`writeJSON: Could not read existing file, starting fresh: ${e.message}`)}a={...s,[o]:{metadata:{...s[o]?.metadata||{},...t.metadata||{}},tasks:t.tasks}}}else if(t&&t._rawTaggedData&&n){let o=r||P(n),s;try{s=JSON.parse(l.readFileSync(e,`utf8`))}catch(e){s=t._rawTaggedData,i&&console.log(`writeJSON: Using _rawTaggedData as fallback: ${e.message}`)}let{_rawTaggedData:c,tag:u,...d}=t;a={...s,[o]:d},i&&console.log(`writeJSON: Merging resolved data back into tag '${o}'`)}let o=a;if(o&&typeof o==`object`){let{_rawTaggedData:e,tag:t,...n}=o;if(o=n,typeof o==`object`&&!Array.isArray(o)){let e={};for(let[t,n]of Object.entries(o))if(n&&typeof n==`object`&&Array.isArray(n.tasks)){let{created:r,description:i,...a}=n;a.metadata||={},r&&!a.metadata.created&&(a.metadata.created=r),i&&!a.metadata.description&&(a.metadata.description=i),e[t]=a}else e[t]=n;o=e}}let s=`${e}.tmp.${process.pid}`;try{l.writeFileSync(s,JSON.stringify(o,null,2),`utf8`),l.renameSync(s,e)}catch(e){try{l.existsSync(s)&&l.unlinkSync(s)}catch{}throw e}i&&console.log(`writeJSON: Successfully wrote to ${e}`)},{createIfMissing:!0})}catch(t){throw T(`error`,`Error writing JSON file ${e}:`,t.message),i&&T(`error`,`Full error details:`,t),t}}function ve(e=null){let t=!1;try{t=Q()}catch{t=!1}try{let n;if(n=e||o.join(process.cwd(),g),!l.existsSync(n))return t&&T(`debug`,`Complexity report not found at ${n}`),null;let r=O(n);return t&&T(`debug`,`Successfully read complexity report from ${n}`),r}catch(e){return t&&T(`error`,`Error reading complexity report: ${e.message}`),null}}function ye(e,t){return!e||!e.complexityAnalysis||!Array.isArray(e.complexityAnalysis)?null:e.complexityAnalysis.find(e=>e.taskId===t)}function N(e,t){let n;n=e.isSubtask?e.parentTask.id:e.parentId?e.parentId:e.id;let r=ye(t,n);r&&(e.complexityScore=r.complexityScore)}function be(e,t){if(!t||!e||!Array.isArray(e))return!1;if(typeof t==`string`&&t.includes(`.`)){let[n,r]=t.split(`.`).map(e=>parseInt(e,10)),i=e.find(e=>e.id===n);return!i||!i.subtasks?!1:i.subtasks.some(e=>e.id===r)}let n=parseInt(t,10);return e.some(e=>e.id===n)}function xe(e){return typeof e==`string`&&e.includes(`.`)?e:typeof e==`number`?e.toString():e}function Se(e,t,n=null,r=null){if(!t||!e||!Array.isArray(e))return{task:null,originalSubtaskCount:null};if(typeof t==`string`&&t.includes(`.`)){let[r,i]=t.split(`.`).map(e=>parseInt(e,10)),a=e.find(e=>e.id===r);if(!a||!a.subtasks)return{task:null,originalSubtaskCount:null,originalSubtasks:null};let o=a.subtasks.find(e=>e.id===i);return o&&(o.parentTask={id:a.id,title:a.title,status:a.status},o.isSubtask=!0),o&&n&&N(o,n),{task:o||null,originalSubtaskCount:null,originalSubtasks:null}}let i=null,a=null,o=null,s=parseInt(t,10),c=e.find(e=>e.id===s)||null;if(!c)return{task:null,originalSubtaskCount:null,originalSubtasks:null};if(i=c,r&&c.subtasks&&Array.isArray(c.subtasks)){o=[...c.subtasks],a=c.subtasks.length;let e={...c};e.subtasks=c.subtasks.filter(e=>e.status&&e.status.toLowerCase()===r.toLowerCase()),i=e}return i&&n&&N(i,n),{task:i,originalSubtaskCount:a,originalSubtasks:o}}function Ce(e,t){return!e||e.length<=t?e:`${e.slice(0,t-3)}...`}function we(e){return Array.isArray(e)?e.length===0:typeof e==`object`&&e?Object.keys(e).length===0:!1}function Te(e,t,n=/* @__PURE__ */ new Set,r=/* @__PURE__ */ new Set,i=[]){n.add(e),r.add(e),i.push(e);let a=[],o=t.get(e)||[];for(let e of o)if(!n.has(e)){let o=Te(e,t,n,r,[...i]);a.push(...o)}else if(r.has(e)){let t=i.indexOf(e);i.slice(t),a.push(e)}return r.delete(e),a}function Ee(e,t,n={}){let{maxDepth:r=50,includeSelf:i=!1,direction:a=`forward`,logger:o=null}=n,s=/* @__PURE__ */ new Set,c=/* @__PURE__ */ new Set;function l(e){if(typeof e==`string`){if(e.includes(`.`))return e;let t=parseInt(e,10);return isNaN(t)?e:t}return e}function u(e,n=0){if(n>=r){let t=`Maximum recursion depth (${r}) reached for task ${e}`;o&&typeof o.warn==`function`?o.warn(t):T!==void 0&&T.warn?T.warn(t):console.warn(t);return}if(c.has(e))return;c.add(e);let a=t.find(t=>t.id===e);a&&Array.isArray(a.dependencies)&&a.dependencies.forEach(t=>{let r=l(t);r==null||!i&&r===e||(s.add(r),u(r,n+1))})}function d(e,n=0){if(n>=r){let t=`Maximum recursion depth (${r}) reached for task ${e}`;o&&typeof o.warn==`function`?o.warn(t):T!==void 0&&T.warn?T.warn(t):console.warn(t)}else c.has(e)||(c.add(e),t.forEach(t=>{if(t.dependencies&&Array.isArray(t.dependencies)&&t.dependencies.some(t=>l(t)===e)){if(t.id==null||!i&&t.id===e)return;s.add(t.id),d(t.id,n+1)}}))}let f=a===`reverse`?d:u;return e.forEach(e=>{e&&e.id&&f(e.id)}),Array.from(s)}function De(e,t){if(!e||e.length===0)return null;let n={timestamp:(/* @__PURE__ */ new Date()).toISOString(),userId:e[0].userId,commandName:t,modelUsed:`Multiple`,providerName:`Multiple`,inputTokens:0,outputTokens:0,cachedInputTokens:0,totalTokens:0,totalCost:0,currency:e[0].currency||`USD`},r=/* @__PURE__ */ new Set,i=/* @__PURE__ */ new Set,a=/* @__PURE__ */ new Set;return e.forEach(e=>{n.inputTokens+=e.inputTokens||0,n.outputTokens+=e.outputTokens||0,n.cachedInputTokens+=e.cachedInputTokens||0,n.totalCost+=e.totalCost||0,r.add(e.modelUsed),i.add(e.providerName),a.add(e.currency||`USD`)}),n.totalTokens=n.inputTokens+n.outputTokens,n.totalCost=parseFloat(n.totalCost.toFixed(6)),r.size===1&&(n.modelUsed=[...r][0]),i.size===1&&(n.providerName=[...i][0]),a.size>1?n.currency=`Multiple`:a.size===1&&(n.currency=[...a][0]),n}function P(e){if(!e)throw Error(`projectRoot is required for getCurrentTag`);try{let t=o.join(e,`.taskgraph`,`state.json`);if(l.existsSync(t)){let e=l.readFileSync(t,`utf8`),n=JSON.parse(e);if(n&&n.currentTag)return n.currentTag}}catch{}try{let t=o.join(e,`.taskgraph`,`config.json`);if(l.existsSync(t)){let e=l.readFileSync(t,`utf8`),n=JSON.parse(e);if(n&&n.global&&n.global.defaultTag)return n.global.defaultTag}}catch{}return`master`}function F(e={}){let{projectRoot:t,tag:n}=e;if(!t)throw Error(`projectRoot is required for resolveTag`);return n||P(t)}function Oe(e,t){return!e||!t?[]:e[t]&&e[t].tasks&&Array.isArray(e[t].tasks)?e[t].tasks:[]}function ke(e){let t=[];for(let n of e)if(t.push({...n,searchableId:n.id.toString(),isSubtask:!1}),n.subtasks&&n.subtasks.length>0)for(let e of n.subtasks)t.push({...e,searchableId:`${n.id}.${e.id}`,isSubtask:!0,parentId:n.id,parentTitle:n.title,title:`${e.title} (subtask of: ${n.title})`,description:`${e.description} [Parent: ${n.description}]`});return t}function I(e,t={}){if(!e||typeof e!=`object`)throw Error(`tagObj must be a valid object`);let n=(/* @__PURE__ */ new Date()).toISOString();return e.metadata?(e.metadata.created||(e.metadata.created=n),t.skipUpdate||(e.metadata.updated=n),t.description&&!e.metadata.description&&(e.metadata.description=t.description)):e.metadata={created:n,updated:n,...t.description?{description:t.description}:{}},e}function Ae(){return{info:(e,...t)=>T(`info`,e,...t),warn:(e,...t)=>T(`warn`,e,...t),error:(e,...t)=>T(`error`,e,...t),debug:(e,...t)=>T(`debug`,e,...t),success:(e,...t)=>T(`success`,e,...t)}}function L(e=null){return e||Ae()}function R(e){return r(e)}function z(t=process.cwd()){return e(t)}function je(e=null,t=null,n=null){let r=L(n),i=t?.projectRoot||z();if(!i)return r.warn?.(`Could not determine project root directory`),null;let a=R(i);if(e){let t=o.isAbsolute(e)?e:o.resolve(a,e);if(l.existsSync(t))return r.info?.(`Using explicit tasks path: ${t}`),t;r.warn?.(`Explicit tasks path not found: ${t}, trying fallbacks`)}let s=o.join(a,_);return l.existsSync(s)?(r.info?.(`Found tasks file at: ${s}`),s):(r.warn?.(`No tasks.json found in project: ${a}`),null)}function Me(e=null,t=null,n=null){let r=L(n);if(e){let t=process.env.TASKGRAPH_ORIGINAL_CWD||process.cwd(),n=o.isAbsolute(e)?e:o.resolve(t,e);if(l.existsSync(n))return r.info?.(`Using explicit PRD path: ${n}`),n;r.warn?.(`Explicit PRD path not found: ${n}, trying fallbacks`)}let i=t?.projectRoot||z();if(!i)return r.warn?.(`Could not determine project root directory`),null;let a=R(i);for(let e of[`PRD.md`,`prd.md`,`PRD.txt`,`prd.txt`]){let t=o.join(a,p,e);if(l.existsSync(t))return r.info?.(`Found PRD document at: ${t}`),t}return r.warn?.(`No PRD document found in project: ${a}`),null}function Ne(e=null,t=null,n=null){let r=L(n);if(e){let t=process.env.TASKGRAPH_ORIGINAL_CWD||process.cwd(),n=o.isAbsolute(e)?e:o.resolve(t,e);if(l.existsSync(n))return r.info?.(`Using explicit complexity report path: ${n}`),n;r.warn?.(`Explicit complexity report path not found: ${n}, trying fallbacks`)}let i=t?.projectRoot||z();if(!i)return r.warn?.(`Could not determine project root directory`),null;let a=R(i),s=[`task-complexity-report`,`task-complexity`,`complexity-report`].map(e=>t?.tag&&t?.tag!==`master`?`${e}_${t.tag}.json`:`${e}.json`);for(let e of s){let t=o.join(a,m,e);if(l.existsSync(t))return r.info?.(`Found complexity report at: ${t}`),t}return r.warn?.(`No complexity report found in project: ${a}`),null}function Pe(e=null,t=null,n=null){let r=L(n),i=t?.tag;if(e){let t=process.env.TASKGRAPH_ORIGINAL_CWD||process.cwd(),n=o.isAbsolute(e)?e:o.resolve(t,e);return r.info?.(`Using explicit complexity report output path: ${n}`),n}let a=R(t?.projectRoot||z()||process.cwd()),s=`task-complexity-report.json`;i&&i!==`master`&&(s=`task-complexity-report_${i}.json`);let c=o.join(a,`.taskgraph/reports`,s);r.info?.(`Using tag-aware complexity report output path: ${c}`);let u=o.dirname(c);return l.existsSync(u)||(r.info?.(`Creating reports directory: ${u}`),l.mkdirSync(u,{recursive:!0})),c}function B(e=null,t=null,n=null){let r=L(n);if(e){let t=process.env.TASKGRAPH_ORIGINAL_CWD||process.cwd(),n=o.isAbsolute(e)?e:o.resolve(t,e);if(l.existsSync(n))return r.info?.(`Using explicit config path: ${n}`),n;r.warn?.(`Explicit config path not found: ${n}, trying fallbacks`)}let i=t?.projectRoot||z();if(!i)return r.warn?.(`Could not determine project root directory`),null;let a=R(i),s=o.join(a,h);if(l.existsSync(s))return s;if(!G()){let e=`config_warning_${a}`;global._tmConfigWarningsThisRun||(global._tmConfigWarningsThisRun=/* @__PURE__ */ new Set),global._tmConfigWarningsThisRun.has(e)||(global._tmConfigWarningsThisRun.add(e),r.warn?.(`No configuration file found in project: ${a}`))}return null}var V={"claude-code":[{id:`opus`,swe_score:.725,cost_per_1m_tokens:{input:0,output:0},allowed_roles:[`main`,`fallback`,`research`],max_tokens:32e3,supported:!0},{id:`sonnet`,swe_score:.727,cost_per_1m_tokens:{input:0,output:0},allowed_roles:[`main`,`fallback`,`research`],max_tokens:64e3,supported:!0},{id:`haiku`,swe_score:.45,cost_per_1m_tokens:{input:0,output:0},allowed_roles:[`main`,`fallback`,`research`],max_tokens:2e5,supported:!0}]};const Fe=u(import.meta.url);o.dirname(Fe);const H={models:{main:{provider:`claude-code`,modelId:`sonnet`,maxTokens:64e3,temperature:.2},research:{provider:`claude-code`,modelId:`sonnet`,maxTokens:8700,temperature:.1},fallback:{provider:`claude-code`,modelId:`sonnet`,maxTokens:64e3,temperature:.2}},global:{logLevel:`info`,debug:!1,defaultNumTasks:10,defaultSubtasks:5,defaultPriority:`medium`,projectName:`TaskGraph`,responseLanguage:`English`,enableCodebaseAnalysis:!0,enableProxy:!1},claudeCode:{}};let U=null,W=null;function G(){return global._tmSuppressConfigWarnings===!0}var Ie=class extends Error{constructor(e){super(e),this.name=`ConfigurationError`}};function Le(e=null){let t=H,n=e;e&&`${e}`,n||(n=S(),n||=process.cwd(),`${n}`);let r=null,i={...t};if(l.existsSync(o.join(n,`.taskgraph`))&&(r=B(null,{projectRoot:n})),r)try{let e=l.readFileSync(r,`utf-8`),n=JSON.parse(e);i={models:{main:{...t.models.main,...n?.models?.main},research:{...t.models.research,...n?.models?.research},fallback:n?.models?.fallback?.provider&&n?.models?.fallback?.modelId?{...t.models.fallback,...n.models.fallback}:{...t.models.fallback}},global:{...t.global,...n?.global},claudeCode:{...t.claudeCode,...n?.claudeCode}},`${r}`,q(i.models.main.provider)||(console.warn(a.yellow(`Warning: Invalid main provider "${i.models.main.provider}" in ${r}. Falling back to default. Run 'taskgraph models --setup' to choose a Claude Code model.`)),i.models.main={...t.models.main}),q(i.models.research.provider)||(console.warn(a.yellow(`Warning: Invalid research provider "${i.models.research.provider}" in ${r}. Falling back to default. Run 'taskgraph models --setup' to choose a Claude Code model.`)),i.models.research={...t.models.research}),i.models.fallback?.provider&&!q(i.models.fallback.provider)&&(console.warn(a.yellow(`Warning: Invalid fallback provider "${i.models.fallback.provider}" in ${r}. Fallback model configuration will be ignored. Run 'taskgraph models --setup' to choose a Claude Code model.`)),i.models.fallback.provider=void 0,i.models.fallback.modelId=void 0),i.claudeCode&&!we(i.claudeCode)&&(i.claudeCode=J(i.claudeCode))}catch(e){console.error(a.red(`Error reading or parsing ${r}: ${e.message}. Using default configuration.`)),i={...t},`${r}`}else G()||(e?console.warn(a.yellow(`Warning: Configuration file not found at provided project root (${e}). Using default configuration. Run 'taskgraph models --setup' to configure.`)):l.existsSync(o.join(n,`.taskgraph`))&&console.warn(a.yellow(`Warning: Configuration file not found at derived root (${n}). Using defaults.`))),i={...t},`${n}`;return i}function K(e=null,t=!1){if(!U||t||e&&e!==W){let n=Le(e);return(t||e)&&(U=n,W=e),n}return U}function q(e){return!!t.includes(e)}function Re(e){return V[e]?V[e].filter(e=>e.supported!==!1).map(e=>e.id):[]}function J(e){let t=s.object({pathToClaudeCodeExecutable:s.string().optional(),maxTurns:s.number().int().positive().optional(),customSystemPrompt:s.string().optional(),appendSystemPrompt:s.string().optional(),permissionMode:s.enum([`default`,`acceptEdits`,`plan`,`bypassPermissions`]).optional(),allowedTools:s.array(s.string()).optional(),disallowedTools:s.array(s.string()).optional(),mcpServers:s.record(s.string(),s.object({type:s.enum([`stdio`,`sse`]).optional(),command:s.string(),args:s.array(s.string()).optional(),env:s.record(s.string(),s.string()).optional(),url:s.url().optional(),headers:s.record(s.string(),s.string()).optional()})).optional()}),n=s.record(s.string(),t).refine(e=>Object.keys(e||{}).every(e=>d.includes(e)),{message:`Invalid command name in commandSpecific`}),r=t.extend({commandSpecific:n.optional()}),i={};try{i=r.parse(e)}catch(e){console.warn(a.yellow(`Warning: Invalid Claude Code settings in config: ${e.message}. Falling back to default.`)),i={}}return i}function Y(e=null,t=!1){let n=K(e,t);return{...H.claudeCode,...n?.claudeCode||{}}}function ze(e,t=null,n=!1){let r=Y(t,n),i=r?.commandSpecific||{};return{...r,...i[e]}}function X(e,t=null){return K(t)?.models?.[e]||(T(`warn`,`No model configuration found for role: ${e}. Returning default.`),H.models[e]||{})}function Be(e=null){return X(`main`,e).provider}function Ve(e=null){return X(`main`,e).modelId}function He(e=null){return X(`research`,e).provider}function Ue(e=null,t=null){let n=x(`TASKGRAPH_ENABLE_CODEBASE_ANALYSIS`,e,t);if(n!=null&&n!==``)return n.toLowerCase()===`true`||n===`1`;if(e?.env?.TASKGRAPH_ENABLE_CODEBASE_ANALYSIS){let t=e.env.TASKGRAPH_ENABLE_CODEBASE_ANALYSIS;return t.toLowerCase()===`true`||t===`1`}return Z(t).enableCodebaseAnalysis!==!1}function We(e=!1,t=null,r=null){return!Ue(r,t)||e?!1:(e?He(t):Be(t))===n.CLAUDE_CODE}function Ge(e=null){return X(`research`,e).modelId}function Ke(e=null){return X(`fallback`,e).provider}function qe(e=null){return X(`fallback`,e).modelId}function Z(e=null){let t=K(e);return{...H.global,...t?.global||{}}}function Je(e=null){return Z(e).logLevel.toLowerCase()}function Q(e=null){return Z(e).debug===!0}function Ye(e=null){let t=Z(e).defaultSubtasks,n=parseInt(t,10);return Number.isNaN(n)?H.global.defaultSubtasks:n}function Xe(e=null){let t=Z(e).defaultNumTasks,n=parseInt(t,10);return Number.isNaN(n)?H.global.defaultNumTasks:n}function Ze(e=null){return Z(e).defaultPriority}function Qe(e=null){return Z(e).projectName}function $e(e=null){return Z(e).responseLanguage}function et(e=null){return Z(e).enableProxy===!0}function tt(e=null,t=null){let n=x(`TASKGRAPH_ENABLE_PROXY`,e,t);if(n!=null&&n!==``)return n.toLowerCase()===`true`||n===`1`;if(e?.env?.TASKGRAPH_ENABLE_PROXY){let t=e.env.TASKGRAPH_ENABLE_PROXY;return t.toLowerCase()===`true`||t===`1`}return et(t)}function nt(e,t=null){let n=X(e,t),r=n.maxTokens,i=n.temperature,a=n.modelId,o=n.provider,s=r,c=i;try{let e=V[o];if(e&&Array.isArray(e)){let t=e.find(e=>e.id===a);if(t&&typeof t.max_tokens==`number`&&t.max_tokens>0){let e=t.max_tokens;s=Math.min(r,e),T(`debug`,`Applying model-specific max_tokens (${e}) for ${a}. Effective limit: ${s}`)}else T(`debug`,`No valid model-specific max_tokens override found for ${a}. Using role default: ${r}`);t&&typeof t.temperature==`number`&&t.temperature>=0&&t.temperature<=1&&(c=t.temperature,T(`debug`,`Applying model-specific temperature (${t.temperature}) for ${a}`))}else T(`debug`,`No model definitions found for provider ${o} in MODEL_MAP. Using role default maxTokens: ${r}`)}catch(e){T(`warn`,`Error looking up model-specific parameters for ${a}: ${e.message}. Using role defaults.`),s=r,c=i}return{maxTokens:s,temperature:c}}function rt(){let e=[];for(let[t,n]of Object.entries(V))n.length>0&&n.filter(e=>!!e.supported).forEach(n=>{let r=n.id,i=n.swe_score,a=n.cost_per_1m_tokens,o=n.allowed_roles||[`main`,`fallback`],s=n.name;s||=r.split(`-`).map(e=>e.charAt(0).toUpperCase()+e.slice(1)).join(` `),e.push({id:r,name:s,provider:t,swe_score:i,cost_per_1m_tokens:a,allowed_roles:o,max_tokens:n.max_tokens})});return e}function $(e,t=null){let n=t;if(t==null){let e=S();if(!e)return console.error(a.red(`Error: Could not determine project root. Configuration not saved.`)),!1;n=e}let r=o.join(n,`.taskgraph`),i=o.join(r,`config.json`);try{return l.existsSync(r)||l.mkdirSync(r,{recursive:!0}),l.writeFileSync(i,JSON.stringify(e,null,2)),U=e,!0}catch(e){return console.error(a.red(`Error writing configuration to ${i}: ${e.message}`)),!1}}function it(e=null){return B(null,{projectRoot:e})!==null}function at(e=null){let t=K(e);return t.global||={},t.global.userId||(t.global.userId=`1234567890`,$(t,e)||T(`warning`,`Failed to write updated configuration with new userId. Please let the developers know.`)),t.global.userId}export{Oe as $,$ as A,m as At,N as B,We as C,ae as Ct,tt as D,h as Dt,G as E,re as Et,z as F,I as G,j as H,je as I,Se as J,Te as K,R as L,Ne as M,ee as Mt,B as N,_ as Nt,J as O,f as Ot,Me as P,te as Pt,P as Q,Pe as R,at as S,g as St,it as T,oe as Tt,he as U,De as V,me as W,ke as X,ye as Y,xe as Z,et as _,ce as _t,K as a,D as at,$e as b,le as bt,Ze as c,O as ct,Ke as d,be as dt,we as et,Je as f,Ee as ft,Qe as g,se as gt,nt as h,_e as ht,ze as i,A as it,V as j,ne as jt,q as k,p as kt,Ye as l,x as lt,Be as m,pe as mt,rt as n,T as nt,Q as o,k as ot,Ve as p,Ce as pt,S as q,Y as r,M as rt,Xe as s,ve as st,Ie as t,w as tt,qe as u,F as ut,Ge as v,v as vt,Ue as w,ie as wt,Re as x,y as xt,He as y,ue as yt,C as z};
@@ -0,0 +1 @@
1
+ import"./src-BaM893RS.js";export{S as getUserId}from"./config-manager-BxNrtquR.js";