taskgraph-ai 0.54.13 → 0.54.22

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -265,7 +265,7 @@ In Claude Code, say `Change the main model to opus`, or run `taskgraph models --
265
265
 
266
266
  Projects created with Task Master, or with a TaskGraph release before 0.47, also need a few manual changes:
267
267
 
268
- - **Rename `.taskmaster/` to `.taskgraph/`** by hand. TaskGraph no longer detects the old folder.
268
+ - **Import `.taskmaster/`** with `taskgraph init --from-taskmaster --yes`. It copies every tag, the docs and reports, and the settings that still apply, and leaves `.taskmaster/` in place. See [Migrating from Task Master](apps/docs/migrating-from-taskmaster.mdx).
269
269
  - **Rename environment variables:** `TASK_MASTER_*` and `TASKMASTER_*` are now `TASKGRAPH_*`. The old names are ignored.
270
270
  - **Removed:** the `taskgraph migrate` command and `.taskmasterconfig`. Configuration lives in `.taskgraph/config.json`; run `taskgraph models --setup` to recreate it.
271
271
  - **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`.
@@ -1,3 +1,3 @@
1
- import{n as e}from"./rolldown-runtime-BxhE39jg.js";import{B as t}from"./src-Cs4ilbQ-.js";import{$ as n,D as r,G as i,M as a,S as o,X as s,at as c,b as l,d as u,h as d,i as f,m as p,o as m,p as h,u as g,v as _,x as v,y}from"./config-manager-DIET_FiX.js";import b from"path";import{execSync as x}from"child_process";import S from"fs";import{createClaudeCode as C}from"ai-sdk-provider-claude-code";import*as w from"ai";import{jsonrepair as T}from"jsonrepair";import{EnvHttpProxyAgent as E}from"undici";const D=[`Read`,`Grep`,`Glob`];function O(e){let t=e,n=[];for(;;)try{return b.join(S.realpathSync(t),...n.reverse())}catch{let r=b.dirname(t);if(r===t)return e;n.push(b.basename(t)),t=r}}function k(e,t){if(typeof t!=`string`||t.startsWith(`~`))return!1;let n=O(b.resolve(e,t)),r=b.relative(e,n),i=r===`..`||r.startsWith(`..${b.sep}`);return r===``||!i&&!b.isAbsolute(r)}const A=/^(\.env(\..*)?|\.git|\.npmrc|id_(rsa|dsa|ecdsa|ed25519).*)$|\.pem$/i,ee=/^\.env\.(example|sample|template)$/i;function j(e){return e.split(/[\\/,]/).map(e=>e.replace(/[*?[\]{}]/g,``)).some(e=>A.test(e)&&!ee.test(e))}function M(e,t){let n=b.resolve(e,t);return[n,O(n)].some(t=>j(b.relative(e,t)))}function N(e){return e.split(/[\\/]/).includes(`..`)}function P(e){if(!b.posix.isAbsolute(e)&&!b.win32.isAbsolute(e))return null;if(!/[*?[{]/.test(e)){let t=e.replace(/[\\/]+$/,``)||e;return b.win32.isAbsolute(t)&&!b.posix.isAbsolute(t)?b.win32.dirname(t):b.posix.dirname(t)}let t=e.split(/[*?[{]/)[0],n=Math.max(t.lastIndexOf(`/`),t.lastIndexOf(`\\`));return t.slice(0,n+1)||t}function te(e,t,n={}){if(!D.includes(t))return null;let r=[n.file_path,n.path].filter(e=>e!=null);for(let n of r){if(!k(e,n))return`${t} is limited to the project directory (${e}); ${n} is outside it.`;if(M(e,n))return`${t} may not open secret files such as .env, .git or keys (${n}).`}if(typeof n.glob==`string`&&j(n.glob))return`${t} globs may not match secret files such as .env, .git or keys.`;let i=t===`Glob`?n.pattern:void 0;if(typeof i==`string`){let n=`${t} patterns may not leave the project directory (${e}).`;if(N(i)||i.startsWith(`~`))return n;if(j(i))return`${t} patterns may not match secret files such as .env, .git or keys.`;let r=P(i);if(r!==null&&!k(e,r))return n}return null}function ne(e){let t=O(b.resolve(e));return{matcher:D.join(`|`),hooks:[async e=>{let n=te(t,e?.tool_name,e?.tool_input);return n?{hookSpecificOutput:{hookEventName:`PreToolUse`,permissionDecision:`deny`,permissionDecisionReason:n}}:{}}]}}const{JSONParseError:re,NoObjectGeneratedError:ie,generateObject:ae,generateText:oe,streamObject:se,streamText:ce,zodSchema:le}=w,F=w.jsonSchema,I=/* @__PURE__ */ new Set([`minimum`,`maximum`,`exclusiveMinimum`,`exclusiveMaximum`]),L=[`additionalProperties`,`contains`,`if`,`then`,`else`,`not`,`propertyNames`],R=[`allOf`,`anyOf`,`oneOf`,`prefixItems`],z=[`definitions`,`$defs`,`dependentSchemas`,`patternProperties`,`properties`],B=e=>e?Array.isArray(e)?e.includes(`integer`):e===`integer`:!1,V=e=>{if(!e||typeof e!=`object`)return e;if(Array.isArray(e))return e.map(V);let t={...e};if(B(t.type))for(let e of I)e in t&&delete t[e];for(let e of L)t[e]&&(t[e]=V(t[e]));for(let e of R)Array.isArray(t[e])&&(t[e]=t[e].map(V));for(let e of z)if(t[e]&&typeof t[e]==`object`){let n={};for(let[r,i]of Object.entries(t[e]))n[r]=V(i);t[e]=n}return t.items&&=V(t.items),t},H=e=>{let t=le(e);if(!t||typeof t!=`object`||!t.jsonSchema)return t;let n=V(t.jsonSchema);return typeof F==`function`?F(n,{validate:t.validate}):{...t,jsonSchema:n}};function U(){let e=Number(process.env.TASKGRAPH_AI_TIMEOUT_MS);return AbortSignal.timeout(Number.isFinite(e)&&e>0?e:6e5)}var W=class e{constructor(){if(this.constructor===e)throw Error(`BaseAIProvider cannot be instantiated directly`);this.name=this.constructor.name,this._proxyAgent=null,this.needsExplicitJsonSchema=!1,this.supportsTemperature=!0}validateAuth(e){if(!e.apiKey)throw Error(`${this.name} API key is required`)}createProxyFetch(){this._projectRoot||=i();let e=this._projectRoot;if(r(null,e))return this._proxyAgent||=new E,(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 r=t.message||`Unknown error occurred`;throw n(`error`,`${this.name} ${e} failed: ${r}`,{error:t}),Error(`${this.name} API error during ${e}: ${r}`)}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{n as e}from"./rolldown-runtime-BxhE39jg.js";import{Y as t}from"./src-BQZsjzA5.js";import{$ as n,D as r,G as i,M as a,S as o,X as s,at as c,b as l,d as u,h as d,i as f,m as p,o as m,p as h,u as g,v as _,x as v,y}from"./config-manager-DTkRerDn.js";import b from"path";import{execSync as x}from"child_process";import S from"fs";import{createClaudeCode as C}from"ai-sdk-provider-claude-code";import*as w from"ai";import{jsonrepair as T}from"jsonrepair";import{EnvHttpProxyAgent as E}from"undici";const D=[`Read`,`Grep`,`Glob`];function O(e){let t=e,n=[];for(;;)try{return b.join(S.realpathSync(t),...n.reverse())}catch{let r=b.dirname(t);if(r===t)return e;n.push(b.basename(t)),t=r}}function k(e,t){if(typeof t!=`string`||t.startsWith(`~`))return!1;let n=O(b.resolve(e,t)),r=b.relative(e,n),i=r===`..`||r.startsWith(`..${b.sep}`);return r===``||!i&&!b.isAbsolute(r)}const A=/^(\.env(\..*)?|\.git|\.npmrc|id_(rsa|dsa|ecdsa|ed25519).*)$|\.pem$/i,ee=/^\.env\.(example|sample|template)$/i;function j(e){return e.split(/[\\/,]/).map(e=>e.replace(/[*?[\]{}]/g,``)).some(e=>A.test(e)&&!ee.test(e))}function M(e,t){let n=b.resolve(e,t);return[n,O(n)].some(t=>j(b.relative(e,t)))}function N(e){return e.split(/[\\/]/).includes(`..`)}function P(e){if(!b.posix.isAbsolute(e)&&!b.win32.isAbsolute(e))return null;if(!/[*?[{]/.test(e)){let t=e.replace(/[\\/]+$/,``)||e;return b.win32.isAbsolute(t)&&!b.posix.isAbsolute(t)?b.win32.dirname(t):b.posix.dirname(t)}let t=e.split(/[*?[{]/)[0],n=Math.max(t.lastIndexOf(`/`),t.lastIndexOf(`\\`));return t.slice(0,n+1)||t}function te(e,t,n={}){if(!D.includes(t))return null;let r=[n.file_path,n.path].filter(e=>e!=null);for(let n of r){if(!k(e,n))return`${t} is limited to the project directory (${e}); ${n} is outside it.`;if(M(e,n))return`${t} may not open secret files such as .env, .git or keys (${n}).`}if(typeof n.glob==`string`&&j(n.glob))return`${t} globs may not match secret files such as .env, .git or keys.`;let i=t===`Glob`?n.pattern:void 0;if(typeof i==`string`){let n=`${t} patterns may not leave the project directory (${e}).`;if(N(i)||i.startsWith(`~`))return n;if(j(i))return`${t} patterns may not match secret files such as .env, .git or keys.`;let r=P(i);if(r!==null&&!k(e,r))return n}return null}function ne(e){let t=O(b.resolve(e));return{matcher:D.join(`|`),hooks:[async e=>{let n=te(t,e?.tool_name,e?.tool_input);return n?{hookSpecificOutput:{hookEventName:`PreToolUse`,permissionDecision:`deny`,permissionDecisionReason:n}}:{}}]}}const{JSONParseError:re,NoObjectGeneratedError:ie,generateObject:ae,generateText:oe,streamObject:se,streamText:ce,zodSchema:le}=w,F=w.jsonSchema,I=/* @__PURE__ */ new Set([`minimum`,`maximum`,`exclusiveMinimum`,`exclusiveMaximum`]),L=[`additionalProperties`,`contains`,`if`,`then`,`else`,`not`,`propertyNames`],R=[`allOf`,`anyOf`,`oneOf`,`prefixItems`],z=[`definitions`,`$defs`,`dependentSchemas`,`patternProperties`,`properties`],B=e=>e?Array.isArray(e)?e.includes(`integer`):e===`integer`:!1,V=e=>{if(!e||typeof e!=`object`)return e;if(Array.isArray(e))return e.map(V);let t={...e};if(B(t.type))for(let e of I)e in t&&delete t[e];for(let e of L)t[e]&&(t[e]=V(t[e]));for(let e of R)Array.isArray(t[e])&&(t[e]=t[e].map(V));for(let e of z)if(t[e]&&typeof t[e]==`object`){let n={};for(let[r,i]of Object.entries(t[e]))n[r]=V(i);t[e]=n}return t.items&&=V(t.items),t},H=e=>{let t=le(e);if(!t||typeof t!=`object`||!t.jsonSchema)return t;let n=V(t.jsonSchema);return typeof F==`function`?F(n,{validate:t.validate}):{...t,jsonSchema:n}};function U(){let e=Number(process.env.TASKGRAPH_AI_TIMEOUT_MS);return AbortSignal.timeout(Number.isFinite(e)&&e>0?e:6e5)}var W=class e{constructor(){if(this.constructor===e)throw Error(`BaseAIProvider cannot be instantiated directly`);this.name=this.constructor.name,this._proxyAgent=null,this.needsExplicitJsonSchema=!1,this.supportsTemperature=!0}validateAuth(e){if(!e.apiKey)throw Error(`${this.name} API key is required`)}createProxyFetch(){this._projectRoot||=i();let e=this._projectRoot;if(r(null,e))return this._proxyAgent||=new E,(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 r=t.message||`Unknown error occurred`;throw n(`error`,`${this.name} ${e} failed: ${r}`,{error:t}),Error(`${this.name} API error during ${e}: ${r}`)}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),n(`debug`,`Generating ${this.name} text with model: ${e.modelId}`);let t=await this.getClient(e),r=await oe({abortSignal:U(),model:t(e.modelId),...this.prepareMessages(e.messages),...this.prepareTokenParam(e.modelId,e.maxTokens),...this.supportsTemperature&&e.temperature!==void 0?{temperature:e.temperature}:{}});n(`debug`,`${this.name} generateText completed successfully for model: ${e.modelId}`);let i=r.usage?.inputTokens??r.usage?.promptTokens??0,a=r.usage?.outputTokens??r.usage?.completionTokens??0,o=r.usage?.totalTokens??i+a,s=r.usage?.inputTokenDetails?.cacheReadTokens??r.usage?.cachedInputTokens??0;return{text:r.text,usage:{inputTokens:i,outputTokens:a,totalTokens:o,cachedInputTokens:s}}}catch(e){this.handleError(`text generation`,e)}}async streamText(e){try{this.validateParams(e),this.validateMessages(e.messages),n(`debug`,`Streaming ${this.name} text with model: ${e.modelId}`);let t=await this.getClient(e),r=await ce({model:t(e.modelId),...this.prepareMessages(e.messages),...this.prepareTokenParam(e.modelId,e.maxTokens),...this.supportsTemperature&&e.temperature!==void 0?{temperature:e.temperature}:{},...e.experimental_transform&&{experimental_transform:e.experimental_transform}});return n(`debug`,`${this.name} streamText initiated successfully for model: ${e.modelId}`),r}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`);n(`debug`,`Streaming ${this.name} object with model: ${e.modelId}`);let t=await this.getClient(e),r=H(e.schema),i=await se({model:t(e.modelId),...this.prepareMessages(e.messages),schema:r,mode:this.needsExplicitJsonSchema?`json`:`auto`,...e.objectName&&{schemaName:e.objectName,schemaDescription:`Generate a valid JSON object for ${e.objectName}`},...this.prepareTokenParam(e.modelId,e.maxTokens),...this.supportsTemperature&&e.temperature!==void 0?{temperature:e.temperature}:{},onError:({error:e})=>n(`debug`,`${this.name} stream error: ${e?.message??e}`)});return n(`debug`,`${this.name} streamObject initiated successfully for model: ${e.modelId}`),i}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`);n(`debug`,`Generating ${this.name} object ('${e.objectName}') with model: ${e.modelId}`);let t=await this.getClient(e),r=H(e.schema),i=await ae({abortSignal:U(),model:t(e.modelId),...this.prepareMessages(e.messages),schema:r,mode:this.needsExplicitJsonSchema?`json`:`auto`,schemaName:e.objectName,schemaDescription:`Generate a valid JSON object for ${e.objectName}`,...this.prepareTokenParam(e.modelId,e.maxTokens),...this.supportsTemperature&&e.temperature!==void 0?{temperature:e.temperature}:{}});n(`debug`,`${this.name} generateObject completed successfully for model: ${e.modelId}`);let a=i.usage?.inputTokens??i.usage?.promptTokens??0,o=i.usage?.outputTokens??i.usage?.completionTokens??0,s=i.usage?.totalTokens??a+o,c=i.usage?.inputTokenDetails?.cacheReadTokens??i.usage?.cachedInputTokens??0;return{object:i.object,usage:{inputTokens:a,outputTokens:o,totalTokens:s,cachedInputTokens:c}}}catch(e){if(ie.isInstance(e)&&e.cause instanceof re&&e.cause.text){n(`warn`,`${this.name} generated malformed JSON, attempting to repair...`);try{let t=T(e.cause.text),r=JSON.parse(t);return n(`debug`,`Successfully repaired ${this.name} JSON output`),{object:r,usage:{inputTokens:e.usage?.promptTokens||e.usage?.inputTokens||0,outputTokens:e.usage?.completionTokens||e.usage?.outputTokens||0,totalTokens:e.usage?.totalTokens||0}}}catch(e){n(`error`,`Failed to repair ${this.name} JSON: ${e.message}`)}}this.handleError(`object generation`,e)}}};let G=!1;const ue=[`WebSearch`,`WebFetch`],de=[`Read`,`Grep`,`Glob`],fe=/^claude(\.exe|\.cmd)?$/i;function K(e,t){let n=b.relative(e,t);return n===``||n!==`..`&&!n.startsWith(`..${b.sep}`)&&!b.isAbsolute(n)}function pe(e,t){if(typeof e!=`string`||!b.isAbsolute(e)||!fe.test(b.basename(e)))return!1;let n;try{n=S.realpathSync(e)}catch{return!1}if(!t)return!0;let r=b.resolve(t),i=r;try{i=S.realpathSync(r)}catch{}return!K(r,b.resolve(e))&&!K(i,n)}function me(e,t){let r=e.pathToClaudeCodeExecutable;if(r===void 0||pe(r,t))return e;n(`warn`,`Ignoring pathToClaudeCodeExecutable "${r}": it must be an absolute path to a file named claude outside the project`);let{pathToClaudeCodeExecutable:i,...a}=e;return a}function he(e,t,n){let r=e===`research`,i=r?ue:n?de:[];return{tools:[...i],allowedTools:[...i],permissionMode:`dontAsk`,permissionPrompts:`none`,strictMcpConfig:!0,mcpServers:{},settingSources:[],...r?{maxTurns:t.maxTurns??8}:{cwd:n??void 0,additionalDirectories:void 0,hooks:n?{PreToolUse:[ne(n)]}:{}}}}var ge=class extends W{constructor(){super(),this.name=`Claude Code`,this.supportedModels=v(`claude-code`),this.supportedModels.length===0&&n(`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`&&!G&&!process.env.CLAUDE_CODE_OAUTH_TOKEN)try{x(`claude --version`,{stdio:`pipe`,timeout:1e3})}catch{n(`debug`,"No `claude` on PATH; using the Claude Code bundled with the Agent SDK")}finally{G=!0}}getClient(e={}){try{let r=e.projectRoot?b.resolve(e.projectRoot):null,i=me(f(e.commandName)||{},r),a=r?t(r):{...process.env},o=a.CLAUDE_CODE_API_KEY;return o?a.ANTHROPIC_API_KEY=o:delete a.ANTHROPIC_API_KEY,C({defaultSettings:{systemPrompt:{type:`preset`,preset:`claude_code`},env:a,logger:{debug:e=>n(`debug`,e),info:e=>n(`debug`,e),warn:e=>n(`debug`,e),error:e=>n(`error`,e)},...i,...he(e.role,i,r)}})}catch(e){let t=String(e?.message||``);if(e?.code===`ENOENT`||/claude/i.test(t)){let t=/* @__PURE__ */ Error(`Claude Code CLI not available. Please install Claude Code CLI first. Original error: ${e.message}`);t.cause=e,this.handleError(`Claude Code CLI initialization`,t)}else this.handleError(`client initialization`,e)}}getSupportedModels(){return this.supportedModels}isModelSupported(e){return e?this.supportedModels.includes(String(e).toLowerCase()):!1}};let q=null;var J=class e{constructor(){this._providers=/* @__PURE__ */ new Map,this._initialized=!1}static getInstance(){return q||=new e,q}initialize(){return this._initialized||=!0,this}registerProvider(e,t,n={}){if(!e||typeof e!=`string`)throw Error(`Provider name must be a non-empty string`);if(!t)throw Error(`Provider instance is required`);if(typeof t.generateText!=`function`||typeof t.streamText!=`function`||typeof t.generateObject!=`function`)throw Error(`Provider must implement BaseAIProvider interface`);return this._providers.set(e,{instance:t,options:n,registeredAt:/* @__PURE__ */ new Date}),this}hasProvider(e){return this._providers.has(e)}getProvider(e){let t=this._providers.get(e);return t?t.instance:null}getAllProviders(){return new Map(this._providers)}unregisterProvider(e){return this._providers.has(e)?(this._providers.delete(e),!0):!1}reset(){this._providers.clear(),this._initialized=!1}};J.getInstance().initialize(),globalThis.AI_SDK_LOG_WARNINGS===void 0&&(globalThis.AI_SDK_LOG_WARNINGS=({warnings:e,provider:t,model:r})=>{for(let i of e){let e=i.message||i.feature||i.setting||i.type;n(`debug`,`AI SDK warning (${t??`?`}/${r??`?`}): ${e}`)}});const Y={"claude-code":new ge};function X(e){if(Y[e])return Y[e];let t=J.getInstance();return t.hasProvider(e)?(n(`debug`,`Provider "${e}" found in dynamic registry`),t.getProvider(e)):null}function _e(e,t){let r={inputCost:0,outputCost:0,currency:`USD`,isUnknown:!1};if(!a||!a[e])return n(`warn`,`Provider "${e}" not found in MODEL_MAP. Cannot determine cost for model ${t}.`),{...r,isUnknown:!0};let i=a[e].find(e=>e.id===t);if(!i)return n(`debug`,`Model "${t}" not found under provider "${e}". Assuming unknown cost.`),{...r,isUnknown:!0};if(i.cost_per_1m_tokens===null)return n(`debug`,`Cost data is null for model "${t}" under provider "${e}". Pricing unknown.`),{...r,isUnknown:!0};if(i.cost_per_1m_tokens===void 0)return n(`debug`,`Cost data not found for model "${t}" under provider "${e}". Pricing unknown.`),{...r,isUnknown:!0};let o=i.cost_per_1m_tokens;return{inputCost:o.input||0,outputCost:o.output||0,currency:o.currency||`USD`,isUnknown:!1}}function ve(e,t,n,r){let i=(e||0)/1e6*n+(t||0)/1e6*r;return parseFloat(i.toFixed(6))}function ye(e){let t={currentTag:`master`,availableTags:[`master`]};try{return e?{currentTag:s(e)||`master`,availableTags:be(e)}:t}catch(e){return m()&&n(`debug`,`Error getting tag information: ${e.message}`),t}}function be(t){let r=[`master`];try{let n=e(`path`),i=e(`fs`),a=n.join(t,`.taskgraph`,`tasks`,`tasks.json`);if(!i.existsSync(a))return r;let o=JSON.parse(i.readFileSync(a,`utf8`));if(!o||typeof o!=`object`)return r;let s=Object.keys(o).filter(e=>xe(o[e]));return s.length>0?s:r}catch(e){return m()&&n(`debug`,`Could not read tasks file for available tags: ${e.message}`),r}}function xe(e){return e&&typeof e==`object`&&Array.isArray(e.tasks)}function Se(e){let t=e.message?.toLowerCase()||``;return e.name===`TimeoutError`||t.includes(`aborted`)?!1: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 Z(e){try{if(e?.data?.error?.message)return e.data.error.message;if(e?.error?.message)return e.error.message;if(typeof e?.responseBody==`string`)try{let t=JSON.parse(e.responseBody);if(t?.error?.message)return t.error.message}catch{}return typeof e?.message==`string`&&e.message?e.message:typeof e==`string`?e:`An unknown AI service error occurred.`}catch{return`Failed to extract error message.`}}function Ce(e,t){return{main:{provider:p(t),modelId:h(t)},research:{provider:y(t),modelId:_(t)},fallback:{provider:u(t),modelId:g(t)}}[e]||null}function we(e,t,n=null){let r=X(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 Te(e,t,r,i,a,o){let s=0,c=t;for(;s<=2;)try{m()&&n(`info`,`Attempt ${s+1}/3 calling ${c} (Provider: ${i}, Model: ${a}, Role: ${o})`);let l=await e[t](r);return m()&&n(`info`,`${c} succeeded for role ${o} (Provider: ${i}) on attempt ${s+1}`),l}catch(e){if(n(`warn`,`Attempt ${s+1} failed for role ${o} (${c} / ${i}): ${e.message}`),Se(e)&&s<2){s++;let e=1e3*2**(s-1);n(`info`,`Something went wrong on the provider side. Retrying in ${e/1e3}s...`),await new Promise(t=>setTimeout(t,e))}else throw n(`error`,`Something went wrong on the provider side. Max retries reached for role ${o} (${c} / ${i}).`),e}throw Error(`Exhausted all retries for role ${o} (${c} / ${i})`)}async function Q(e,t){let{role:r,session:a,projectRoot:s,systemPrompt:c,prompt:u,schema:f,objectName:p,commandName:h,outputType:g,experimental_transform:_,...v}=t;m()&&n(`debug`,`${e}Service called`,{role:r,commandName:h,outputType:g,projectRoot:s});let y=s||i(),b=o(y),x;r===`main`?x=[`main`,`fallback`,`research`]:r===`research`?x=[`research`,`fallback`,`main`]:r===`fallback`?x=[`fallback`,`main`,`research`]:(n(`warn`,`Unknown initial role: ${r}. Defaulting to main -> fallback -> research sequence.`),x=[`main`,`fallback`,`research`]);let S=/* @__PURE__ */ new Set,C=null,w=`AI service call failed for all configured roles.`;for(let t of x){let r,i,o,s,m,x,T=null;try{n(`debug`,`New AI service call with role: ${t}`);let w=Ce(t,y);if(!w){n(`error`,`Unknown role encountered in _unifiedServiceRunner: ${t}`),C||=/* @__PURE__ */ Error(`Unknown AI role specified: ${t}`);continue}if(r=w.provider,i=w.modelId,!r||!i){n(`warn`,`Skipping role '${t}': Provider or Model ID not configured.`),C||=/* @__PURE__ */ Error(`Configuration missing for role '${t}'. Provider: ${r}, Model: ${i}`);continue}if(S.has(`${r}/${i}`)){n(`debug`,`Skipping role '${t}': ${r}/${i} already failed for this request.`);continue}if(m=X(r?.toLowerCase()),!m){n(`warn`,`Skipping role '${t}': Provider '${r}' not supported.`),C||=/* @__PURE__ */ Error(`Unsupported provider configured: ${r}`);continue}s=d(t,y),o=we(r?.toLowerCase(),a,y);let E=[],D=`${c} \n\n Always respond in ${l(y)}.`;if(E.push({role:`system`,content:D.trim()}),u)E.push({role:`user`,content:u});else throw Error(`User prompt content is missing.`);let O={apiKey:o,modelId:i,maxTokens:s.maxTokens,temperature:s.temperature,messages:E,...(e===`generateObject`||e===`streamObject`)&&{schema:f,objectName:p},role:t,projectRoot:y,...h&&{commandName:h},..._&&{experimental_transform:_},...v};if(x=await Te(m,e,O,r,i,t),b&&x&&x.usage)try{T=await $({userId:b,commandName:h,providerName:r,modelId:i,inputTokens:x.usage.inputTokens,outputTokens:x.usage.outputTokens,cachedInputTokens:x.usage.cachedInputTokens,outputType:g})}catch{}else b&&x&&!x.usage&&n(`warn`,`Cannot log telemetry for ${h} (${r}/${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`||n(`error`,`Unknown serviceType in _unifiedServiceRunner: ${e}`),k=x);let A=ye(y);return{mainResult:k,telemetryData:T,tagInfo:A,providerName:r,modelId:i}}catch(a){let o=Z(a);if(n(`error`,`Service call failed for role ${t} (Provider: ${r||`unknown`}, Model: ${i||`unknown`}): ${o}`),C=a,w=o,r&&i&&S.add(`${r}/${i}`),e===`generateObject`){let e=o.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 '${r||`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 n(`error`,`[Tool Support Error] ${e}`),Error(e)}}}}throw n(`error`,`All roles in the sequence [${x.join(`, `)}] failed.`),Error(w)}async function Ee(e){return Q(`generateText`,{outputType:`cli`,...e})}async function De(e){let t={outputType:`cli`,...e};if(!t.schema)throw Error(`streamObjectService requires a schema parameter`);return Q(`streamObject`,t)}async function Oe(e){return Q(`generateObject`,{objectName:`generated_object`,maxRetries:3,outputType:`cli`,...e})}async function $({userId:e,commandName:t,providerName:r,modelId:i,inputTokens:a,outputTokens:o,cachedInputTokens:s,outputType:c}){try{let c=(/* @__PURE__ */ new Date()).toISOString(),l=(a||0)+(o||0),{inputCost:u,outputCost:d,currency:f,isUnknown:p}=_e(r,i),h=ve(a,o,u,d),g={timestamp:c,userId:e,commandName:t,modelUsed:i,providerName:r,inputTokens:a||0,outputTokens:o||0,totalTokens:l,...s>0?{cachedInputTokens:s}:{},totalCost:h,currency:f,isUnknownCost:p};return m()&&n(`debug`,`AI Usage Telemetry:`,g),g}catch(e){return n(`error`,`Failed to log AI usage telemetry: ${e.message}`,{error:e}),null}}export{k as a,De as i,Ee as n,$ as r,Oe as t};
@@ -0,0 +1 @@
1
+ export{r as logAiUsage}from"./ai-services-unified-B45jIPar.js";
@@ -1,433 +1,13 @@
1
- # TaskGraph - Agent Integration Guide
1
+ # TaskGraph
2
2
 
3
- ## Essential Commands
3
+ This project tracks work in TaskGraph. Run `taskgraph prime` for the task in progress, what's ready next, and the workflow rules; follow those rules. A Claude Code session with the TaskGraph plugin gets this at startup.
4
4
 
5
- ### Core Workflow Commands
5
+ ## Daily commands
6
6
 
7
- ```bash
8
- # Project Setup
9
- taskgraph init # Initialize TaskGraph in current project
10
- taskgraph parse-prd .taskgraph/docs/prd.md # Generate tasks from PRD document
11
- taskgraph models --setup # Configure AI models interactively
7
+ - `taskgraph next`: the next task to work on
8
+ - `taskgraph show <id>`: one task in detail (`3`, or a subtask like `3.2`)
9
+ - `taskgraph list`: all tasks, filtered by `--status` or `--tag`
10
+ - `taskgraph set-status --id=<id> --status=in-progress`: claim a task (`--status=done` when finished)
11
+ - `taskgraph add-task --prompt="<what>"`: add a task
12
12
 
13
- # Daily Development Workflow
14
- taskgraph list # Show all tasks with status
15
- taskgraph next # Get next available task to work on
16
- taskgraph show <id> # View detailed task information (e.g., taskgraph show 1.2)
17
- taskgraph set-status --id=<id> --status=done # Mark task complete
18
-
19
- # Task Management
20
- taskgraph add-task --prompt="description" --research # Add new task with AI assistance
21
- taskgraph expand --id=<id> --research --force # Break task into subtasks
22
- taskgraph update-task --id=<id> --prompt="changes" # Update specific task
23
- taskgraph update --from=<id> --prompt="changes" # Update multiple tasks from ID onwards
24
- taskgraph update-subtask --id=<id> --prompt="notes" # Add implementation notes to subtask
25
-
26
- # Analysis & Planning
27
- taskgraph analyze-complexity --research # Analyze task complexity
28
- taskgraph complexity-report # View complexity analysis
29
- taskgraph expand --all --research # Expand all eligible tasks
30
-
31
- # Dependencies & Organization
32
- taskgraph add-dependency --id=<id> --depends-on=<id> # Add task dependency
33
- taskgraph move --from=<id> --to=<id> # Reorganize task hierarchy
34
- taskgraph validate-dependencies # Check for dependency issues
35
- taskgraph generate # Update task markdown files (usually auto-called)
36
- ```
37
-
38
- ## Key Files & Project Structure
39
-
40
- ### Core Files
41
-
42
- - `.taskgraph/tasks/tasks.json` - Main task data file (auto-managed)
43
- - `.taskgraph/config.json` - AI model configuration (use `taskgraph models` to modify)
44
- - `.taskgraph/docs/prd.md` - Product Requirements Document for parsing (`.md` extension recommended for better editor support)
45
- - `.taskgraph/tasks/*.txt` - Individual task files (auto-generated from tasks.json)
46
- - `.env` - Optional environment variables (for example `CLAUDE_CODE_API_KEY`)
47
-
48
- **PRD File Format:** While both `.txt` and `.md` extensions work, **`.md` is recommended** because:
49
- - Markdown syntax highlighting in editors improves readability
50
- - Proper rendering when previewing in VS Code, GitHub, or other tools
51
- - Better collaboration through formatted documentation
52
-
53
- ### Claude Code Integration Files
54
-
55
- - `CLAUDE.md` - Auto-loaded context for Claude Code (this file)
56
- - `.claude/settings.json` - Claude Code tool allowlist and preferences
57
- - `.claude/commands/` - Custom slash commands for repeated workflows
58
- - `.mcp.json` - MCP server configuration (project-specific)
59
-
60
- ### Directory Structure
61
-
62
- ```
63
- project/
64
- ├── .taskgraph/
65
- │ ├── tasks/ # Task files directory
66
- │ │ ├── tasks.json # Main task database
67
- │ │ ├── task-1.md # Individual task files
68
- │ │ └── task-2.md
69
- │ ├── docs/ # Documentation directory
70
- │ │ ├── prd.md # Product requirements (.md recommended)
71
- │ ├── reports/ # Analysis reports directory
72
- │ │ └── task-complexity-report.json
73
- │ ├── templates/ # Template files
74
- │ │ └── example_prd.md # Example PRD template (.md recommended)
75
- │ └── config.json # AI models & settings
76
- ├── .claude/
77
- │ ├── settings.json # Claude Code configuration
78
- │ └── commands/ # Custom slash commands
79
- ├── .env # Optional env vars
80
- ├── .mcp.json # MCP configuration
81
- └── CLAUDE.md # This file - auto-loaded by Claude Code
82
- ```
83
-
84
- ## Slash Commands & CLI (Preferred)
85
-
86
- Use slash commands or the `taskgraph` CLI first. They need no MCP server and load no extra tool definitions into context. Only fall back to the MCP tools below when a command you need has no slash command or CLI equivalent.
87
-
88
- With the TaskGraph plugin installed (`/plugin marketplace add stephennmiller/taskgraph-ai`, then `/plugin install taskgraph@taskgraph`), the slash commands live under `/taskgraph:` (type `/taskgraph` to list them). `taskgraph init` does not write slash commands:
89
-
90
- | Task | Slash command | CLI |
91
- |------|---------------|-----|
92
- | Find next task | `/taskgraph:next-task` | `taskgraph next` |
93
- | View a task | `/taskgraph:show-task <id>` | `taskgraph show <id>` |
94
- | List tasks | `/taskgraph:list-tasks` | `taskgraph list` |
95
- | Parse a PRD | `/taskgraph:parse-prd` | `taskgraph parse-prd <file>` |
96
- | Add a task | `/taskgraph:add-task` | `taskgraph add-task --prompt="..."` |
97
- | Break into subtasks | `/taskgraph:expand-task <id>` | `taskgraph expand --id=<id>` |
98
- | Change status | `/taskgraph:set-status <id> <status>`, or the shortcuts `/taskgraph:to-in-progress <id>` and `/taskgraph:to-done <id>` | `taskgraph set-status --id=<id> --status=<status>` |
99
- | Update a task | `/taskgraph:update-task <id>` | `taskgraph update-task --id=<id> --prompt="..."` |
100
- | Check complexity | `/taskgraph:analyze-complexity` | `taskgraph analyze-complexity` |
101
-
102
- ## MCP Integration (Optional)
103
-
104
- TaskGraph also provides an MCP server that Claude Code can connect to. It is optional; the slash commands and CLI above cover the same workflow. To use it, configure `.mcp.json`:
105
-
106
- ```json
107
- {
108
- "mcpServers": {
109
- "taskgraph-ai": {
110
- "command": "npx",
111
- "args": ["-y", "taskgraph-ai"],
112
- "env": {
113
- "TASKGRAPH_TOOLS": "core"
114
- }
115
- }
116
- }
117
- }
118
- ```
119
-
120
- ### MCP Tool Tiers
121
-
122
- Default: `core` (7 tools). Set via `TASKGRAPH_TOOLS` env var.
123
-
124
- | Tier | Count | Tools |
125
- |------|-------|-------|
126
- | `core` | 7 | `get_tasks`, `next_task`, `get_task`, `set_task_status`, `update_subtask`, `parse_prd`, `expand_task` |
127
- | `standard` | 15 | core + `initialize_project`, `analyze_project_complexity`, `expand_all`, `add_subtask`, `remove_task`, `add_task`, `complexity_report`, `dependency_analysis` |
128
- | `all` | 46 | standard + dependencies, tags, research, autopilot, scoping, models |
129
-
130
- **Upgrade when tool unavailable:** Edit MCP config, change `TASKGRAPH_TOOLS` from `"core"` to `"standard"` or `"all"`, restart MCP.
131
-
132
- ### Essential MCP Tools
133
-
134
- ```javascript
135
- // Project setup
136
- initialize_project; // = taskgraph init
137
- parse_prd; // = taskgraph parse-prd
138
-
139
- // Daily workflow
140
- get_tasks; // = taskgraph list
141
- next_task; // = taskgraph next
142
- get_task; // = taskgraph show <id>
143
- set_task_status; // = taskgraph set-status
144
-
145
- // Task management
146
- add_task; // = taskgraph add-task
147
- expand_task; // = taskgraph expand
148
- update_task; // = taskgraph update-task
149
- update_subtask; // = taskgraph update-subtask
150
- update; // = taskgraph update
151
-
152
- // Analysis
153
- analyze_project_complexity; // = taskgraph analyze-complexity
154
- complexity_report; // = taskgraph complexity-report
155
- ```
156
-
157
- ## Claude Code Workflow Integration
158
-
159
- ### Standard Development Workflow
160
-
161
- #### 1. Project Initialization
162
-
163
- ```bash
164
- # Initialize TaskGraph
165
- taskgraph init
166
-
167
- # Create or obtain PRD, then parse it (use .md extension for better editor support)
168
- taskgraph parse-prd .taskgraph/docs/prd.md
169
-
170
- # Analyze complexity and expand tasks
171
- taskgraph analyze-complexity --research
172
- taskgraph expand --all --research
173
- ```
174
-
175
- If tasks already exist, another PRD can be parsed (with new information only!) using parse-prd with --append flag. This will add the generated tasks to the existing list of tasks..
176
-
177
- #### 2. Daily Development Loop
178
-
179
- ```bash
180
- # Start each session
181
- taskgraph next # Find next available task
182
- taskgraph show <id> # Review task details
183
-
184
- # During implementation, check in code context into the tasks and subtasks
185
- taskgraph update-subtask --id=<id> --prompt="implementation notes..."
186
-
187
- # Complete tasks
188
- taskgraph set-status --id=<id> --status=done
189
- ```
190
-
191
- #### 3. Multi-Claude Workflows
192
-
193
- For complex projects, use multiple Claude Code sessions:
194
-
195
- ```bash
196
- # Terminal 1: Main implementation
197
- cd project && claude
198
-
199
- # Terminal 2: Testing and validation
200
- cd project-test-worktree && claude
201
-
202
- # Terminal 3: Documentation updates
203
- cd project-docs-worktree && claude
204
- ```
205
-
206
- ### Custom Slash Commands
207
-
208
- Create `.claude/commands/taskgraph-next.md`:
209
-
210
- ```markdown
211
- Find the next available TaskGraph task and show its details.
212
-
213
- Steps:
214
-
215
- 1. Run `taskgraph next` to get the next task
216
- 2. If a task is available, run `taskgraph show <id>` for full details
217
- 3. Provide a summary of what needs to be implemented
218
- 4. Suggest the first implementation step
219
- ```
220
-
221
- Create `.claude/commands/taskgraph-complete.md`:
222
-
223
- ```markdown
224
- Complete a TaskGraph task: $ARGUMENTS
225
-
226
- Steps:
227
-
228
- 1. Review the current task with `taskgraph show $ARGUMENTS`
229
- 2. Verify all implementation is complete
230
- 3. Run any tests related to this task
231
- 4. Mark as complete: `taskgraph set-status --id=$ARGUMENTS --status=done`
232
- 5. Show the next available task with `taskgraph next`
233
- ```
234
-
235
- ## Tool Allowlist Recommendations
236
-
237
- Add to `.claude/settings.json`:
238
-
239
- ```json
240
- {
241
- "allowedTools": [
242
- "Edit",
243
- "Bash(taskgraph *)",
244
- "Bash(git commit:*)",
245
- "Bash(git add:*)",
246
- "Bash(npm run *)",
247
- "mcp__taskgraph_ai__*"
248
- ]
249
- }
250
- ```
251
-
252
- ## Configuration & Setup
253
-
254
- ### Authentication
255
-
256
- 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.
257
-
258
- ### Model Configuration
259
-
260
- ```bash
261
- # Interactive setup (recommended)
262
- taskgraph models --setup
263
-
264
- # Set specific models
265
- taskgraph models --set-main sonnet
266
- taskgraph models --set-research opus
267
- taskgraph models --set-fallback haiku
268
- ```
269
-
270
- ## Task Structure & IDs
271
-
272
- ### Task ID Format
273
-
274
- - Main tasks: `1`, `2`, `3`, etc.
275
- - Subtasks: `1.1`, `1.2`, `2.1`, etc.
276
- - Sub-subtasks: `1.1.1`, `1.1.2`, etc.
277
-
278
- ### Task Status Values
279
-
280
- - `pending` - Ready to work on
281
- - `in-progress` - Currently being worked on
282
- - `done` - Completed and verified
283
- - `deferred` - Postponed
284
- - `cancelled` - No longer needed
285
- - `blocked` - Waiting on external factors
286
-
287
- ### Task Fields
288
-
289
- ```json
290
- {
291
- "id": "1.2",
292
- "title": "Implement user authentication",
293
- "description": "Set up JWT-based auth system",
294
- "status": "pending",
295
- "priority": "high",
296
- "dependencies": ["1.1"],
297
- "details": "Use bcrypt for hashing, JWT for tokens...",
298
- "testStrategy": "Unit tests for auth functions, integration tests for login flow",
299
- "subtasks": []
300
- }
301
- ```
302
-
303
- ## Claude Code Best Practices with TaskGraph
304
-
305
- ### Context Management
306
-
307
- - Use `/clear` between different tasks to maintain focus
308
- - This CLAUDE.md file is automatically loaded for context
309
- - Use `taskgraph show <id>` to pull specific task context when needed
310
-
311
- ### Iterative Implementation
312
-
313
- 1. `taskgraph show <subtask-id>` - Understand requirements
314
- 2. Explore codebase and plan implementation
315
- 3. `taskgraph update-subtask --id=<id> --prompt="detailed plan"` - Log plan
316
- 4. `taskgraph set-status --id=<id> --status=in-progress` - Start work
317
- 5. Implement code following logged plan
318
- 6. `taskgraph update-subtask --id=<id> --prompt="what worked/didn't work"` - Log progress
319
- 7. `taskgraph set-status --id=<id> --status=done` - Complete task
320
-
321
- ### Complex Workflows with Checklists
322
-
323
- For large migrations or multi-step processes:
324
-
325
- 1. Create a markdown PRD file describing the new changes: `touch task-migration-checklist.md` (prds can be .txt or .md)
326
- 2. Use TaskGraph to parse the new prd with `taskgraph parse-prd --append` (also available in MCP)
327
- 3. Use TaskGraph to expand the newly generated tasks into subtasks. Consdier using `analyze-complexity` with the correct --to and --from IDs (the new ids) to identify the ideal subtask amounts for each task. Then expand them.
328
- 4. Work through items systematically, checking them off as completed
329
- 5. Use `taskgraph update-subtask` to log progress on each task/subtask and/or updating/researching them before/during implementation if getting stuck
330
-
331
- ### Git Integration
332
-
333
- TaskGraph works well with `gh` CLI:
334
-
335
- ```bash
336
- # Create PR for completed task
337
- gh pr create --title "Complete task 1.2: User authentication" --body "Implements JWT auth system as specified in task 1.2"
338
-
339
- # Reference task in commits
340
- git commit -m "feat: implement JWT auth (task 1.2)"
341
- ```
342
-
343
- ### Parallel Development with Git Worktrees
344
-
345
- ```bash
346
- # Create worktrees for parallel task development
347
- git worktree add ../project-auth feature/auth-system
348
- git worktree add ../project-api feature/api-refactor
349
-
350
- # Run Claude Code in each worktree
351
- cd ../project-auth && claude # Terminal 1: Auth work
352
- cd ../project-api && claude # Terminal 2: API work
353
- ```
354
-
355
- ## Troubleshooting
356
-
357
- ### AI Commands Failing
358
-
359
- ```bash
360
- # Make sure Claude Code is installed and signed in
361
- claude --version
362
-
363
- # Verify model configuration
364
- taskgraph models
365
-
366
- # Test with different model
367
- taskgraph models --set-fallback haiku
368
- ```
369
-
370
- ### MCP Connection Issues (only if you use MCP)
371
-
372
- - Check `.mcp.json` configuration
373
- - Verify Node.js installation
374
- - Use `--mcp-debug` flag when starting Claude Code
375
- - Slash commands and the CLI work without MCP; use them if the server will not connect
376
-
377
- ### Task File Sync Issues
378
-
379
- ```bash
380
- # Regenerate task files from tasks.json
381
- taskgraph generate
382
-
383
- # Fix dependency issues
384
- taskgraph fix-dependencies
385
- ```
386
-
387
- DO NOT RE-INITIALIZE. That will not do anything beyond re-adding the same TaskGraph core files.
388
-
389
- ## Important Notes
390
-
391
- ### AI-Powered Operations
392
-
393
- These commands make AI calls and may take up to a minute:
394
-
395
- - `parse_prd` / `taskgraph parse-prd`
396
- - `analyze_project_complexity` / `taskgraph analyze-complexity`
397
- - `expand_task` / `taskgraph expand`
398
- - `expand_all` / `taskgraph expand --all`
399
- - `add_task` / `taskgraph add-task`
400
- - `update` / `taskgraph update`
401
- - `update_task` / `taskgraph update-task`
402
- - `update_subtask` / `taskgraph update-subtask`
403
-
404
- ### File Management
405
-
406
- - Never manually edit `tasks.json` - use commands instead
407
- - Never manually edit `.taskgraph/config.json` - use `taskgraph models`
408
- - Task markdown files in `tasks/` are auto-generated
409
- - Run `taskgraph generate` after manual changes to tasks.json
410
-
411
- ### Claude Code Session Management
412
-
413
- - Use `/clear` frequently to maintain focused context
414
- - Create custom slash commands for repeated TaskGraph workflows
415
- - Configure tool allowlist to streamline permissions
416
- - Use headless mode for automation: `claude -p "taskgraph next"`
417
-
418
- ### Multi-Task Updates
419
-
420
- - Use `update --from=<id>` to update multiple future tasks
421
- - Use `update-task --id=<id>` for single task updates
422
- - Use `update-subtask --id=<id>` for implementation logging
423
-
424
- ### Research Mode
425
-
426
- - Add `--research` flag for research-based AI enhancement
427
- - The research role has web search and fetch only; it cannot read or change your files
428
- - Provides more informed task creation and updates
429
- - Recommended for complex technical tasks
430
-
431
- ---
432
-
433
- _This guide ensures Claude Code has immediate access to TaskGraph's essential functionality for agentic development workflows._
13
+ Statuses: pending, in-progress, review, done, deferred, cancelled, blocked. Subtask IDs have one dot (`3.2`). Change tasks through the commands, not by editing `.taskgraph/tasks/tasks.json`. `taskgraph --help` lists the rest.