taskgraph-ai 0.49.1 → 0.52.6
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 +76 -32
- package/dist/ai-services-unified-BbSRBK0N.js +3 -0
- package/dist/ai-services-unified-CQMZv2X-.js +1 -0
- package/dist/assets/AGENTS.md +12 -31
- package/dist/assets/example_prd_rpg.txt +1 -4
- package/dist/assets/scripts_README.md +12 -14
- package/dist/commands-DOZyxFfM.js +231 -0
- package/dist/config-manager-BsUS_HoV.js +1 -0
- package/dist/config-manager-CKzRb4tZ.js +1 -0
- package/dist/dependency-manager-BcQJdp1Y.js +971 -0
- package/dist/git-utils--i2q96hv.js +1 -0
- package/dist/git-utils-BezpEZd4.js +1 -0
- package/dist/{init-wtXaFE45.js → init-S96FNSm7.js} +65 -389
- package/dist/mcp-server.js +6 -6
- package/dist/research-cdWIHSpn.js +1 -0
- package/dist/response-language-Bjbf2_9z.js +1 -0
- package/dist/{response-language-BHhde6n_.js → response-language-Ln6H6G2z.js} +1 -1
- package/dist/src-Cio2Sps9.js +207 -0
- package/dist/tag-management-BzAE-dVv.js +1 -0
- package/dist/task-manager-Utma-ZPy.js +1 -0
- package/dist/taskgraph.js +1 -1
- package/dist/update-subtask-by-id-UcjCRJbf.js +1 -0
- package/dist/update-task-by-id-98Q5zy74.js +1 -0
- package/dist/utils-BzS6gmZZ.js +1 -0
- package/package.json +16 -30
- package/dist/ai-services-unified--6CT6QUI.js +0 -1
- package/dist/ai-services-unified-D8PahWkz.js +0 -3
- package/dist/commands-CceFmRJA.js +0 -230
- package/dist/config-manager-CvDCaURh.js +0 -1
- package/dist/config-manager-DD5sEcpv.js +0 -270
- package/dist/dependency-manager-B7SaMC6u.js +0 -966
- package/dist/git-utils-DllbRE35.js +0 -1
- package/dist/git-utils-PBP1PRVP.js +0 -1
- package/dist/research-BRpAIbWg.js +0 -1
- package/dist/response-language-Dz-rFnaJ.js +0 -1
- package/dist/sentry-DNoFrfjb.js +0 -1
- package/dist/tag-management-BEKnBGXA.js +0 -1
- package/dist/task-manager-BQkOlw_W.js +0 -1
- package/dist/update-subtask-by-id-BOFRADbR.js +0 -1
- package/dist/update-task-by-id-DTHqRii_.js +0 -1
- package/dist/utils-DYpucGVy.js +0 -1
package/README.md
CHANGED
|
@@ -18,55 +18,81 @@
|
|
|
18
18
|
|
|
19
19
|
TaskGraph turns a product requirements document (PRD) into a dependency-aware task list, then walks Claude Code through it one task at a time. You describe what to build, TaskGraph plans the work, and Claude Code implements it, with the plan and progress stored in your repo.
|
|
20
20
|
|
|
21
|
+
<p align="center">
|
|
22
|
+
<img src="images/taskgraph-flow.svg" alt="Eight tasks from scaffold to launch. Each unlocks when its dependencies are done, and taskgraph next always points at the next unblocked task." width="720">
|
|
23
|
+
</p>
|
|
24
|
+
|
|
21
25
|
- **Plan from a PRD:** generate tasks and subtasks, with dependencies, priorities and test strategies.
|
|
22
26
|
- **Always know what's next:** `next` picks the first unblocked task.
|
|
23
27
|
- **Stay in Claude Code:** use slash commands (`/tm:next-task`) or the `taskgraph` CLI. An MCP server is available if you want plain-language control, but it is optional.
|
|
24
28
|
- **No API keys:** every AI call runs through your signed-in Claude Code.
|
|
25
29
|
|
|
26
|
-
>
|
|
30
|
+
<p align="center">
|
|
31
|
+
<a href="images/demo/03-pick-up-where-you-left-off.mp4"><img src="images/demo/03-pick-up-where-you-left-off.svg" alt="A new Claude Code session running /tm:next-task and resuming from the notes logged last time" width="820"></a>
|
|
32
|
+
<br>
|
|
33
|
+
<sub>3. Pick up where you left off · <a href="images/demo/03-pick-up-where-you-left-off.mp4">MP4</a></sub>
|
|
34
|
+
</p>
|
|
35
|
+
|
|
36
|
+
<details>
|
|
37
|
+
<summary><b>See the full workflow</b> (4 short clips)</summary>
|
|
38
|
+
|
|
39
|
+
<p align="center">
|
|
40
|
+
<a href="images/demo/01-setup.mp4"><img src="images/demo/01-setup.svg" alt="Running taskgraph init --rules claude in a project" width="820"></a>
|
|
41
|
+
<br>
|
|
42
|
+
<sub>1. Set it up in your project · <a href="images/demo/01-setup.mp4">MP4</a></sub>
|
|
43
|
+
</p>
|
|
44
|
+
|
|
45
|
+
<p align="center">
|
|
46
|
+
<a href="images/demo/02-prd-to-tasks.mp4"><img src="images/demo/02-prd-to-tasks.svg" alt="Claude Code running /tm:parse-prd to turn a PRD into 8 dependent tasks" width="820"></a>
|
|
47
|
+
<br>
|
|
48
|
+
<sub>2. Turn your PRD into a plan · <a href="images/demo/02-prd-to-tasks.mp4">MP4</a></sub>
|
|
49
|
+
</p>
|
|
50
|
+
|
|
51
|
+
<p align="center">
|
|
52
|
+
<a href="images/demo/03-pick-up-where-you-left-off.mp4"><img src="images/demo/03-pick-up-where-you-left-off.svg" alt="A new Claude Code session running /tm:next-task and resuming from the notes logged last time" width="820"></a>
|
|
53
|
+
<br>
|
|
54
|
+
<sub>3. Pick up where you left off · <a href="images/demo/03-pick-up-where-you-left-off.mp4">MP4</a></sub>
|
|
55
|
+
</p>
|
|
56
|
+
|
|
57
|
+
<p align="center">
|
|
58
|
+
<a href="images/demo/04-terminal.mp4"><img src="images/demo/04-terminal.svg" alt="The taskgraph list dashboard and task table in a terminal" width="820"></a>
|
|
59
|
+
<br>
|
|
60
|
+
<sub>4. Or drive it from your terminal · <a href="images/demo/04-terminal.mp4">MP4</a></sub>
|
|
61
|
+
</p>
|
|
62
|
+
|
|
63
|
+
</details>
|
|
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)). Coming from Task Master or a release before 0.47? See [Upgrading](#upgrading).
|
|
27
66
|
|
|
28
67
|
## Contents
|
|
29
68
|
|
|
30
|
-
[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)
|
|
31
70
|
|
|
32
71
|
## Set up in Claude Code
|
|
33
72
|
|
|
34
|
-
> **Install from source for now.** `taskgraph-ai` isn't published to npm yet, so `npx -y taskgraph-ai` and `npm install -g taskgraph-ai` don't work. Build it once from this repository (step 1). When the package is published, `npx -y taskgraph-ai` replaces `node /path/to/taskgraph-ai/dist/mcp-server.js` everywhere below.
|
|
35
|
-
|
|
36
73
|
You need [Claude Code](https://docs.claude.com/en/docs/claude-code) installed and signed in (run `claude` once) and Node.js 22 or later.
|
|
37
74
|
|
|
38
|
-
### 1.
|
|
75
|
+
### 1. Install
|
|
39
76
|
|
|
40
77
|
```bash
|
|
41
|
-
|
|
42
|
-
cd taskgraph-ai
|
|
43
|
-
npm install
|
|
44
|
-
npm run build
|
|
78
|
+
npm install -g taskgraph-ai
|
|
45
79
|
```
|
|
46
80
|
|
|
47
|
-
This
|
|
81
|
+
This gives you the `taskgraph` command (the CLI) and `taskgraph-mcp`, the optional MCP server. To skip the install, run any command through npx, for example `npx -y -p taskgraph-ai taskgraph list`. To build from source instead, see [Working on TaskGraph itself](#troubleshooting).
|
|
48
82
|
|
|
49
83
|
### 2. Initialize your project
|
|
50
84
|
|
|
51
85
|
From your own project folder:
|
|
52
86
|
|
|
53
87
|
```bash
|
|
54
|
-
|
|
88
|
+
taskgraph init --rules claude
|
|
55
89
|
```
|
|
56
90
|
|
|
57
91
|
This creates `.taskgraph/` (tasks, docs, config), a `CLAUDE.md` import with TaskGraph's workflow guide, and 46 slash commands in `.claude/commands/tm/`. Don't run it twice; it only re-adds the same files.
|
|
58
92
|
|
|
59
|
-
`init` also writes a `.mcp.json` that
|
|
93
|
+
`init` also writes a `.mcp.json` that registers the MCP server with the 7 `core` tools. Delete that file if you only want the slash commands and CLI; see step 4 to keep and configure the server.
|
|
60
94
|
|
|
61
|
-
### 3.
|
|
62
|
-
|
|
63
|
-
A shell alias keeps the commands in the rest of this README short:
|
|
64
|
-
|
|
65
|
-
```bash
|
|
66
|
-
alias taskgraph="node /path/to/taskgraph-ai/dist/taskgraph.js"
|
|
67
|
-
```
|
|
68
|
-
|
|
69
|
-
### 4. (Optional) Install the plugin
|
|
95
|
+
### 3. (Optional) Install the plugin
|
|
70
96
|
|
|
71
97
|
The plugin adds a nearly identical set of 46 slash commands (as `/taskgraph:<name>`) and three agents (`task-orchestrator`, `task-executor`, `task-checker`).
|
|
72
98
|
|
|
@@ -75,16 +101,16 @@ The plugin adds a nearly identical set of 46 slash commands (as `/taskgraph:<nam
|
|
|
75
101
|
/plugin install taskgraph@taskgraph
|
|
76
102
|
```
|
|
77
103
|
|
|
78
|
-
The plugin does not register an MCP server. The `task-checker` agent uses the `taskgraph show` CLI, and uses the MCP tool instead if you registered the server as `taskgraph-ai` (step
|
|
104
|
+
The plugin does not register an MCP server. The `task-checker` agent uses the `taskgraph show` CLI, and uses the MCP tool instead if you registered the server as `taskgraph-ai` (step 4). Its slash commands overlap with the ones from step 2, so install the plugin only if you want the agents.
|
|
79
105
|
|
|
80
|
-
###
|
|
106
|
+
### 4. (Optional) Add the MCP server
|
|
81
107
|
|
|
82
108
|
Skip this unless you want to drive TaskGraph in plain language. Slash commands and the CLI do everything without it.
|
|
83
109
|
|
|
84
110
|
```bash
|
|
85
111
|
claude mcp add taskgraph-ai --scope user \
|
|
86
112
|
--env TASKGRAPH_TOOLS=standard \
|
|
87
|
-
--
|
|
113
|
+
-- npx -y taskgraph-ai
|
|
88
114
|
```
|
|
89
115
|
|
|
90
116
|
Restart Claude Code and run `/mcp`; `taskgraph-ai` should show as connected. `standard` loads 14 tools, enough for everything in [How to use it](#how-to-use-it). See [MCP tool tiers](#mcp-tool-tiers) for the others.
|
|
@@ -95,8 +121,8 @@ To share the setup with your team instead, put it in the project's `.mcp.json`:
|
|
|
95
121
|
{
|
|
96
122
|
"mcpServers": {
|
|
97
123
|
"taskgraph-ai": {
|
|
98
|
-
"command": "
|
|
99
|
-
"args": ["
|
|
124
|
+
"command": "npx",
|
|
125
|
+
"args": ["-y", "taskgraph-ai"],
|
|
100
126
|
"env": { "TASKGRAPH_TOOLS": "standard" }
|
|
101
127
|
}
|
|
102
128
|
}
|
|
@@ -105,6 +131,13 @@ To share the setup with your team instead, put it in the project's `.mcp.json`:
|
|
|
105
131
|
|
|
106
132
|
## How to use it
|
|
107
133
|
|
|
134
|
+
<p align="center">
|
|
135
|
+
<picture>
|
|
136
|
+
<source media="(prefers-color-scheme: dark)" srcset="images/how-it-works-dark.svg">
|
|
137
|
+
<img src="images/how-it-works.svg" alt="parse-prd turns your PRD into a task graph stored in .taskgraph/tasks/tasks.json in your repo. Each Claude Code session reads and updates that file, so a new session picks up the next task and the notes from the last one." width="820">
|
|
138
|
+
</picture>
|
|
139
|
+
</p>
|
|
140
|
+
|
|
108
141
|
The examples below use slash commands (`/tm:...`), with the CLI equivalent in each table. If you added the optional MCP server, you can say the same things in plain language instead.
|
|
109
142
|
|
|
110
143
|
### 1. Write a PRD
|
|
@@ -189,7 +222,7 @@ taskgraph research "latest JWT best practices"
|
|
|
189
222
|
taskgraph models --setup # choose models
|
|
190
223
|
```
|
|
191
224
|
|
|
192
|
-
Every command, flag and example is in the [command reference](docs/
|
|
225
|
+
Every command, flag and example is in the [command reference](apps/docs/capabilities/cli-root-commands.mdx).
|
|
193
226
|
|
|
194
227
|
## MCP tool tiers
|
|
195
228
|
|
|
@@ -207,7 +240,7 @@ Set it when you add the server:
|
|
|
207
240
|
```bash
|
|
208
241
|
claude mcp add taskgraph-ai --scope user \
|
|
209
242
|
--env TASKGRAPH_TOOLS=all \
|
|
210
|
-
--
|
|
243
|
+
-- npx -y taskgraph-ai
|
|
211
244
|
```
|
|
212
245
|
|
|
213
246
|
Or edit the `env` block in `.mcp.json`, then restart Claude Code.
|
|
@@ -216,12 +249,23 @@ Or edit the `env` block in `.mcp.json`, then restart Claude Code.
|
|
|
216
249
|
|
|
217
250
|
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.
|
|
218
251
|
|
|
219
|
-
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/
|
|
252
|
+
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).
|
|
253
|
+
|
|
254
|
+
## Upgrading
|
|
255
|
+
|
|
256
|
+
Projects created with Task Master, or with a TaskGraph release before 0.47, need a few manual changes:
|
|
257
|
+
|
|
258
|
+
- **Rename `.taskmaster/` to `.taskgraph/`** by hand. TaskGraph no longer detects the old folder.
|
|
259
|
+
- **Rename environment variables:** `TASK_MASTER_*` and `TASKMASTER_*` are now `TASKGRAPH_*`. The old names are ignored.
|
|
260
|
+
- **Removed:** the `taskgraph migrate` command and `.taskmasterconfig`. Configuration lives in `.taskgraph/config.json`; run `taskgraph models --setup` to recreate it.
|
|
261
|
+
- **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`.
|
|
262
|
+
|
|
263
|
+
Full details are in the [upgrade guide](apps/docs/upgrading.mdx).
|
|
220
264
|
|
|
221
265
|
## Troubleshooting
|
|
222
266
|
|
|
223
|
-
- **`0 tools enabled` or the server won't connect:** restart Claude Code, run `/mcp`, and confirm `
|
|
224
|
-
- **Working on TaskGraph itself:**
|
|
267
|
+
- **`0 tools enabled` or the server won't connect:** restart Claude Code, run `/mcp`, and confirm `npx -y taskgraph-ai` starts on its own in a terminal (it waits for input; press Ctrl+C to stop).
|
|
268
|
+
- **Working on TaskGraph itself:** build from source with `git clone https://github.com/stephennmiller/taskgraph-ai.git && cd taskgraph-ai && npm install && npm run build`, then run `node dist/taskgraph.js` for the CLI. This repository's own `.mcp.json` starts `dist/mcp-server.js` relative to the repo, so run `npm run build` first or the server won't connect.
|
|
225
269
|
- **AI commands fail:** run `claude` once and make sure you're signed in.
|
|
226
270
|
- **Fewer tools than expected:** `TASKGRAPH_TOOLS` defaults to `core`. Set `standard` or `all`.
|
|
227
271
|
- **Commands behave oddly after `git pull`:** run `npm run build` again; the CLI and server run from `dist/`.
|
|
@@ -230,7 +274,7 @@ In Claude Code, say `Change the main model to opus`, or run `taskgraph models --
|
|
|
230
274
|
|
|
231
275
|
## Documentation
|
|
232
276
|
|
|
233
|
-
[Tutorial](docs/tutorial.
|
|
277
|
+
[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)
|
|
234
278
|
|
|
235
279
|
## Contributors
|
|
236
280
|
|
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
import{D as e,Q as t,S as n,b as r,d as i,h as a,i as o,j as s,lt as c,m as l,nt as u,o as d,p as f,q as p,u as m,v as h,x as g,y as _}from"./config-manager-CKzRb4tZ.js";import{createRequire as v}from"node:module";import{execSync as y}from"child_process";import{createClaudeCode as b}from"ai-sdk-provider-claude-code";import*as x from"ai";import{jsonrepair as S}from"jsonrepair";import{EnvHttpProxyAgent as C}from"undici";var w=Object.defineProperty,T=(e,t)=>{let n={};for(var r in e)w(n,r,{get:e[r],enumerable:!0});return t||w(n,Symbol.toStringTag,{value:`Module`}),n},E=/* @__PURE__ */ v(import.meta.url);const{JSONParseError:D,NoObjectGeneratedError:O,generateObject:k,generateText:A,streamObject:j,streamText:ee,zodSchema:te}=x,M=x.jsonSchema,N=/* @__PURE__ */ new Set([`minimum`,`maximum`,`exclusiveMinimum`,`exclusiveMaximum`]),P=[`additionalProperties`,`contains`,`if`,`then`,`else`,`not`,`propertyNames`],F=[`allOf`,`anyOf`,`oneOf`,`prefixItems`],I=[`definitions`,`$defs`,`dependentSchemas`,`patternProperties`,`properties`],ne=e=>e?Array.isArray(e)?e.includes(`integer`):e===`integer`:!1,L=e=>{if(!e||typeof e!=`object`)return e;if(Array.isArray(e))return e.map(L);let t={...e};if(ne(t.type))for(let e of N)e in t&&delete t[e];for(let e of P)t[e]&&(t[e]=L(t[e]));for(let e of F)Array.isArray(t[e])&&(t[e]=t[e].map(L));for(let e of I)if(t[e]&&typeof t[e]==`object`){let n={};for(let[r,i]of Object.entries(t[e]))n[r]=L(i);t[e]=n}return t.items&&=L(t.items),t},R=e=>{let t=te(e);if(!t||typeof t!=`object`||!t.jsonSchema)return t;let n=L(t.jsonSchema);return typeof M==`function`?M(n,{validate:t.validate}):{...t,jsonSchema:n}};var z=class t{constructor(){if(this.constructor===t)throw Error(`BaseAIProvider cannot be instantiated directly`);this.name=this.constructor.name,this._proxyAgent=null,this.needsExplicitJsonSchema=!1,this.supportsTemperature=!0}validateAuth(e){if(!e.apiKey)throw Error(`${this.name} API key is required`)}createProxyFetch(){this._projectRoot||=p();let t=this._projectRoot;if(e(null,t))return this._proxyAgent||=new C,(e,t={})=>fetch(e,{...t,dispatcher:this._proxyAgent})}validateParams(e){if(this.validateAuth(e),!e.modelId)throw Error(`${this.name} Model ID is required`);this.validateOptionalParams(e)}validateOptionalParams(e){if(e.temperature!==void 0&&(e.temperature<0||e.temperature>1))throw Error(`Temperature must be between 0 and 1`);if(e.maxTokens!==void 0){let t=Number(e.maxTokens);if(!Number.isFinite(t)||t<=0)throw Error(`maxTokens must be a finite number greater than 0`)}}validateMessages(e){if(!e||!Array.isArray(e)||e.length===0)throw Error(`Invalid or empty messages array provided`);for(let t of e)if(!t.role||!t.content)throw Error(`Invalid message format. Each message must have role and content`)}handleError(e,t){let n=t.message||`Unknown error occurred`;throw u(`error`,`${this.name} ${e} failed: ${n}`,{error:t}),Error(`${this.name} API error during ${e}: ${n}`)}getClient(e){throw Error(`getClient must be implemented by provider`)}isRequiredApiKey(){return!0}getRequiredApiKeyName(){throw Error(`getRequiredApiKeyName must be implemented by provider`)}prepareTokenParam(e,t){return t===void 0?{}:{maxOutputTokens:Math.floor(Number(t))}}prepareMessages(e){let t=e.filter(e=>e.role===`system`);return t.length===0?{messages:e}:{instructions:t.map(e=>typeof e.content==`string`?e.content:e.content.map(e=>e.text??``).join(``)).join(`
|
|
2
|
+
|
|
3
|
+
`),messages:e.filter(e=>e.role!==`system`)}}async generateText(e){try{this.validateParams(e),this.validateMessages(e.messages),u(`debug`,`Generating ${this.name} text with model: ${e.modelId}`);let t=await this.getClient(e),n=await A({model:t(e.modelId),...this.prepareMessages(e.messages),...this.prepareTokenParam(e.modelId,e.maxTokens),...this.supportsTemperature&&e.temperature!==void 0?{temperature:e.temperature}:{}});u(`debug`,`${this.name} generateText completed successfully for model: ${e.modelId}`);let r=n.usage?.inputTokens??n.usage?.promptTokens??0,i=n.usage?.outputTokens??n.usage?.completionTokens??0,a=n.usage?.totalTokens??r+i;return{text:n.text,usage:{inputTokens:r,outputTokens:i,totalTokens:a}}}catch(e){this.handleError(`text generation`,e)}}async streamText(e){try{this.validateParams(e),this.validateMessages(e.messages),u(`debug`,`Streaming ${this.name} text with model: ${e.modelId}`);let t=await this.getClient(e),n=await ee({model:t(e.modelId),...this.prepareMessages(e.messages),...this.prepareTokenParam(e.modelId,e.maxTokens),...this.supportsTemperature&&e.temperature!==void 0?{temperature:e.temperature}:{},...e.experimental_transform&&{experimental_transform:e.experimental_transform}});return u(`debug`,`${this.name} streamText initiated successfully for model: ${e.modelId}`),n}catch(e){this.handleError(`text streaming`,e)}}async streamObject(e){try{if(this.validateParams(e),this.validateMessages(e.messages),!e.schema)throw Error(`Schema is required for object streaming`);u(`debug`,`Streaming ${this.name} object with model: ${e.modelId}`);let t=await this.getClient(e),n=R(e.schema),r=await j({model:t(e.modelId),...this.prepareMessages(e.messages),schema:n,mode: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=/* @__PURE__ */ Error(`Claude Code CLI not available. Please install Claude Code CLI first. Original error: ${e.message}`);t.cause=e,this.handleError(`Claude Code CLI initialization`,t)}else this.handleError(`client initialization`,e)}}getSupportedModels(){return this.supportedModels}isModelSupported(e){return e?this.supportedModels.includes(String(e).toLowerCase()):!1}};let G=null;var K=class e{constructor(){this._providers=/* @__PURE__ */ new Map,this._initialized=!1}static getInstance(){return G||=new e,G}initialize(){return this._initialized||=!0,this}registerProvider(e,t,n={}){if(!e||typeof e!=`string`)throw Error(`Provider name must be a non-empty string`);if(!t)throw Error(`Provider instance is required`);if(typeof t.generateText!=`function`||typeof t.streamText!=`function`||typeof t.generateObject!=`function`)throw Error(`Provider must implement BaseAIProvider interface`);return this._providers.set(e,{instance:t,options:n,registeredAt:/* @__PURE__ */ new Date}),this}hasProvider(e){return this._providers.has(e)}getProvider(e){let t=this._providers.get(e);return t?t.instance:null}getAllProviders(){return new Map(this._providers)}unregisterProvider(e){return this._providers.has(e)?(this._providers.delete(e),!0):!1}reset(){this._providers.clear(),this._initialized=!1}};K.getInstance().initialize();const q={"claude-code":new W};function J(e){if(q[e])return q[e];let t=K.getInstance();return t.hasProvider(e)?(u(`debug`,`Provider "${e}" found in dynamic registry`),t.getProvider(e)):null}function Y(e,t){let n={inputCost:0,outputCost:0,currency:`USD`,isUnknown:!1};if(!s||!s[e])return u(`warn`,`Provider "${e}" not found in MODEL_MAP. Cannot determine cost for model ${t}.`),{...n,isUnknown:!0};let r=s[e].find(e=>e.id===t);if(!r)return u(`debug`,`Model "${t}" not found under provider "${e}". Assuming unknown cost.`),{...n,isUnknown:!0};if(r.cost_per_1m_tokens===null)return u(`debug`,`Cost data is null for model "${t}" under provider "${e}". Pricing unknown.`),{...n,isUnknown:!0};if(r.cost_per_1m_tokens===void 0)return u(`debug`,`Cost data not found for model "${t}" under provider "${e}". Pricing unknown.`),{...n,isUnknown:!0};let i=r.cost_per_1m_tokens;return{inputCost:i.input||0,outputCost:i.output||0,currency:i.currency||`USD`,isUnknown:!1}}function X(e,t,n,r){let i=(e||0)/1e6*n+(t||0)/1e6*r;return parseFloat(i.toFixed(6))}function re(e){let n={currentTag:`master`,availableTags:[`master`]};try{return e?{currentTag:t(e)||`master`,availableTags:ie(e)}:n}catch(e){return d()&&u(`debug`,`Error getting tag information: ${e.message}`),n}}function ie(e){let t=[`master`];try{let n=E(`path`),r=E(`fs`),i=n.join(e,`.taskgraph`,`tasks`,`tasks.json`);if(!r.existsSync(i))return t;let a=JSON.parse(r.readFileSync(i,`utf8`));if(!a||typeof a!=`object`)return t;let o=Object.keys(a).filter(e=>ae(a[e]));return o.length>0?o:t}catch(e){return d()&&u(`debug`,`Could not read tasks file for available tags: ${e.message}`),t}}function ae(e){return e&&typeof e==`object`&&Array.isArray(e.tasks)}function oe(e){let t=e.message?.toLowerCase()||``;return t.includes(`rate limit`)||t.includes(`overloaded`)||t.includes(`service temporarily unavailable`)||t.includes(`timeout`)||t.includes(`network error`)||e.status===429||e.status>=500}function se(e){try{if(e?.data?.error?.message)return e.data.error.message;if(e?.error?.message)return e.error.message;if(typeof e?.responseBody==`string`)try{let t=JSON.parse(e.responseBody);if(t?.error?.message)return t.error.message}catch{}return typeof e?.message==`string`&&e.message?e.message:typeof e==`string`?e:`An unknown AI service error occurred.`}catch{return`Failed to extract error message.`}}function ce(e,t){return{main:{provider:l(t),modelId:f(t)},research:{provider:_(t),modelId:h(t)},fallback:{provider:i(t),modelId:m(t)}}[e]||null}function Z(e,t,n=null){let r=J(e);if(!r)throw Error(`Unknown provider '${e}' for API key resolution.`);let i=r.getRequiredApiKeyName();if(i===null)return null;let a=c(i,t,n);if(!r.isRequiredApiKey())return a||null;if(!a)throw Error(`Required API key ${i} for provider '${e}' is not set in environment, session, or .env file.`);return a}async function le(e,t,n,r,i,a){let o=0,s=t;for(;o<=2;)try{d()&&u(`info`,`Attempt ${o+1}/3 calling ${s} (Provider: ${r}, Model: ${i}, Role: ${a})`);let c=await e[t](n);return d()&&u(`info`,`${s} succeeded for role ${a} (Provider: ${r}) on attempt ${o+1}`),c}catch(e){if(u(`warn`,`Attempt ${o+1} failed for role ${a} (${s} / ${r}): ${e.message}`),oe(e)&&o<2){o++;let e=1e3*2**(o-1);u(`info`,`Something went wrong on the provider side. Retrying in ${e/1e3}s...`),await new Promise(t=>setTimeout(t,e))}else throw u(`error`,`Something went wrong on the provider side. Max retries reached for role ${a} (${s} / ${r}).`),e}throw Error(`Exhausted all retries for role ${a} (${s} / ${r})`)}async function Q(e,t){let{role:i,session:o,projectRoot:s,systemPrompt:c,prompt:l,schema:f,objectName:m,commandName:h,outputType:g,experimental_transform:_,...v}=t;d()&&u(`info`,`${e}Service called`,{role:i,commandName:h,outputType:g,projectRoot:s});let y=s||p(),b=n(y),x;i===`main`?x=[`main`,`fallback`,`research`]:i===`research`?x=[`research`,`fallback`,`main`]:i===`fallback`?x=[`fallback`,`main`,`research`]:(u(`warn`,`Unknown initial role: ${i}. Defaulting to main -> fallback -> research sequence.`),x=[`main`,`fallback`,`research`]);let S=/* @__PURE__ */ new Set,C=null,w=`AI service call failed for all configured roles.`;for(let t of x){let n,i,s,d,p,x,T=null;try{u(`debug`,`New AI service call with role: ${t}`);let w=ce(t,y);if(!w){u(`error`,`Unknown role encountered in _unifiedServiceRunner: ${t}`),C||=/* @__PURE__ */ Error(`Unknown AI role specified: ${t}`);continue}if(n=w.provider,i=w.modelId,!n||!i){u(`warn`,`Skipping role '${t}': Provider or Model ID not configured.`),C||=/* @__PURE__ */ Error(`Configuration missing for role '${t}'. Provider: ${n}, Model: ${i}`);continue}if(S.has(`${n}/${i}`)){u(`debug`,`Skipping role '${t}': ${n}/${i} already failed for this request.`);continue}if(p=J(n?.toLowerCase()),!p){u(`warn`,`Skipping role '${t}': Provider '${n}' not supported.`),C||=/* @__PURE__ */ Error(`Unsupported provider configured: ${n}`);continue}d=a(t,y),s=Z(n?.toLowerCase(),o,y);let E=[],D=`${c} \n\n Always respond in ${r(y)}.`;if(E.push({role:`system`,content:D.trim()}),l)E.push({role:`user`,content:l});else throw Error(`User prompt content is missing.`);let O={apiKey:s,modelId:i,maxTokens:d.maxTokens,temperature:d.temperature,messages:E,...(e===`generateObject`||e===`streamObject`)&&{schema:f,objectName:m},role:t,...h&&{commandName:h},..._&&{experimental_transform:_},...v};if(x=await le(p,e,O,n,i,t),b&&x&&x.usage)try{T=await $({userId:b,commandName:h,providerName:n,modelId:i,inputTokens:x.usage.inputTokens,outputTokens:x.usage.outputTokens,outputType:g})}catch{}else b&&x&&!x.usage&&u(`warn`,`Cannot log telemetry for ${h} (${n}/${i}): AI result missing 'usage' data. (May be expected for streams)`);let k;e===`generateText`?k=x.text:e===`generateObject`?k=x.object:(e===`streamText`||e===`streamObject`||u(`error`,`Unknown serviceType in _unifiedServiceRunner: ${e}`),k=x);let A=re(y);return{mainResult:k,telemetryData:T,tagInfo:A,providerName:n,modelId:i}}catch(r){let a=se(r);if(u(`error`,`Service call failed for role ${t} (Provider: ${n||`unknown`}, Model: ${i||`unknown`}): ${a}`),C=r,w=a,n&&i&&S.add(`${n}/${i}`),e===`generateObject`){let e=a.toLowerCase();if(e.includes(`no endpoints found that support tool use`)||e.includes(`does not support tool_use`)||e.includes(`tool use is not supported`)||e.includes(`tools are not supported`)||e.includes(`function calling is not supported`)||e.includes(`tool use is not supported`)){let e=`Model '${i||`unknown`}' via provider '${n||`unknown`}' does not support the 'tool use' required by generateObjectService. Please configure a model that supports tool/function calling for the '${t}' role, or use generateTextService if structured output is not strictly required.`;throw u(`error`,`[Tool Support Error] ${e}`),Error(e)}}}}throw u(`error`,`All roles in the sequence [${x.join(`, `)}] failed.`),Error(w)}async function ue(e){return Q(`generateText`,{outputType:`cli`,...e})}async function de(e){return Q(`streamText`,{outputType:`cli`,...e})}async function fe(e){let t={outputType:`cli`,...e};if(!t.schema)throw Error(`streamObjectService requires a schema parameter`);return Q(`streamObject`,t)}async function pe(e){return Q(`generateObject`,{objectName:`generated_object`,maxRetries:3,outputType:`cli`,...e})}async function $({userId:e,commandName:t,providerName:n,modelId:r,inputTokens:i,outputTokens:a,outputType:o}){try{let o=(/* @__PURE__ */ new Date()).toISOString(),s=(i||0)+(a||0),{inputCost:c,outputCost:l,currency:f,isUnknown:p}=Y(n,r),m=X(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{de as a,fe as i,ue as n,T as o,$ as r,pe as t};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export{r as logAiUsage}from"./ai-services-unified-BbSRBK0N.js";
|
package/dist/assets/AGENTS.md
CHANGED
|
@@ -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` -
|
|
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 #
|
|
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
|
-
###
|
|
255
|
+
### Authentication
|
|
265
256
|
|
|
266
|
-
|
|
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
|
|
286
|
-
taskgraph models --set-research
|
|
287
|
-
taskgraph models --set-fallback
|
|
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
|
-
#
|
|
381
|
-
|
|
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
|
|
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
|
-
-
|
|
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
|
|
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
|
|
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 (
|
|
30
|
-
-
|
|
31
|
-
-
|
|
32
|
-
- See
|
|
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
|
|
163
|
+
# Use the research model for research-backed subtask generation
|
|
164
164
|
taskgraph expand --id=3 --research
|
|
165
165
|
|
|
166
|
-
# Use
|
|
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 (
|
|
196
|
-
- API keys are
|
|
197
|
-
- To use the research capabilities (
|
|
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
|
|
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
|
|
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`
|