taskgraph-ai 0.52.3 → 0.52.4

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 (30) hide show
  1. package/README.md +16 -5
  2. package/dist/ai-services-unified-BTTXDpEu.js +1 -0
  3. package/dist/{ai-services-unified-C_rt4w5B.js → ai-services-unified-CL8dbLYJ.js} +1 -1
  4. package/dist/assets/AGENTS.md +12 -31
  5. package/dist/assets/example_prd_rpg.txt +1 -4
  6. package/dist/assets/scripts_README.md +12 -14
  7. package/dist/{commands-REN-S3Y5.js → commands-B49KHl_a.js} +5 -5
  8. package/dist/{config-manager-ze5VncSH.js → config-manager-BTO7V7yI.js} +1 -1
  9. package/dist/{config-manager-DDFU1C2i.js → config-manager-cM9YWtuF.js} +1 -1
  10. package/dist/{dependency-manager-BPBdmQcF.js → dependency-manager-Mm62BpiN.js} +9 -9
  11. package/dist/{init-DE4mO3CM.js → init-C75AhVRQ.js} +3 -3
  12. package/dist/mcp-server.js +2 -2
  13. package/dist/research-ZJOfL6U9.js +1 -0
  14. package/dist/response-language-BiLoLKGt.js +1 -0
  15. package/dist/{response-language-8XZaALbD.js → response-language-CAUwZ_BR.js} +1 -1
  16. package/dist/src-kk3jUMbL.js +207 -0
  17. package/dist/tag-management-upzMTb_q.js +1 -0
  18. package/dist/{task-manager-9jVID7X1.js → task-manager-Bo-fv6V-.js} +1 -1
  19. package/dist/taskgraph.js +1 -1
  20. package/dist/update-subtask-by-id-usEluJxs.js +1 -0
  21. package/dist/update-task-by-id-BDHadCwU.js +1 -0
  22. package/dist/{utils-Drd3leuW.js → utils-D-_waI9k.js} +1 -1
  23. package/package.json +2 -10
  24. package/dist/ai-services-unified-BDcAS7eZ.js +0 -1
  25. package/dist/research-CC0KE46z.js +0 -1
  26. package/dist/response-language-Bo97h8xL.js +0 -1
  27. package/dist/src-DUT6aK7P.js +0 -203
  28. package/dist/tag-management-neogW4lA.js +0 -1
  29. package/dist/update-subtask-by-id-Dv7PlU5v.js +0 -1
  30. package/dist/update-task-by-id-Dzn7ZNbs.js +0 -1
package/README.md CHANGED
@@ -62,11 +62,11 @@ TaskGraph turns a product requirements document (PRD) into a dependency-aware ta
62
62
 
63
63
  </details>
64
64
 
65
- > **Attribution:** TaskGraph is based on [Task Master](https://github.com/eyaltoledano/claude-task-master) by Eyal Toledano ([@eyaltoledano](https://x.com/eyaltoledano)) and Ralph Khreish ([@RalphEcom](https://x.com/RalphEcom)). It is named `taskgraph-ai` with `taskgraph` and `taskgraph-mcp` binaries, so it can sit next to the original, and it keeps the original license and copyright notices (see [Licensing](#licensing)). Existing `.taskmaster/` project folders work unchanged.
65
+ > **Attribution:** TaskGraph is based on [Task Master](https://github.com/eyaltoledano/claude-task-master) by Eyal Toledano ([@eyaltoledano](https://x.com/eyaltoledano)) and Ralph Khreish ([@RalphEcom](https://x.com/RalphEcom)). It is named `taskgraph-ai` with `taskgraph` and `taskgraph-mcp` binaries, so it can sit next to the original, and it keeps the original license and copyright notices (see [Licensing](#licensing)). Coming from Task Master or a release before 0.47? See [Upgrading](#upgrading).
66
66
 
67
67
  ## Contents
68
68
 
69
- [Set up in Claude Code](#set-up-in-claude-code) · [How to use it](#how-to-use-it) · [Commands](#commands) · [MCP tool tiers](#mcp-tool-tiers) · [Models](#models) · [Troubleshooting](#troubleshooting) · [Docs](#documentation) · [Licensing](#licensing)
69
+ [Set up in Claude Code](#set-up-in-claude-code) · [How to use it](#how-to-use-it) · [Commands](#commands) · [MCP tool tiers](#mcp-tool-tiers) · [Models](#models) · [Upgrading](#upgrading) · [Troubleshooting](#troubleshooting) · [Docs](#documentation) · [Licensing](#licensing)
70
70
 
71
71
  ## Set up in Claude Code
72
72
 
@@ -215,7 +215,7 @@ taskgraph research "latest JWT best practices"
215
215
  taskgraph models --setup # choose models
216
216
  ```
217
217
 
218
- Every command, flag and example is in the [command reference](docs/command-reference.md).
218
+ Every command, flag and example is in the [command reference](apps/docs/capabilities/cli-root-commands.mdx).
219
219
 
220
220
  ## MCP tool tiers
221
221
 
@@ -242,7 +242,18 @@ Or edit the `env` block in `.mcp.json`, then restart Claude Code.
242
242
 
243
243
  TaskGraph uses three roles: **main**, **research** and **fallback** (used if either of the others fails). The choices are `opus`, `sonnet` and `haiku`. The research role gets web search and fetch only. It cannot read or change your files and has no shell.
244
244
 
245
- In Claude Code, say `Change the main model to opus`, or run `taskgraph models --setup`. Details are in [Models](docs/models.md) and the [Claude Code guide](docs/examples/claude-code-usage.md).
245
+ In Claude Code, say `Change the main model to opus`, or run `taskgraph models --setup`. Details are in [Models](docs/models.md) and the [Claude Code guide](apps/docs/capabilities/claude-code.mdx).
246
+
247
+ ## Upgrading
248
+
249
+ Projects created with Task Master, or with a TaskGraph release before 0.47, need a few manual changes:
250
+
251
+ - **Rename `.taskmaster/` to `.taskgraph/`** by hand. TaskGraph no longer detects the old folder.
252
+ - **Rename environment variables:** `TASK_MASTER_*` and `TASKMASTER_*` are now `TASKGRAPH_*`. The old names are ignored.
253
+ - **Removed:** the `taskgraph migrate` command and `.taskmasterconfig`. Configuration lives in `.taskgraph/config.json`; run `taskgraph models --setup` to recreate it.
254
+ - **Claude Code only:** other providers and their flags are gone, models are `opus`, `sonnet` and `haiku`, and the only API key still read is the optional `CLAUDE_CODE_API_KEY`.
255
+
256
+ Full details are in the [upgrade guide](apps/docs/upgrading.mdx).
246
257
 
247
258
  ## Troubleshooting
248
259
 
@@ -256,7 +267,7 @@ In Claude Code, say `Change the main model to opus`, or run `taskgraph models --
256
267
 
257
268
  ## Documentation
258
269
 
259
- [Tutorial](docs/tutorial.md) · [Command reference](docs/command-reference.md) · [Configuration](docs/configuration.md) · [Task structure](docs/task-structure.md) · [Examples](docs/examples.md) · [Models](docs/models.md) · [Plugin](CLAUDE_CODE_PLUGIN.md) · [Contributing](CONTRIBUTING.md) · [Changelog](CHANGELOG.md)
270
+ [Tutorial](apps/docs/tutorial.mdx) · [Command reference](apps/docs/capabilities/cli-root-commands.mdx) · [Configuration](apps/docs/configuration.mdx) · [Task structure](apps/docs/capabilities/task-structure.mdx) · [Examples](apps/docs/examples.mdx) · [Models](docs/models.md) · [Upgrading](apps/docs/upgrading.mdx) · [Plugin](CLAUDE_CODE_PLUGIN.md) · [Contributing](CONTRIBUTING.md) · [Changelog](CHANGELOG.md)
260
271
 
261
272
  ## Contributors
262
273
 
@@ -0,0 +1 @@
1
+ import{a as e,i as t,n,r,t as i}from"./ai-services-unified-CL8dbLYJ.js";import"./src-kk3jUMbL.js";import"./config-manager-BTO7V7yI.js";import"./git-utils-CrYiSKu0.js";export{i as generateObjectService,n as generateTextService,r as logAiUsage,t as streamObjectService,e as streamTextService};
@@ -1,3 +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-ze5VncSH.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=>{let t={};for(var n in e)w(t,n,{get:e[n],enumerable:!0});return t},E=v(import.meta.url);const{JSONParseError:D,NoObjectGeneratedError:O,generateObject:k,generateText:A,streamObject:j,streamText:ee,zodSchema:te}=x,M=x.jsonSchema,N=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(`
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-BTO7V7yI.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=>{let t={};for(var n in e)w(t,n,{get:e[n],enumerable:!0});return t},E=v(import.meta.url);const{JSONParseError:D,NoObjectGeneratedError:O,generateObject:k,generateText:A,streamObject:j,streamText:ee,zodSchema:te}=x,M=x.jsonSchema,N=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
2
 
3
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 A({model:(await this.getClient(e))(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 n=t.usage?.inputTokens??t.usage?.promptTokens??0,r=t.usage?.outputTokens??t.usage?.completionTokens??0,i=t.usage?.totalTokens??n+r;return{text:t.text,usage:{inputTokens:n,outputTokens:r,totalTokens:i}}}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 ee({model:(await this.getClient(e))(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}`),t}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:e.mode||`auto`,maxOutputTokens:e.maxTokens,...this.supportsTemperature&&e.temperature!==void 0?{temperature:e.temperature}:{}});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;return{object:r.object,usage:{inputTokens:i,outputTokens:a,totalTokens:o}}}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(`warn`,`Claude Code CLI not detected. Install it with: npm install -g @anthropic-ai/claude-code`)}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,...t,...U(e.role,t)}})}catch(e){let t=String(e?.message||``);if(e?.code===`ENOENT`||/claude/i.test(t)){let t=Error(`Claude Code CLI not available. Please install Claude Code CLI first. Original error: ${e.message}`);t.cause=e,this.handleError(`Claude Code CLI initialization`,t)}else this.handleError(`client initialization`,e)}}getSupportedModels(){return this.supportedModels}isModelSupported(e){return e?this.supportedModels.includes(String(e).toLowerCase()):!1}};let G=null;var K=class e{constructor(){this._providers=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: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();var q=K;const J={"claude-code":new W};function Y(e){if(J[e])return J[e];let t=q.getInstance();return t.hasProvider(e)?(u(`debug`,`Provider "${e}" found in dynamic registry`),t.getProvider(e)):null}function X(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 re(e,t,n,r){let i=(e||0)/1e6*n+(t||0)/1e6*r;return parseFloat(i.toFixed(6))}function ie(e){let n={currentTag:`master`,availableTags:[`master`]};try{return e?{currentTag:t(e)||`master`,availableTags:ae(e)}:n}catch(e){return d()&&u(`debug`,`Error getting tag information: ${e.message}`),n}}function ae(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=>oe(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 oe(e){return e&&typeof e==`object`&&Array.isArray(e.tasks)}function se(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 ce(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 Z(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 le(e,t,n=null){let r=Y(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 ue(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}`),se(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=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=Z(t,y);if(!w){u(`error`,`Unknown role encountered in _unifiedServiceRunner: ${t}`),C||=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||=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=Y(n?.toLowerCase()),!p){u(`warn`,`Skipping role '${t}': Provider '${n}' not supported.`),C||=Error(`Unsupported provider configured: ${n}`);continue}d=a(t,y),s=le(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 ue(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,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=ie(y);return{mainResult:k,telemetryData:T,tagInfo:A,providerName:n,modelId:i}}catch(r){let a=ce(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 de(e){return Q(`generateText`,{outputType:`cli`,...e})}async function fe(e){return Q(`streamText`,{outputType:`cli`,...e})}async function pe(e){let t={outputType:`cli`,...e};if(!t.schema)throw Error(`streamObjectService requires a schema parameter`);return Q(`streamObject`,t)}async function me(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,outputType:o}){try{let o=new Date().toISOString(),s=(i||0)+(a||0),{inputCost:c,outputCost:l,currency:f,isUnknown:p}=X(n,r),m=re(i,a,c,l),h={timestamp:o,userId:e,commandName:t,modelUsed:r,providerName:n,inputTokens:i||0,outputTokens:a||0,totalTokens:s,totalCost:m,currency:f,isUnknownCost:p};return d()&&u(`info`,`AI Usage Telemetry:`,h),h}catch(e){return u(`error`,`Failed to log AI usage telemetry: ${e.message}`,{error:e}),null}}export{fe as a,pe as i,de as n,T as o,$ as r,me as t};
@@ -43,7 +43,7 @@ taskgraph generate # Update task markdow
43
43
  - `.taskgraph/config.json` - AI model configuration (use `taskgraph models` to modify)
44
44
  - `.taskgraph/docs/prd.md` - Product Requirements Document for parsing (`.md` extension recommended for better editor support)
45
45
  - `.taskgraph/tasks/*.txt` - Individual task files (auto-generated from tasks.json)
46
- - `.env` - API keys for CLI usage
46
+ - `.env` - Optional environment variables (for example `CLAUDE_CODE_API_KEY`)
47
47
 
48
48
  **PRD File Format:** While both `.txt` and `.md` extensions work, **`.md` is recommended** because:
49
49
  - Markdown syntax highlighting in editors improves readability
@@ -76,7 +76,7 @@ project/
76
76
  ├── .claude/
77
77
  │ ├── settings.json # Claude Code configuration
78
78
  │ └── commands/ # Custom slash commands
79
- ├── .env # API keys
79
+ ├── .env # Optional env vars
80
80
  ├── .mcp.json # MCP configuration
81
81
  └── CLAUDE.md # This file - auto-loaded by Claude Code
82
82
  ```
@@ -110,16 +110,7 @@ TaskGraph also provides an MCP server that Claude Code can connect to. It is opt
110
110
  "command": "npx",
111
111
  "args": ["-y", "taskgraph-ai"],
112
112
  "env": {
113
- "TASKGRAPH_TOOLS": "core",
114
- "ANTHROPIC_API_KEY": "your_key_here",
115
- "PERPLEXITY_API_KEY": "your_key_here",
116
- "OPENAI_API_KEY": "OPENAI_API_KEY_HERE",
117
- "GOOGLE_API_KEY": "GOOGLE_API_KEY_HERE",
118
- "XAI_API_KEY": "XAI_API_KEY_HERE",
119
- "OPENROUTER_API_KEY": "OPENROUTER_API_KEY_HERE",
120
- "MISTRAL_API_KEY": "MISTRAL_API_KEY_HERE",
121
- "AZURE_OPENAI_API_KEY": "AZURE_OPENAI_API_KEY_HERE",
122
- "OLLAMA_API_KEY": "OLLAMA_API_KEY_HERE"
113
+ "TASKGRAPH_TOOLS": "core"
123
114
  }
124
115
  }
125
116
  }
@@ -261,19 +252,9 @@ Add to `.claude/settings.json`:
261
252
 
262
253
  ## Configuration & Setup
263
254
 
264
- ### API Keys Required
255
+ ### Authentication
265
256
 
266
- At least **one** of these API keys must be configured:
267
-
268
- - `ANTHROPIC_API_KEY` (Claude models) - **Recommended**
269
- - `PERPLEXITY_API_KEY` (Research features) - **Highly recommended**
270
- - `OPENAI_API_KEY` (GPT models)
271
- - `GOOGLE_API_KEY` (Gemini models)
272
- - `MISTRAL_API_KEY` (Mistral models)
273
- - `OPENROUTER_API_KEY` (Multiple models)
274
- - `XAI_API_KEY` (Grok models)
275
-
276
- An API key is required for any provider used across any of the 3 roles defined in the `models` command.
257
+ TaskGraph runs every AI call through your signed-in Claude Code, so no provider API keys are needed. Run `claude` once to sign in. Optionally set `CLAUDE_CODE_API_KEY` to bill calls to a specific Anthropic API key.
277
258
 
278
259
  ### Model Configuration
279
260
 
@@ -282,9 +263,9 @@ An API key is required for any provider used across any of the 3 roles defined i
282
263
  taskgraph models --setup
283
264
 
284
265
  # Set specific models
285
- taskgraph models --set-main claude-sonnet-5-5
286
- taskgraph models --set-research perplexity-llama-3.1-sonar-large-128k-online
287
- taskgraph models --set-fallback gpt-4o-mini
266
+ taskgraph models --set-main sonnet
267
+ taskgraph models --set-research opus
268
+ taskgraph models --set-fallback haiku
288
269
  ```
289
270
 
290
271
  ## Task Structure & IDs
@@ -377,14 +358,14 @@ cd ../project-api && claude # Terminal 2: API work
377
358
  ### AI Commands Failing
378
359
 
379
360
  ```bash
380
- # Check API keys are configured
381
- cat .env # For CLI usage
361
+ # Make sure Claude Code is installed and signed in
362
+ claude --version
382
363
 
383
364
  # Verify model configuration
384
365
  taskgraph models
385
366
 
386
367
  # Test with different model
387
- taskgraph models --set-fallback gpt-4o-mini
368
+ taskgraph models --set-fallback haiku
388
369
  ```
389
370
 
390
371
  ### MCP Connection Issues (only if you use MCP)
@@ -444,7 +425,7 @@ These commands make AI calls and may take up to a minute:
444
425
  ### Research Mode
445
426
 
446
427
  - Add `--research` flag for research-based AI enhancement
447
- - Requires a research model API key like Perplexity (`PERPLEXITY_API_KEY`) in environment
428
+ - The research role has web search and fetch only; it cannot read or change your files
448
429
  - Provides more informed task creation and updates
449
430
  - Recommended for complex technical tasks
450
431
 
@@ -26,11 +26,8 @@ When using this template to **create** a PRD (not parse it), use **code-context-
26
26
 
27
27
  **Recommended tools:**
28
28
  - **Claude Code** (claude-code CLI) - Best for structured reasoning and large contexts
29
- - **Cursor/Windsurf** - IDE integration with full codebase context
30
- - **Gemini CLI** (gemini-cli) - Massive context window for large codebases
31
- - **Codex/Grok CLI** - Strong code generation with context awareness
32
29
 
33
- **Note:** Once your PRD is created, `taskgraph parse-prd` works with any configured AI model - it just needs to read the PRD text itself, not your codebase.
30
+ **Note:** Once your PRD is created, `taskgraph parse-prd` works with Claude Code - it just needs to read the PRD text itself, not your codebase.
34
31
  </rpg-method>
35
32
 
36
33
  ---
@@ -12,7 +12,7 @@ In an AI-driven development process—particularly with tools like [Cursor](http
12
12
  4. **Generate** individual task files (e.g., `task_001.txt`) for easy reference or to feed into an AI coding workflow.
13
13
  5. **Set task status**—mark tasks as `done`, `pending`, or `deferred` based on progress.
14
14
  6. **Expand** tasks with subtasks—break down complex tasks into smaller, more manageable subtasks.
15
- 7. **Research-backed subtask generation**—use Perplexity AI to generate more informed and contextually relevant subtasks.
15
+ 7. **Research-backed subtask generation**—use the research model to generate more informed and contextually relevant subtasks.
16
16
  8. **Clear subtasks**—remove subtasks from specified tasks to allow regeneration or restructuring.
17
17
  9. **Show task details**—display detailed information about a specific task and its subtasks.
18
18
 
@@ -26,10 +26,10 @@ TaskGraph configuration is now managed through two primary methods:
26
26
  - Managed using the `taskgraph models --setup` command or the `models` MCP tool.
27
27
  - This is the main configuration file for most settings.
28
28
 
29
- 2. **Environment Variables (`.env` File - API Keys Only)**
30
- - Used **only** for sensitive **API Keys** (e.g., `ANTHROPIC_API_KEY`, `PERPLEXITY_API_KEY`).
31
- - Create a `.env` file in your project root for CLI usage.
32
- - See `assets/env.example` for required key names.
29
+ 2. **Environment Variables (optional)**
30
+ - TaskGraph needs no provider API keys; AI calls run through your signed-in Claude Code.
31
+ - `CLAUDE_CODE_API_KEY` optionally bills calls to a specific Anthropic API key.
32
+ - See the Configuration page in the TaskGraph docs for the `TASKGRAPH_*` variables.
33
33
 
34
34
  **Important:** Settings like `MODEL`, `MAX_TOKENS`, `TEMPERATURE`, `TASKGRAPH_LOG_LEVEL`, etc., are **no longer set via `.env`**. Use `taskgraph models --setup` instead.
35
35
 
@@ -160,10 +160,10 @@ taskgraph expand --all
160
160
  # Force regeneration of subtasks for all pending tasks
161
161
  taskgraph expand --all --force
162
162
 
163
- # Use Perplexity AI for research-backed subtask generation
163
+ # Use the research model for research-backed subtask generation
164
164
  taskgraph expand --id=3 --research
165
165
 
166
- # Use Perplexity AI for research-backed generation on all pending tasks
166
+ # Use the research model for research-backed generation on all pending tasks
167
167
  taskgraph expand --all --research
168
168
  ```
169
169
 
@@ -192,11 +192,9 @@ Notes:
192
192
  ## AI Integration (Updated)
193
193
 
194
194
  - The script now uses a unified AI service layer (`ai-services-unified.js`).
195
- - Model selection (e.g., Claude vs. Perplexity for `--research`) is determined by the configuration in `.taskgraph/config.json` based on the requested `role` (`main` or `research`).
196
- - API keys are automatically resolved from your `.env` file (for CLI) or MCP session environment.
197
- - To use the research capabilities (e.g., `expand --research`), ensure you have:
198
- 1. Configured a model for the `research` role using `taskgraph models --setup` (Perplexity models are recommended).
199
- 2. Added the corresponding API key (e.g., `PERPLEXITY_API_KEY`) to your `.env` file.
195
+ - Model selection (for example `opus`, `sonnet` or `haiku`) is determined by the configuration in `.taskgraph/config.json` based on the requested `role` (`main` or `research`).
196
+ - No provider API keys are needed; calls run through your signed-in Claude Code.
197
+ - To use the research capabilities (for example `expand --research`), configure a model for the `research` role with `taskgraph models --setup`.
200
198
 
201
199
  ## Logging
202
200
 
@@ -317,13 +315,13 @@ taskgraph analyze-complexity --model=claude-3-opus-20240229
317
315
  # Set a custom complexity threshold (1-10)
318
316
  taskgraph analyze-complexity --threshold=6
319
317
 
320
- # Use Perplexity AI for research-backed complexity analysis
318
+ # Use the research model for research-backed complexity analysis
321
319
  taskgraph analyze-complexity --research
322
320
  ```
323
321
 
324
322
  Notes:
325
323
 
326
- - The command uses Claude to analyze each task's complexity (or Perplexity with --research flag)
324
+ - The command uses Claude to analyze each task's complexity (or the research model with the --research flag)
327
325
  - Tasks are scored on a scale of 1-10
328
326
  - Each task receives a recommended number of subtasks based on DEFAULT_SUBTASKS configuration
329
327
  - The default output path is `scripts/task-complexity-report.json`
@@ -1,4 +1,4 @@
1
- import"./ai-services-unified-C_rt4w5B.js";import"./src-DUT6aK7P.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,o as f,s as p,t as m,xt as h}from"./config-manager-ze5VncSH.js";import"./git-utils-CrYiSKu0.js";import{$ as ee,A as te,B as g,C as ne,D as re,E as _,F as v,G as ie,H as ae,J as oe,K as se,M as ce,N as le,O as y,P as ue,R as de,S as fe,U as b,V as pe,W as x,X as me,Y as he,Z as ge,_ as _e,b as S,c as C,ct as w,d as T,et as E,f 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,n as I,o as ve,ot as ye,p as L,q as be,r as xe,s as Se,st as Ce,t as we,u as Te,ut as Ee,v as R,x as De,y as Oe,z as ke}from"./dependency-manager-BPBdmQcF.js";import{t as Ae}from"./response-language-8XZaALbD.js";import{n as z,r as je,t as Me}from"./init-DE4mO3CM.js";import B from"chalk";import V from"path";import H from"fs";import U from"boxen";import{Command as Ne,Option as W}from"commander";import G from"inquirer";const K={AUTHENTICATION:`authentication`,VALIDATION:`validation`,NETWORK:`network`,API:`api`,FILE_SYSTEM:`file_system`,TASK:`task`,PERMISSION:`permission`,TIMEOUT:`timeout`,GENERIC:`generic`},q=[/\b[A-Za-z0-9_-]{20,}\b/g,/sk-[A-Za-z0-9]{32,}/g,/api[_-]?key[:\s=]+[^\s]+/gi,/bearer\s+[^\s]+/gi,/token[:\s=]+[^\s]+/gi,/\/Users\/[^/]+/g,/C:\\Users\\[^\\]+/g,/\/home\/[^/]+/g,/[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}/g,/https?:\/\/[^:]+:[^@]+@/g];function J(e){if(!e||typeof e!=`string`)return e;let t=e;for(let e of q)t=t.replace(e,`***REDACTED***`);return t}function Pe(e){if(!e)return K.GENERIC;let t=(e.message||``).toLowerCase(),n=(e.code||``).toLowerCase();return t.includes(`auth`)||t.includes(`unauthorized`)||t.includes(`forbidden`)||t.includes(`api key`)||t.includes(`token`)||n.includes(`auth`)?K.AUTHENTICATION:t.includes(`invalid`)||t.includes(`validation`)||t.includes(`required`)||t.includes(`must be`)||n.includes(`validation`)?K.VALIDATION:t.includes(`network`)||t.includes(`connection`)||t.includes(`econnrefused`)||t.includes(`enotfound`)||n.includes(`network`)||n.includes(`econnrefused`)||n.includes(`enotfound`)?K.NETWORK:t.includes(`timeout`)||t.includes(`timed out`)||n.includes(`timeout`)?K.TIMEOUT:t.includes(`api`)||t.includes(`rate limit`)||t.includes(`quota`)||n.includes(`api`)?K.API:t.includes(`enoent`)||t.includes(`eacces`)||t.includes(`file`)||t.includes(`directory`)||n.includes(`enoent`)||n.includes(`eacces`)?K.FILE_SYSTEM:t.includes(`permission`)||t.includes(`access denied`)||n.includes(`eperm`)?K.PERMISSION:t.includes(`task`)||t.includes(`subtask`)?K.TASK:K.GENERIC}function Fe(e,t,n){let r=[],i=(t.message||``).toLowerCase();switch(e){case K.AUTHENTICATION:i.includes(`api key`)?(r.push(`Check that your API key is correctly set in the .env file`),r.push(`Verify the API key has not expired or been revoked`)):i.includes(`token`)?(r.push(`Your authentication token may have expired`),r.push(`Check the provider key in your .env file`)):(r.push(`Verify your credentials are correctly configured`),r.push(`Check that the provider key is set in your .env file`));break;case K.VALIDATION:i.includes(`task id`)||i.includes(`invalid id`)?(r.push(`Task IDs should be numbers (e.g., 1, 2, 3)`),r.push(`Subtask IDs use dot notation (e.g., 1.1, 2.3)`)):(r.push(`Check that all required parameters are provided`),r.push(`Verify parameter values match expected formats`));break;case K.NETWORK:i.includes(`econnrefused`)?(r.push(`Could not connect to the server`),r.push(`Check your internet connection`),r.push(`Verify the API endpoint URL is correct`)):i.includes(`enotfound`)?(r.push(`Could not resolve the server hostname`),r.push(`Check your internet connection`)):(r.push(`Check your network connection`),r.push(`Verify firewall settings are not blocking the request`));break;case K.TIMEOUT:r.push(`The operation took too long to complete`),r.push(`Try again with a simpler request`),r.push(`Check your network speed and stability`);break;case K.API:i.includes(`rate limit`)?(r.push(`You have exceeded the API rate limit`),r.push(`Wait a few minutes before trying again`)):i.includes(`quota`)?(r.push(`You have reached your API quota`),r.push(`Check your account usage and limits`)):(r.push(`The API returned an error`),r.push(`Try again in a few moments`));break;case K.FILE_SYSTEM:i.includes(`enoent`)?(r.push(`The specified file or directory does not exist`),r.push(`Check the file path and ensure it is correct`),n.includes(`tasks.json`)&&r.push(`Initialize the project with: tm init`)):i.includes(`eacces`)?(r.push(`Permission denied to access the file`),r.push(`Check file permissions or run with appropriate privileges`)):r.push(`Check that the file or directory exists and is accessible`);break;case K.PERMISSION:r.push(`You do not have permission to perform this operation`),r.push(`Check file/directory permissions`),r.push(`You may need elevated privileges (sudo)`);break;case K.TASK:i.includes(`not found`)?(r.push(`The specified task does not exist`),r.push(`Use: tm list to see all available tasks`)):i.includes(`dependency`)||i.includes(`circular`)?(r.push(`Task dependencies form a circular reference`),r.push(`Use: tm validate-dependencies to identify issues`)):(r.push(`Check that the task ID is correct`),r.push(`Use: tm show <id> to view task details`));break;default:r.push(`Check the error message for specific details`),n&&r.push(`Operation failed while: ${n}`)}return r.slice(0,2)}function Ie(e,t={}){let{context:n=``,debug:r=!1,command:i=``}=t;typeof e==`string`&&(e=Error(e)),(!e||typeof e!=`object`)&&(e=Error(`An unknown error occurred`));let a=J(e.message||`Unknown error`),o=Pe(e),s=Fe(o,e,n);return{type:o,message:a,context:n||`Unknown operation`,hints:s,command:i||null,code:e.code||null,stack:r?J(e.stack):null}}function Y(e,t={}){let n=Ie(e,t),r=B.red.bold(`✗ Error
1
+ import"./ai-services-unified-CL8dbLYJ.js";import"./src-kk3jUMbL.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,o as f,s as p,t as m,xt as h}from"./config-manager-BTO7V7yI.js";import"./git-utils-CrYiSKu0.js";import{$ as ee,A as te,B as g,C as ne,D as re,E as _,F as v,G as ie,H as ae,J as oe,K as se,M as ce,N as le,O as y,P as ue,R as de,S as fe,U as b,V as pe,W as x,X as me,Y as he,Z as ge,_ as _e,b as S,c as C,ct as w,d as T,et as E,f 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,n as I,o as ve,ot as ye,p as L,q as be,r as xe,s as Se,st as Ce,t as we,u as Te,ut as Ee,v as R,x as De,y as Oe,z as ke}from"./dependency-manager-Mm62BpiN.js";import{t as Ae}from"./response-language-CAUwZ_BR.js";import{n as z,r as je,t as Me}from"./init-C75AhVRQ.js";import B from"chalk";import V from"path";import H from"fs";import U from"boxen";import{Command as Ne,Option as W}from"commander";import G from"inquirer";const K={AUTHENTICATION:`authentication`,VALIDATION:`validation`,NETWORK:`network`,API:`api`,FILE_SYSTEM:`file_system`,TASK:`task`,PERMISSION:`permission`,TIMEOUT:`timeout`,GENERIC:`generic`},q=[/\b[A-Za-z0-9_-]{20,}\b/g,/sk-[A-Za-z0-9]{32,}/g,/api[_-]?key[:\s=]+[^\s]+/gi,/bearer\s+[^\s]+/gi,/token[:\s=]+[^\s]+/gi,/\/Users\/[^/]+/g,/C:\\Users\\[^\\]+/g,/\/home\/[^/]+/g,/[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}/g,/https?:\/\/[^:]+:[^@]+@/g];function J(e){if(!e||typeof e!=`string`)return e;let t=e;for(let e of q)t=t.replace(e,`***REDACTED***`);return t}function Pe(e){if(!e)return K.GENERIC;let t=(e.message||``).toLowerCase(),n=(e.code||``).toLowerCase();return t.includes(`auth`)||t.includes(`unauthorized`)||t.includes(`forbidden`)||t.includes(`api key`)||t.includes(`token`)||n.includes(`auth`)?K.AUTHENTICATION:t.includes(`invalid`)||t.includes(`validation`)||t.includes(`required`)||t.includes(`must be`)||n.includes(`validation`)?K.VALIDATION:t.includes(`network`)||t.includes(`connection`)||t.includes(`econnrefused`)||t.includes(`enotfound`)||n.includes(`network`)||n.includes(`econnrefused`)||n.includes(`enotfound`)?K.NETWORK:t.includes(`timeout`)||t.includes(`timed out`)||n.includes(`timeout`)?K.TIMEOUT:t.includes(`api`)||t.includes(`rate limit`)||t.includes(`quota`)||n.includes(`api`)?K.API:t.includes(`enoent`)||t.includes(`eacces`)||t.includes(`file`)||t.includes(`directory`)||n.includes(`enoent`)||n.includes(`eacces`)?K.FILE_SYSTEM:t.includes(`permission`)||t.includes(`access denied`)||n.includes(`eperm`)?K.PERMISSION:t.includes(`task`)||t.includes(`subtask`)?K.TASK:K.GENERIC}function Fe(e,t,n){let r=[],i=(t.message||``).toLowerCase();switch(e){case K.AUTHENTICATION:i.includes(`api key`)?(r.push(`Check that your API key is correctly set in the .env file`),r.push(`Verify the API key has not expired or been revoked`)):i.includes(`token`)?(r.push(`Your authentication token may have expired`),r.push(`Check the provider key in your .env file`)):(r.push(`Verify your credentials are correctly configured`),r.push(`Check that the provider key is set in your .env file`));break;case K.VALIDATION:i.includes(`task id`)||i.includes(`invalid id`)?(r.push(`Task IDs should be numbers (e.g., 1, 2, 3)`),r.push(`Subtask IDs use dot notation (e.g., 1.1, 2.3)`)):(r.push(`Check that all required parameters are provided`),r.push(`Verify parameter values match expected formats`));break;case K.NETWORK:i.includes(`econnrefused`)?(r.push(`Could not connect to the server`),r.push(`Check your internet connection`),r.push(`Verify the API endpoint URL is correct`)):i.includes(`enotfound`)?(r.push(`Could not resolve the server hostname`),r.push(`Check your internet connection`)):(r.push(`Check your network connection`),r.push(`Verify firewall settings are not blocking the request`));break;case K.TIMEOUT:r.push(`The operation took too long to complete`),r.push(`Try again with a simpler request`),r.push(`Check your network speed and stability`);break;case K.API:i.includes(`rate limit`)?(r.push(`You have exceeded the API rate limit`),r.push(`Wait a few minutes before trying again`)):i.includes(`quota`)?(r.push(`You have reached your API quota`),r.push(`Check your account usage and limits`)):(r.push(`The API returned an error`),r.push(`Try again in a few moments`));break;case K.FILE_SYSTEM:i.includes(`enoent`)?(r.push(`The specified file or directory does not exist`),r.push(`Check the file path and ensure it is correct`),n.includes(`tasks.json`)&&r.push(`Initialize the project with: tm init`)):i.includes(`eacces`)?(r.push(`Permission denied to access the file`),r.push(`Check file permissions or run with appropriate privileges`)):r.push(`Check that the file or directory exists and is accessible`);break;case K.PERMISSION:r.push(`You do not have permission to perform this operation`),r.push(`Check file/directory permissions`),r.push(`You may need elevated privileges (sudo)`);break;case K.TASK:i.includes(`not found`)?(r.push(`The specified task does not exist`),r.push(`Use: tm list to see all available tasks`)):i.includes(`dependency`)||i.includes(`circular`)?(r.push(`Task dependencies form a circular reference`),r.push(`Use: tm validate-dependencies to identify issues`)):(r.push(`Check that the task ID is correct`),r.push(`Use: tm show <id> to view task details`));break;default:r.push(`Check the error message for specific details`),n&&r.push(`Operation failed while: ${n}`)}return r.slice(0,2)}function Ie(e,t={}){let{context:n=``,debug:r=!1,command:i=``}=t;typeof e==`string`&&(e=Error(e)),(!e||typeof e!=`object`)&&(e=Error(`An unknown error occurred`));let a=J(e.message||`Unknown error`),o=Pe(e),s=Fe(o,e,n);return{type:o,message:a,context:n||`Unknown operation`,hints:s,command:i||null,code:e.code||null,stack:r?J(e.stack):null}}function Y(e,t={}){let n=Ie(e,t),r=B.red.bold(`✗ Error
2
2
 
3
3
  `);r+=h.text(n.message)+`
4
4
 
@@ -29,7 +29,7 @@ Subtask update was not completed. Review the messages above for details.`))}catc
29
29
  To fix this issue:`)),console.log(` 1. Run taskgraph list --with-subtasks to see all available subtask IDs`),console.log(` 2. Use a valid subtask ID with the --id parameter in format "parentId.subtaskId"`)):e.message.includes(`API key`)&&console.log(B.yellow(`
30
30
  This error is related to API keys. Check your environment variables.`)),f()&&console.error(e),process.exit(1)}}),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=X({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});y(e.strength)||(console.error(B.red(`Error: Invalid strength level: ${e.strength}. Must be one of: light, regular, heavy`)),process.exit(1)),H.existsSync(n)||(console.error(B.red(`Error: Tasks file not found at path: ${n}`)),process.exit(1)),console.log(h.brand(`Scoping up ${i.length} task(s): ${i.join(`, `)}`)),console.log(h.brand(`Strength level: ${e.strength}`)),e.prompt&&console.log(h.brand(`Custom instructions: ${e.prompt}`));let a={projectRoot:t.getProjectRoot(),tag:r,commandName:`scope-up`,outputType:`cli`,research:e.research||!1},o=await re(n,i,e.strength,e.prompt||null,a,`text`);console.log(B.green(`✅ Successfully scoped up ${o.updatedTasks.length} task(s)`))}catch(e){console.error(B.red(`Error: ${e.message}`)),e.message.includes(`not found`)&&(console.log(B.yellow(`
31
31
  To fix this issue:`)),console.log(` 1. Run taskgraph list to see all available task IDs`),console.log(` 2. Use valid task IDs with the --id parameter`)),f()&&console.error(e),process.exit(1)}}),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=X({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});y(e.strength)||(console.error(B.red(`Error: Invalid strength level: ${e.strength}. Must be one of: light, regular, heavy`)),process.exit(1)),H.existsSync(n)||(console.error(B.red(`Error: Tasks file not found at path: ${n}`)),process.exit(1)),console.log(h.brand(`Scoping down ${i.length} task(s): ${i.join(`, `)}`)),console.log(h.brand(`Strength level: ${e.strength}`)),e.prompt&&console.log(h.brand(`Custom instructions: ${e.prompt}`));let a={projectRoot:t.getProjectRoot(),tag:r,commandName:`scope-down`,outputType:`cli`,research:e.research||!1},o=await _(n,i,e.strength,e.prompt||null,a,`text`);console.log(B.green(`✅ Successfully scoped down ${o.updatedTasks.length} task(s)`))}catch(e){console.error(B.red(`Error: ${e.message}`)),e.message.includes(`not found`)&&(console.log(B.yellow(`
32
- To fix this issue:`)),console.log(` 1. Run taskgraph list to see all available task IDs`),console.log(` 2. Use valid task IDs with the --id parameter`)),f()&&console.error(e),process.exit(1)}}),he(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(`-cr, --complexity-report <file>`,`Path to the complexity report file (use this to specify the complexity report, not --file)`).option(`--tag <tag>`,`Specify tag context for task operations`).action(async t=>{let n={tasksPath:t.file||!0,tag:t.tag};t.complexityReport&&(n.complexityReportPath=t.complexityReport);let r=X(n),i=r.getCurrentTag();if(await T(i),t.all){console.log(h.brand(`Expanding all pending tasks...`));try{await de(r.getTasksPath(),t.num,t.research,t.prompt,t.force,{projectRoot:r.getProjectRoot(),tag:i,complexityReportPath:r.getComplexityReportPath()})}catch(e){console.error(B.red(`Error expanding all tasks: ${e.message}`)),process.exit(1)}}else if(t.id){t.id||(console.error(B.red(`Error: Task ID is required unless using --all.`)),process.exit(1)),console.log(h.brand(`Expanding task ${t.id}...`));try{await ke(r.getTasksPath(),t.id,t.num,t.research,t.prompt,{projectRoot:r.getProjectRoot(),tag:i,complexityReportPath:r.getComplexityReportPath()},t.force)}catch(e){console.error(B.red(`Error expanding task ${t.id}: ${e.message}`)),process.exit(1)}}else console.error(B.red(`Error: You must specify either a task ID (--id) or --all.`)),e.help()}),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=X(t);e.model,parseFloat(e.threshold);let r=e.research||!1,i=n.getCurrentTag();await T(i);let a=n.getComplexityReportPath();if(console.log(h.brand(`Analyzing task complexity from: ${n.getTasksPath()}`)),console.log(h.brand(`Output report will be saved to: ${a}`)),e.id)console.log(h.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(h.brand(`Analyzing tasks in range: ${t} to ${n}`))}r&&console.log(h.brand(`Using Claude Code web research for research-backed complexity analysis`)),await pe({...e,output:a,tag:i,projectRoot:n.getProjectRoot(),file:n.getTasksPath()})}),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=X({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`)),x(),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);H.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(h.brand(`Researching: "${s.prompt}"`)),s.taskIds.length>0&&console.log(h.muted(`Task context: ${s.taskIds.join(`, `)}`)),s.filePaths.length>0&&console.log(h.muted(`File context: ${s.filePaths.join(`, `)}`)),s.customContext&&console.log(h.muted(`Custom context: ${s.customContext.substring(0,50)}${s.customContext.length>50?`...`:``}`)),s.includeProjectTree&&console.log(h.muted(`Including project file tree`)),console.log(h.muted(`Detail level: ${s.detailLevel}`));try{let{performResearch:e}=await import(`./research-CC0KE46z.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}
32
+ To fix this issue:`)),console.log(` 1. Run taskgraph list to see all available task IDs`),console.log(` 2. Use valid task IDs with the --id parameter`)),f()&&console.error(e),process.exit(1)}}),he(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(`-cr, --complexity-report <file>`,`Path to the complexity report file (use this to specify the complexity report, not --file)`).option(`--tag <tag>`,`Specify tag context for task operations`).action(async t=>{let n={tasksPath:t.file||!0,tag:t.tag};t.complexityReport&&(n.complexityReportPath=t.complexityReport);let r=X(n),i=r.getCurrentTag();if(await T(i),t.all){console.log(h.brand(`Expanding all pending tasks...`));try{await de(r.getTasksPath(),t.num,t.research,t.prompt,t.force,{projectRoot:r.getProjectRoot(),tag:i,complexityReportPath:r.getComplexityReportPath()})}catch(e){console.error(B.red(`Error expanding all tasks: ${e.message}`)),process.exit(1)}}else if(t.id){t.id||(console.error(B.red(`Error: Task ID is required unless using --all.`)),process.exit(1)),console.log(h.brand(`Expanding task ${t.id}...`));try{await ke(r.getTasksPath(),t.id,t.num,t.research,t.prompt,{projectRoot:r.getProjectRoot(),tag:i,complexityReportPath:r.getComplexityReportPath()},t.force)}catch(e){console.error(B.red(`Error expanding task ${t.id}: ${e.message}`)),process.exit(1)}}else console.error(B.red(`Error: You must specify either a task ID (--id) or --all.`)),e.help()}),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=X(t);e.model,parseFloat(e.threshold);let r=e.research||!1,i=n.getCurrentTag();await T(i);let a=n.getComplexityReportPath();if(console.log(h.brand(`Analyzing task complexity from: ${n.getTasksPath()}`)),console.log(h.brand(`Output report will be saved to: ${a}`)),e.id)console.log(h.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(h.brand(`Analyzing tasks in range: ${t} to ${n}`))}r&&console.log(h.brand(`Using Claude Code web research for research-backed complexity analysis`)),await pe({...e,output:a,tag:i,projectRoot:n.getProjectRoot(),file:n.getTasksPath()})}),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=X({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`)),x(),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);H.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(h.brand(`Researching: "${s.prompt}"`)),s.taskIds.length>0&&console.log(h.muted(`Task context: ${s.taskIds.join(`, `)}`)),s.filePaths.length>0&&console.log(h.muted(`File context: ${s.filePaths.join(`, `)}`)),s.customContext&&console.log(h.muted(`Custom context: ${s.customContext.substring(0,50)}${s.customContext.length>50?`...`:``}`)),s.includeProjectTree&&console.log(h.muted(`Including project file tree`)),console.log(h.muted(`Detail level: ${s.detailLevel}`));try{let{performResearch:e}=await import(`./research-ZJOfL6U9.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}
33
33
 
34
34
  **Detail Level:** ${r.detailLevel}
35
35
  **Context Size:** ${r.contextSize} characters
@@ -37,7 +37,7 @@ To fix this issue:`)),console.log(` 1. Run taskgraph list to see all available
37
37
 
38
38
  ### Results
39
39
 
40
- ${r.result}`;if(e){let{updateSubtaskById:e}=await import(`./update-subtask-by-id-Dv7PlU5v.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-Dzn7ZNbs.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}
40
+ ${r.result}`;if(e){let{updateSubtaskById:e}=await import(`./update-subtask-by-id-usEluJxs.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-BDHadCwU.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}
41
41
 
42
42
  **Detail Level:** ${r.detailLevel}
43
43
  **Context Size:** ${r.contextSize} characters
@@ -207,14 +207,14 @@ Note: Some tasks were moved successfully. Check the errors above for failed move
207
207
  `+h.text(` • Choose a different target tag without conflicting IDs`)+`
208
208
  `+h.text(` • Move a different set of IDs (avoid existing ones)`)+`
209
209
  `+h.text(` • If needed, move within-tag to a new ID first, then cross-tag move`)),process.exit(1)),i(e,m)}}),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=X({tasksPath:e.file||!0,tag:e.tag}),n=e.withSubtasks||!1,r=e.status||null,i=t.getCurrentTag();console.log(h.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(h.muted(` This command will be removed in a future version.
210
- `));try{let n=X({tasksPath:t.file||!0}),r=n.getTasksPath();H.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-neogW4lA.js`),r=await import(`./git-utils-BFUgMf2g.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 ge(n.getTasksPath(),e,r,i,`text`)}if(t.autoSwitch){let{useTag:r}=await import(`./tag-management-neogW4lA.js`),a=t.fromBranch?(await import(`./git-utils-BFUgMf2g.js`)).sanitizeBranchNameForTag(await(await import(`./git-utils-BFUgMf2g.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(h.muted(` This command will be removed in a future version.
210
+ `));try{let n=X({tasksPath:t.file||!0}),r=n.getTasksPath();H.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-upzMTb_q.js`),r=await import(`./git-utils-BFUgMf2g.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 ge(n.getTasksPath(),e,r,i,`text`)}if(t.autoSwitch){let{useTag:r}=await import(`./tag-management-upzMTb_q.js`),a=t.fromBranch?(await import(`./git-utils-BFUgMf2g.js`)).sanitizeBranchNameForTag(await(await import(`./git-utils-BFUgMf2g.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(h.muted(` This command will be removed in a future version.
211
211
  `));try{let n=X({tasksPath:t.file||!0}),r=n.getTasksPath();H.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 ee(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: "tm use-tag" is deprecated. Use "tm tags use" instead.`)),console.log(h.muted(` This command will be removed in a future version.
212
212
  `));try{let n=X({tasksPath:t.file||!0}),r=n.getTasksPath();H.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){console.error(B.red(`Error switching tag: ${e.message}`)),m(),process.exit(1)}}).on(`error`,function(e){console.error(B.red(`Error: ${e.message}`)),m(),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(h.muted(` This command will be removed in a future version.
213
213
  `));try{let r=X({tasksPath:n.file||!0}),i=r.getTasksPath();H.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(h.muted(` This command will be removed in a future version.
214
214
  `));try{let r=X({tasksPath:n.file||!0}),i=r.getTasksPath();H.existsSync(i)||(console.error(B.red(`Error: Tasks file not found at path: ${i}`)),process.exit(1)),await me(i,e,t,{description:n.description},{projectRoot:r.getProjectRoot(),commandName:`copy-tag`,outputType:`cli`},`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 Q()}),e}async function ze(){return null}async function Q(){let e=await ze();if(!e){console.log(B.yellow(`TUI mode coming soon!`)),console.log(B.dim(`Showing help instead...
215
215
  `)),L();return}let t=await import(`react`),{render:n,Shell:r}=e,i=`master`,a=process.cwd();try{let e=X({});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(`
216
216
  Goodbye! 👋`)),process.exit(0)}},c=n(t.createElement(r,s));o||setTimeout(()=>{c.unmount(),console.log(B.dim(`
217
- 💡 Run in an interactive terminal for full REPL mode.`)),process.exit(0)},200)}function $(){let e=new Ne().name(`taskgraph`).description(`AI-driven development task management`).version(`0.52.3`).helpOption(`-h, --help`,`Display help`).addHelpCommand(!1),t=e.helpInformation.bind(e);return e.helpInformation=function(){return this.parent&&this.parent!==e?t():(L(),``)},Z(e),e}async function Be(e=process.argv){try{if(e.length<=2){await Q();return}let t=e.includes(`init`),n=e.includes(`tui`)||e.includes(`repl`),r=e.includes(`--no-banner`);process.stdout.isTTY&&!t&&!n&&!r&&Se();let i=process.env.TASKGRAPH_SKIP_AUTO_UPDATE===`1`||process.env.CI||process.env.NODE_ENV===`test`,a=x(),o=i?{currentVersion:a,latestVersion:a,needsUpdate:!1}:await P(a);if(o.needsUpdate&&(w(o.currentVersion,o.latestVersion,o.highlights),await Ce(o.latestVersion))){ye(e);return}let s=$(),c=e.filter(e=>e!==`--no-banner`);await s.parseAsync(c);try{let e=X({}),t=e.getTasksPath(),n=e.getStatePath();if(t&&H.existsSync(t)){let e=H.readFileSync(t,`utf8`),r=JSON.parse(e);if(r&&r.master){let e={migrationNoticeShown:!1};if(n&&H.existsSync(n)){let t=H.readFileSync(n,`utf8`);e=JSON.parse(t)||e}e.migrationNoticeShown||(_e({_migrationHappened:!0}),e.migrationNoticeShown=!0,n&&H.writeFileSync(n,JSON.stringify(e,null,2)))}}}catch{}}catch(e){e instanceof m?console.error(U(B.red.bold(`Configuration Update Required!`)+`
217
+ 💡 Run in an interactive terminal for full REPL mode.`)),process.exit(0)},200)}function $(){let e=new Ne().name(`taskgraph`).description(`AI-driven development task management`).version(`0.52.4`).helpOption(`-h, --help`,`Display help`).addHelpCommand(!1),t=e.helpInformation.bind(e);return e.helpInformation=function(){return this.parent&&this.parent!==e?t():(L(),``)},Z(e),e}async function Be(e=process.argv){try{if(e.length<=2){await Q();return}let t=e.includes(`init`),n=e.includes(`tui`)||e.includes(`repl`),r=e.includes(`--no-banner`);process.stdout.isTTY&&!t&&!n&&!r&&Se();let i=process.env.TASKGRAPH_SKIP_AUTO_UPDATE===`1`||process.env.CI||process.env.NODE_ENV===`test`,a=x(),o=i?{currentVersion:a,latestVersion:a,needsUpdate:!1}:await P(a);if(o.needsUpdate&&(w(o.currentVersion,o.latestVersion,o.highlights),await Ce(o.latestVersion))){ye(e);return}let s=$(),c=e.filter(e=>e!==`--no-banner`);await s.parseAsync(c);try{let e=X({}),t=e.getTasksPath(),n=e.getStatePath();if(t&&H.existsSync(t)){let e=H.readFileSync(t,`utf8`),r=JSON.parse(e);if(r&&r.master){let e={migrationNoticeShown:!1};if(n&&H.existsSync(n)){let t=H.readFileSync(n,`utf8`);e=JSON.parse(t)||e}e.migrationNoticeShown||(_e({_migrationHappened:!0}),e.migrationNoticeShown=!0,n&&H.writeFileSync(n,JSON.stringify(e,null,2)))}}}catch{}}catch(e){e instanceof m?console.error(U(B.red.bold(`Configuration Update Required!`)+`
218
218
 
219
219
  `+h.text(`TaskGraph now uses a `)+B.yellow.bold(`configuration file`)+h.text(` in your project for AI model choices and settings.
220
220
 
@@ -1 +1 @@
1
- import{_ as e,d as t,u as n,v as r}from"./src-DUT6aK7P.js";import{t as i}from"./git-utils-CrYiSKu0.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`,re=`.taskgraph/reports/task-complexity-report.json`,ie=`.taskgraph/docs/prd.txt`,ae=`.taskgraph/templates/example_prd.txt`,oe=`.taskgraph/tasks/tasks.json`,se=`.env.example`,ce=`.gitignore`,g={primary:`#0088CC`,accent:`#0096C7`,deep:`#0080C0`},le=[g.accent,g.primary,g.deep],ue=g.accent,de=[`dim`],fe={dimBorder:!0},_={brand:a.cyan,heading:a.cyan.bold,accent:a.magenta,active:a.cyan.bold,muted:a.dim,text:a};let v=!1;const pe={maxRetries:5,retryDelay:100,staleLockAge:1e4};function me(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 y(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}=pe,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&&me(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){w(`warn`,`Failed to release lock for ${e}: ${t.message}`)}}}function b(e,t=null,n=null){if(t?.env?.[e])return t.env[e];if(n){let t=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){w(`warn`,`Could not read or parse ${t}: ${e.message}`)}}if(process.env[e])return process.env[e]}function x(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 S={debug:0,info:1,warn:2,error:3,success:1};function he(){v=!0}function ge(){v=!1}function C(){return v}function w(e,...t){if(C())return;let n=`info`;try{n=qe()||`info`}catch{n=`info`}let r={debug:_.muted(`[DEBUG]`),info:_.brand(`[INFO]`),warn:a.yellow(`[WARN]`),error:a.red(`[ERROR]`),success:a.green(`[SUCCESS]`)},i=S.hasOwnProperty(e)?e:`info`;if(S[i]>=(S[n]??S.info)){let e=r[i]||``,n=t.map(e=>typeof e==`object`?JSON.stringify(e):e).join(` `);console.log(`${e} ${n}`)}}function T(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 E(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 D(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){return r&&console.log(`Failed to read JSON from ${e}: ${t.message}`),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&&!T(a)){r&&console.log(`File is in legacy format, performing migration...`),E(a.tasks);let n={master:{tasks:a.tasks,metadata:a.metadata||{created:new Date().toISOString(),updated:new Date().toISOString(),description:`Tasks for master context`}}};try{if(M(e,n),r&&console.log(`Successfully migrated legacy format to tagged format`),O(e),t)try{i(t,e)}catch{}j(e)}catch(e){r&&console.log(`Error writing migrated data: ${e.message}`)}a=n}if(typeof a==`object`&&!a.tasks){for(let e in r&&console.log(`File is in tagged format, resolving tag...`),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)&&E(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=x(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){E(c.tasks);let e={...c,tag:i,_rawTaggedData:s};return r&&console.log(`Returning data for tag '${i}' with ${c.tasks.length} tasks`),e}else{let e=a.master;return e&&e.tasks?(E(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?(E(t.tasks),{...t,_rawTaggedData:s}):{tasks:[],_rawTaggedData:s}}}return r&&console.log(`File format not recognized, returning as-is`),a}function O(e){try{let t=x(o.dirname(e))||o.dirname(e),n=o.join(t,`.taskgraph`,`config.json`);l.existsSync(n)&&k(n);let r=o.join(t,`.taskgraph`,`state.json`);l.existsSync(r)||A(r),Q()&&w(`debug`,`Complete tag migration performed for project: ${t}`)}catch(e){Q()&&w(`warn`,`Error during complete tag migration: ${e.message}`)}}function k(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 A(e){try{let t={currentTag:`master`,lastSwitched: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 j(e){try{let t=o.dirname(o.dirname(e)),n=o.join(t,`.taskgraph`,`state.json`);l.existsSync(n)||A(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 M(e,t,n=null,r=null){let i=process.env.TASKGRAPH_DEBUG===`true`;try{y(e,()=>{let a=t;if(t&&!t._rawTaggedData&&n&&Array.isArray(t.tasks)&&!T(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 w(`error`,`Error writing JSON file ${e}:`,t.message),i&&w(`error`,`Full error details:`,t),t}}function _e(e=null){let t=!1;try{t=Q()}catch{t=!1}try{let n;if(n=e||o.join(process.cwd(),re),!l.existsSync(n))return t&&w(`debug`,`Complexity report not found at ${n}`),null;let r=D(n);return t&&w(`debug`,`Successfully read complexity report from ${n}`),r}catch(e){return t&&w(`error`,`Error reading complexity report: ${e.message}`),null}}function ve(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=ve(t,n);r&&(e.complexityScore=r.complexityScore)}function ye(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 be(e){return typeof e==`string`&&e.includes(`.`)?e:typeof e==`number`?e.toString():e}function xe(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 Se(e,t){return!e||e.length<=t?e:`${e.slice(0,t-3)}...`}function Ce(e){return Array.isArray(e)?e.length===0:typeof e==`object`&&e?Object.keys(e).length===0:!1}function we(e,t,n=new Set,r=new Set,i=[]){n.add(e),r.add(e),i.push(e);let a=[],o=t.get(e)||[];for(let e of o)if(n.has(e)){if(r.has(e)){let t=i.indexOf(e);i.slice(t),a.push(e)}}else{let o=we(e,t,n,r,[...i]);a.push(...o)}return r.delete(e),a}function Te(e,t,n={}){let{maxDepth:r=50,includeSelf:i=!1,direction:a=`forward`,logger:o=null}=n,s=new Set,c=new Set;function l(e){if(typeof e==`string`){if(e.includes(`.`))return e;let t=parseInt(e,10);return isNaN(t)?e:t}return e}function u(e,n=0){if(n>=r){let t=`Maximum recursion depth (${r}) reached for task ${e}`;o&&typeof o.warn==`function`?o.warn(t):w!==void 0&&w.warn?w.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):w!==void 0&&w.warn?w.warn(t):console.warn(t);return}c.has(e)||(c.add(e),t.forEach(t=>{if(t.dependencies&&Array.isArray(t.dependencies)&&t.dependencies.some(t=>l(t)===e)){if(t.id==null||!i&&t.id===e)return;s.add(t.id),d(t.id,n+1)}}))}let f=a===`reverse`?d:u;return e.forEach(e=>{e&&e.id&&f(e.id)}),Array.from(s)}function Ee(e,t){if(!e||e.length===0)return null;let n={timestamp:new Date().toISOString(),userId:e[0].userId,commandName:t,modelUsed:`Multiple`,providerName:`Multiple`,inputTokens:0,outputTokens:0,totalTokens:0,totalCost:0,currency:e[0].currency||`USD`},r=new Set,i=new Set,a=new Set;return e.forEach(e=>{n.inputTokens+=e.inputTokens||0,n.outputTokens+=e.outputTokens||0,n.totalCost+=e.totalCost||0,r.add(e.modelUsed),i.add(e.providerName),a.add(e.currency||`USD`)}),n.totalTokens=n.inputTokens+n.outputTokens,n.totalCost=parseFloat(n.totalCost.toFixed(6)),r.size===1&&(n.modelUsed=[...r][0]),i.size===1&&(n.providerName=[...i][0]),a.size>1?n.currency=`Multiple`:a.size===1&&(n.currency=[...a][0]),n}function 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 De(e,t){return!e||!t?[]:e[t]&&e[t].tasks&&Array.isArray(e[t].tasks)?e[t].tasks:[]}function Oe(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=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 ke(){return{info:(e,...t)=>w(`info`,e,...t),warn:(e,...t)=>w(`warn`,e,...t),error:(e,...t)=>w(`error`,e,...t),debug:(e,...t)=>w(`debug`,e,...t),success:(e,...t)=>w(`success`,e,...t)}}function L(e=null){return e||ke()}function R(e){return t(e)}function z(e=process.cwd()){return n(e)}function Ae(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,oe);return l.existsSync(s)?(r.info?.(`Found tasks file at: ${s}`),s):(r.warn?.(`No tasks.json found in project: ${a}`),null)}function je(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 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 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 Ne(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=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 Pe=u(import.meta.url);o.dirname(Pe);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 Fe=class extends Error{constructor(e){super(e),this.name=`ConfigurationError`}};function Ie(e=null){let t=H,n=e;e&&`${e}`,n||(n=x(),n||=process.cwd(),`${n}`);let r=null,i={...t};if(l.existsSync(o.join(n,f))&&(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&&!Ce(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,f))&&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=Ie(e);return(t||e)&&(U=n,W=e),n}return U}function q(e){return!!r.includes(e)}function Le(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 Re(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]||(w(`warn`,`No model configuration found for role: ${e}. Returning default.`),H.models[e]||{})}function ze(e=null){return X(`main`,e).provider}function Be(e=null){return X(`main`,e).modelId}function Ve(e=null){return X(`research`,e).provider}function He(e=null,t=null){let n=b(`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 Ue(t=!1,n=null,r=null){return!He(r,n)||t?!1:(t?Ve(n):ze(n))===e.CLAUDE_CODE}function We(e=null){return X(`research`,e).modelId}function Ge(e=null){return X(`fallback`,e).provider}function Ke(e=null){return X(`fallback`,e).modelId}function Z(e=null){let t=K(e);return{...H.global,...t?.global||{}}}function qe(e=null){return Z(e).logLevel.toLowerCase()}function Q(e=null){return Z(e).debug===!0}function Je(e=null){let t=Z(e).defaultSubtasks,n=parseInt(t,10);return Number.isNaN(n)?H.global.defaultSubtasks:n}function Ye(e=null){let t=Z(e).defaultNumTasks,n=parseInt(t,10);return Number.isNaN(n)?H.global.defaultNumTasks:n}function Xe(e=null){return Z(e).defaultPriority}function Ze(e=null){return Z(e).projectName}function Qe(e=null){return Z(e).responseLanguage}function $e(e=null){return Z(e).enableProxy===!0}function et(e=null,t=null){let n=b(`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 $e(t)}function tt(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),w(`debug`,`Applying model-specific max_tokens (${e}) for ${a}. Effective limit: ${s}`)}else w(`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,w(`debug`,`Applying model-specific temperature (${t.temperature}) for ${a}`))}else w(`debug`,`No model definitions found for provider ${o} in MODEL_MAP. Using role default maxTokens: ${r}`)}catch(e){w(`warn`,`Error looking up model-specific parameters for ${a}: ${e.message}. Using role defaults.`),s=r,c=i}return{maxTokens:s,temperature:c}}function nt(){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=x();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 rt(e=null){return B(null,{projectRoot:e})!==null}function it(e=null){let t=K(e);return t.global||={},t.global.userId||(t.global.userId=`1234567890`,$(t,e)||w(`warning`,`Failed to write updated configuration with new userId. Please let the developers know.`)),t.global.userId}export{De as $,$ as A,m as At,N as B,Ue as C,se as Ct,et as D,h as Dt,G as E,ie as Et,z as F,I as G,A as H,Ae as I,xe as J,we as K,R as L,Me as M,ee as Mt,B as N,oe as Nt,J as O,f as Ot,je as P,te as Pt,P as Q,Ne as R,it as S,re as St,rt as T,ce as Tt,ge as U,Ee as V,he as W,Oe as X,ve as Y,be as Z,$e as _,ue as _t,K as a,E as at,Qe as b,de as bt,Xe as c,D as ct,Ge as d,ye as dt,Ce as et,qe as f,Te as ft,Ze as g,le as gt,tt as h,M as ht,Re as i,k as it,V as j,ne as jt,q as k,p as kt,Je as l,b as lt,ze as m,y as mt,nt as n,w as nt,Q as o,O as ot,Be as p,Se as pt,x as q,Y as r,j as rt,Ye as s,_e as st,Fe as t,C as tt,Ke as u,F as ut,We as v,g as vt,He as w,ae as wt,Le as x,_ as xt,Ve as y,fe as yt,S as z};
1
+ import{_ as e,d as t,u as n,v as r}from"./src-kk3jUMbL.js";import{t as i}from"./git-utils-CrYiSKu0.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`,re=`.taskgraph/reports/task-complexity-report.json`,ie=`.taskgraph/docs/prd.txt`,ae=`.taskgraph/templates/example_prd.txt`,oe=`.taskgraph/tasks/tasks.json`,se=`.env.example`,ce=`.gitignore`,g={primary:`#0088CC`,accent:`#0096C7`,deep:`#0080C0`},le=[g.accent,g.primary,g.deep],ue=g.accent,de=[`dim`],fe={dimBorder:!0},_={brand:a.cyan,heading:a.cyan.bold,accent:a.magenta,active:a.cyan.bold,muted:a.dim,text:a};let v=!1;const pe={maxRetries:5,retryDelay:100,staleLockAge:1e4};function me(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 y(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}=pe,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&&me(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){w(`warn`,`Failed to release lock for ${e}: ${t.message}`)}}}function b(e,t=null,n=null){if(t?.env?.[e])return t.env[e];if(n){let t=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){w(`warn`,`Could not read or parse ${t}: ${e.message}`)}}if(process.env[e])return process.env[e]}function x(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 S={debug:0,info:1,warn:2,error:3,success:1};function he(){v=!0}function ge(){v=!1}function C(){return v}function w(e,...t){if(C())return;let n=`info`;try{n=qe()||`info`}catch{n=`info`}let r={debug:_.muted(`[DEBUG]`),info:_.brand(`[INFO]`),warn:a.yellow(`[WARN]`),error:a.red(`[ERROR]`),success:a.green(`[SUCCESS]`)},i=S.hasOwnProperty(e)?e:`info`;if(S[i]>=(S[n]??S.info)){let e=r[i]||``,n=t.map(e=>typeof e==`object`?JSON.stringify(e):e).join(` `);console.log(`${e} ${n}`)}}function T(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 E(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 D(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){return r&&console.log(`Failed to read JSON from ${e}: ${t.message}`),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&&!T(a)){r&&console.log(`File is in legacy format, performing migration...`),E(a.tasks);let n={master:{tasks:a.tasks,metadata:a.metadata||{created:new Date().toISOString(),updated:new Date().toISOString(),description:`Tasks for master context`}}};try{if(M(e,n),r&&console.log(`Successfully migrated legacy format to tagged format`),O(e),t)try{i(t,e)}catch{}j(e)}catch(e){r&&console.log(`Error writing migrated data: ${e.message}`)}a=n}if(typeof a==`object`&&!a.tasks){for(let e in r&&console.log(`File is in tagged format, resolving tag...`),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)&&E(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=x(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){E(c.tasks);let e={...c,tag:i,_rawTaggedData:s};return r&&console.log(`Returning data for tag '${i}' with ${c.tasks.length} tasks`),e}else{let e=a.master;return e&&e.tasks?(E(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?(E(t.tasks),{...t,_rawTaggedData:s}):{tasks:[],_rawTaggedData:s}}}return r&&console.log(`File format not recognized, returning as-is`),a}function O(e){try{let t=x(o.dirname(e))||o.dirname(e),n=o.join(t,`.taskgraph`,`config.json`);l.existsSync(n)&&k(n);let r=o.join(t,`.taskgraph`,`state.json`);l.existsSync(r)||A(r),Q()&&w(`debug`,`Complete tag migration performed for project: ${t}`)}catch(e){Q()&&w(`warn`,`Error during complete tag migration: ${e.message}`)}}function k(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 A(e){try{let t={currentTag:`master`,lastSwitched: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 j(e){try{let t=o.dirname(o.dirname(e)),n=o.join(t,`.taskgraph`,`state.json`);l.existsSync(n)||A(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 M(e,t,n=null,r=null){let i=process.env.TASKGRAPH_DEBUG===`true`;try{y(e,()=>{let a=t;if(t&&!t._rawTaggedData&&n&&Array.isArray(t.tasks)&&!T(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 w(`error`,`Error writing JSON file ${e}:`,t.message),i&&w(`error`,`Full error details:`,t),t}}function _e(e=null){let t=!1;try{t=Q()}catch{t=!1}try{let n;if(n=e||o.join(process.cwd(),re),!l.existsSync(n))return t&&w(`debug`,`Complexity report not found at ${n}`),null;let r=D(n);return t&&w(`debug`,`Successfully read complexity report from ${n}`),r}catch(e){return t&&w(`error`,`Error reading complexity report: ${e.message}`),null}}function ve(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=ve(t,n);r&&(e.complexityScore=r.complexityScore)}function ye(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 be(e){return typeof e==`string`&&e.includes(`.`)?e:typeof e==`number`?e.toString():e}function xe(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 Se(e,t){return!e||e.length<=t?e:`${e.slice(0,t-3)}...`}function Ce(e){return Array.isArray(e)?e.length===0:typeof e==`object`&&e?Object.keys(e).length===0:!1}function we(e,t,n=new Set,r=new Set,i=[]){n.add(e),r.add(e),i.push(e);let a=[],o=t.get(e)||[];for(let e of o)if(n.has(e)){if(r.has(e)){let t=i.indexOf(e);i.slice(t),a.push(e)}}else{let o=we(e,t,n,r,[...i]);a.push(...o)}return r.delete(e),a}function Te(e,t,n={}){let{maxDepth:r=50,includeSelf:i=!1,direction:a=`forward`,logger:o=null}=n,s=new Set,c=new Set;function l(e){if(typeof e==`string`){if(e.includes(`.`))return e;let t=parseInt(e,10);return isNaN(t)?e:t}return e}function u(e,n=0){if(n>=r){let t=`Maximum recursion depth (${r}) reached for task ${e}`;o&&typeof o.warn==`function`?o.warn(t):w!==void 0&&w.warn?w.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):w!==void 0&&w.warn?w.warn(t):console.warn(t);return}c.has(e)||(c.add(e),t.forEach(t=>{if(t.dependencies&&Array.isArray(t.dependencies)&&t.dependencies.some(t=>l(t)===e)){if(t.id==null||!i&&t.id===e)return;s.add(t.id),d(t.id,n+1)}}))}let f=a===`reverse`?d:u;return e.forEach(e=>{e&&e.id&&f(e.id)}),Array.from(s)}function Ee(e,t){if(!e||e.length===0)return null;let n={timestamp:new Date().toISOString(),userId:e[0].userId,commandName:t,modelUsed:`Multiple`,providerName:`Multiple`,inputTokens:0,outputTokens:0,totalTokens:0,totalCost:0,currency:e[0].currency||`USD`},r=new Set,i=new Set,a=new Set;return e.forEach(e=>{n.inputTokens+=e.inputTokens||0,n.outputTokens+=e.outputTokens||0,n.totalCost+=e.totalCost||0,r.add(e.modelUsed),i.add(e.providerName),a.add(e.currency||`USD`)}),n.totalTokens=n.inputTokens+n.outputTokens,n.totalCost=parseFloat(n.totalCost.toFixed(6)),r.size===1&&(n.modelUsed=[...r][0]),i.size===1&&(n.providerName=[...i][0]),a.size>1?n.currency=`Multiple`:a.size===1&&(n.currency=[...a][0]),n}function 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 De(e,t){return!e||!t?[]:e[t]&&e[t].tasks&&Array.isArray(e[t].tasks)?e[t].tasks:[]}function Oe(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=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 ke(){return{info:(e,...t)=>w(`info`,e,...t),warn:(e,...t)=>w(`warn`,e,...t),error:(e,...t)=>w(`error`,e,...t),debug:(e,...t)=>w(`debug`,e,...t),success:(e,...t)=>w(`success`,e,...t)}}function L(e=null){return e||ke()}function R(e){return t(e)}function z(e=process.cwd()){return n(e)}function Ae(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,oe);return l.existsSync(s)?(r.info?.(`Found tasks file at: ${s}`),s):(r.warn?.(`No tasks.json found in project: ${a}`),null)}function je(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 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 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 Ne(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=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 Pe=u(import.meta.url);o.dirname(Pe);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 Fe=class extends Error{constructor(e){super(e),this.name=`ConfigurationError`}};function Ie(e=null){let t=H,n=e;e&&`${e}`,n||(n=x(),n||=process.cwd(),`${n}`);let r=null,i={...t};if(l.existsSync(o.join(n,f))&&(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&&!Ce(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,f))&&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=Ie(e);return(t||e)&&(U=n,W=e),n}return U}function q(e){return!!r.includes(e)}function Le(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 Re(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]||(w(`warn`,`No model configuration found for role: ${e}. Returning default.`),H.models[e]||{})}function ze(e=null){return X(`main`,e).provider}function Be(e=null){return X(`main`,e).modelId}function Ve(e=null){return X(`research`,e).provider}function He(e=null,t=null){let n=b(`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 Ue(t=!1,n=null,r=null){return!He(r,n)||t?!1:(t?Ve(n):ze(n))===e.CLAUDE_CODE}function We(e=null){return X(`research`,e).modelId}function Ge(e=null){return X(`fallback`,e).provider}function Ke(e=null){return X(`fallback`,e).modelId}function Z(e=null){let t=K(e);return{...H.global,...t?.global||{}}}function qe(e=null){return Z(e).logLevel.toLowerCase()}function Q(e=null){return Z(e).debug===!0}function Je(e=null){let t=Z(e).defaultSubtasks,n=parseInt(t,10);return Number.isNaN(n)?H.global.defaultSubtasks:n}function Ye(e=null){let t=Z(e).defaultNumTasks,n=parseInt(t,10);return Number.isNaN(n)?H.global.defaultNumTasks:n}function Xe(e=null){return Z(e).defaultPriority}function Ze(e=null){return Z(e).projectName}function Qe(e=null){return Z(e).responseLanguage}function $e(e=null){return Z(e).enableProxy===!0}function et(e=null,t=null){let n=b(`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 $e(t)}function tt(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),w(`debug`,`Applying model-specific max_tokens (${e}) for ${a}. Effective limit: ${s}`)}else w(`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,w(`debug`,`Applying model-specific temperature (${t.temperature}) for ${a}`))}else w(`debug`,`No model definitions found for provider ${o} in MODEL_MAP. Using role default maxTokens: ${r}`)}catch(e){w(`warn`,`Error looking up model-specific parameters for ${a}: ${e.message}. Using role defaults.`),s=r,c=i}return{maxTokens:s,temperature:c}}function nt(){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=x();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 rt(e=null){return B(null,{projectRoot:e})!==null}function it(e=null){let t=K(e);return t.global||={},t.global.userId||(t.global.userId=`1234567890`,$(t,e)||w(`warning`,`Failed to write updated configuration with new userId. Please let the developers know.`)),t.global.userId}export{De as $,$ as A,m as At,N as B,Ue as C,se as Ct,et as D,h as Dt,G as E,ie as Et,z as F,I as G,A as H,Ae as I,xe as J,we as K,R as L,Me as M,ee as Mt,B as N,oe as Nt,J as O,f as Ot,je as P,te as Pt,P as Q,Ne as R,it as S,re as St,rt as T,ce as Tt,ge as U,Ee as V,he as W,Oe as X,ve as Y,be as Z,$e as _,ue as _t,K as a,E as at,Qe as b,de as bt,Xe as c,D as ct,Ge as d,ye as dt,Ce as et,qe as f,Te as ft,Ze as g,le as gt,tt as h,M as ht,Re as i,k as it,V as j,ne as jt,q as k,p as kt,Je as l,b as lt,ze as m,y as mt,nt as n,w as nt,Q as o,O as ot,Be as p,Se as pt,x as q,Y as r,j as rt,Ye as s,_e as st,Fe as t,C as tt,Ke as u,F as ut,We as v,g as vt,He as w,ae as wt,Le as x,_ as xt,Ve as y,fe as yt,S as z};
@@ -1 +1 @@
1
- import{_ as e}from"./src-DUT6aK7P.js";import{A as t,C as n,D as r,E as i,O as a,S as o,T as s,_ as c,a as l,b as u,c as d,d as f,f as p,g as m,h,i as g,j as _,k as v,l as y,m as b,n as x,o as S,p as C,r as w,s as T,t as E,u as D,v as O,w as k,x as A,y as j}from"./config-manager-ze5VncSH.js";import"./git-utils-CrYiSKu0.js";export{e as CUSTOM_PROVIDERS,E as ConfigurationError,_ as MODEL_MAP,x as getAvailableModels,w as getClaudeCodeSettings,g as getClaudeCodeSettingsForCommand,l as getConfig,S as getDebugFlag,T as getDefaultNumTasks,d as getDefaultPriority,y as getDefaultSubtasks,D as getFallbackModelId,f as getFallbackProvider,p as getLogLevel,C as getMainModelId,b as getMainProvider,h as getParametersForRole,m as getProjectName,c as getProxyEnabled,O as getResearchModelId,j as getResearchProvider,u as getResponseLanguage,A as getSupportedModelsForProvider,o as getUserId,n as hasCodebaseAnalysis,k as isCodebaseAnalysisEnabled,s as isConfigFilePresent,i as isConfigWarningSuppressed,r as isProxyEnabled,a as validateClaudeCodeSettings,v as validateProvider,t as writeConfig};
1
+ import{_ as e}from"./src-kk3jUMbL.js";import{A as t,C as n,D as r,E as i,O as a,S as o,T as s,_ as c,a as l,b as u,c as d,d as f,f as p,g as m,h,i as g,j as _,k as v,l as y,m as b,n as x,o as S,p as C,r as w,s as T,t as E,u as D,v as O,w as k,x as A,y as j}from"./config-manager-BTO7V7yI.js";import"./git-utils-CrYiSKu0.js";export{e as CUSTOM_PROVIDERS,E as ConfigurationError,_ as MODEL_MAP,x as getAvailableModels,w as getClaudeCodeSettings,g as getClaudeCodeSettingsForCommand,l as getConfig,S as getDebugFlag,T as getDefaultNumTasks,d as getDefaultPriority,y as getDefaultSubtasks,D as getFallbackModelId,f as getFallbackProvider,p as getLogLevel,C as getMainModelId,b as getMainProvider,h as getParametersForRole,m as getProjectName,c as getProxyEnabled,O as getResearchModelId,j as getResearchProvider,u as getResponseLanguage,A as getSupportedModelsForProvider,o as getUserId,n as hasCodebaseAnalysis,k as isCodebaseAnalysisEnabled,s as isConfigFilePresent,i as isConfigWarningSuppressed,r as isProxyEnabled,a as validateClaudeCodeSettings,v as validateProvider,t as writeConfig};