taskgraph-ai 0.0.0-stage → 0.50.1
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/CHANGELOG.md +4078 -0
- package/LICENSE +26 -0
- package/README-upstream.md +648 -0
- package/README.md +235 -2
- package/dist/ai-services-unified-DbjBfAvG.js +3 -0
- package/dist/ai-services-unified-TeIK2DoX.js +1 -0
- package/dist/assets/AGENTS.md +453 -0
- package/dist/assets/claude/TM_COMMANDS_GUIDE.md +147 -0
- package/dist/assets/config.json +31 -0
- package/dist/assets/env.example +6 -0
- package/dist/assets/example_prd.txt +47 -0
- package/dist/assets/example_prd_rpg.txt +511 -0
- package/dist/assets/gitignore +25 -0
- package/dist/assets/scripts_README.md +445 -0
- package/dist/commands-2aOf3ERj.js +230 -0
- package/dist/config-manager-C8-BTReQ.js +1 -0
- package/dist/config-manager-Da0wEujO.js +1 -0
- package/dist/dependency-manager-DIbDdrUV.js +964 -0
- package/dist/git-utils-BFUgMf2g.js +1 -0
- package/dist/git-utils-CrYiSKu0.js +1 -0
- package/dist/init-CNSqtmPC.js +3460 -0
- package/dist/mcp-server.js +13 -0
- package/dist/research-CUiuqEKk.js +1 -0
- package/dist/response-language-CGnha79j.js +1 -0
- package/dist/response-language-Cc70IGmg.js +1 -0
- package/dist/src-lvp18X-h.js +203 -0
- package/dist/tag-management-B5XoFcUP.js +1 -0
- package/dist/task-manager-BKqm9QPb.js +1 -0
- package/dist/taskgraph.js +2 -0
- package/dist/update-subtask-by-id-Ct9TTTgG.js +1 -0
- package/dist/update-task-by-id-BvdEKXsG.js +1 -0
- package/dist/utils-D1-Eo-6k.js +1 -0
- package/index.js +157 -0
- package/package.json +156 -5
package/README.md
CHANGED
|
@@ -1,3 +1,236 @@
|
|
|
1
|
-
|
|
1
|
+
<a name="readme-top"></a>
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
<p align="center">
|
|
4
|
+
<picture>
|
|
5
|
+
<source media="(prefers-color-scheme: dark)" srcset="./images/taskgraph-logo-dark.png">
|
|
6
|
+
<img src="./images/taskgraph-logo.png" alt="TaskGraph logo" width="640">
|
|
7
|
+
</picture>
|
|
8
|
+
</p>
|
|
9
|
+
|
|
10
|
+
<p align="center">
|
|
11
|
+
<b>TaskGraph</b>: task management for AI-driven development, built for Claude Code.
|
|
12
|
+
</p>
|
|
13
|
+
|
|
14
|
+
<p align="center">
|
|
15
|
+
<a href="https://github.com/stephennmiller/taskgraph-ai/actions/workflows/ci.yml"><img src="https://github.com/stephennmiller/taskgraph-ai/actions/workflows/ci.yml/badge.svg" alt="CI"></a>
|
|
16
|
+
<a href="LICENSE"><img src="https://img.shields.io/badge/license-MIT%20with%20Commons%20Clause-blue.svg" alt="License"></a>
|
|
17
|
+
</p>
|
|
18
|
+
|
|
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
|
+
|
|
21
|
+
- **Plan from a PRD:** generate tasks and subtasks, with dependencies, priorities and test strategies.
|
|
22
|
+
- **Always know what's next:** `next` picks the first unblocked task.
|
|
23
|
+
- **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
|
+
- **No API keys:** every AI call runs through your signed-in Claude Code.
|
|
25
|
+
|
|
26
|
+
> **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.
|
|
27
|
+
|
|
28
|
+
## Contents
|
|
29
|
+
|
|
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)
|
|
31
|
+
|
|
32
|
+
## Set up in Claude Code
|
|
33
|
+
|
|
34
|
+
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.
|
|
35
|
+
|
|
36
|
+
### 1. Install
|
|
37
|
+
|
|
38
|
+
```bash
|
|
39
|
+
npm install -g taskgraph-ai
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
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).
|
|
43
|
+
|
|
44
|
+
### 2. Initialize your project
|
|
45
|
+
|
|
46
|
+
From your own project folder:
|
|
47
|
+
|
|
48
|
+
```bash
|
|
49
|
+
taskgraph init --rules claude
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
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.
|
|
53
|
+
|
|
54
|
+
`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.
|
|
55
|
+
|
|
56
|
+
### 3. (Optional) Install the plugin
|
|
57
|
+
|
|
58
|
+
The plugin adds a nearly identical set of 46 slash commands (as `/taskgraph:<name>`) and three agents (`task-orchestrator`, `task-executor`, `task-checker`).
|
|
59
|
+
|
|
60
|
+
```txt
|
|
61
|
+
/plugin marketplace add stephennmiller/taskgraph-ai
|
|
62
|
+
/plugin install taskgraph@taskgraph
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
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.
|
|
66
|
+
|
|
67
|
+
### 4. (Optional) Add the MCP server
|
|
68
|
+
|
|
69
|
+
Skip this unless you want to drive TaskGraph in plain language. Slash commands and the CLI do everything without it.
|
|
70
|
+
|
|
71
|
+
```bash
|
|
72
|
+
claude mcp add taskgraph-ai --scope user \
|
|
73
|
+
--env TASKGRAPH_TOOLS=standard \
|
|
74
|
+
-- npx -y taskgraph-ai
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
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.
|
|
78
|
+
|
|
79
|
+
To share the setup with your team instead, put it in the project's `.mcp.json`:
|
|
80
|
+
|
|
81
|
+
```json
|
|
82
|
+
{
|
|
83
|
+
"mcpServers": {
|
|
84
|
+
"taskgraph-ai": {
|
|
85
|
+
"command": "npx",
|
|
86
|
+
"args": ["-y", "taskgraph-ai"],
|
|
87
|
+
"env": { "TASKGRAPH_TOOLS": "standard" }
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
```
|
|
92
|
+
|
|
93
|
+
## How to use it
|
|
94
|
+
|
|
95
|
+
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.
|
|
96
|
+
|
|
97
|
+
### 1. Write a PRD
|
|
98
|
+
|
|
99
|
+
Create `.taskgraph/docs/prd.md` describing what you want to build. The more detail you give, the better the tasks. Skipping the PRD is fine for small jobs; just ask Claude to add a task.
|
|
100
|
+
|
|
101
|
+
### 2. Generate tasks
|
|
102
|
+
|
|
103
|
+
```txt
|
|
104
|
+
/tm:parse-prd .taskgraph/docs/prd.md
|
|
105
|
+
```
|
|
106
|
+
|
|
107
|
+
Then, optionally, check how big each task is and break the big ones down:
|
|
108
|
+
|
|
109
|
+
```txt
|
|
110
|
+
/tm:analyze-complexity
|
|
111
|
+
/tm:expand-all-tasks
|
|
112
|
+
```
|
|
113
|
+
|
|
114
|
+
### 3. Work through them
|
|
115
|
+
|
|
116
|
+
| Slash command | CLI | What happens |
|
|
117
|
+
|---|---|---|
|
|
118
|
+
| `/tm:next-task` | `taskgraph next` | Shows the first unblocked, pending task |
|
|
119
|
+
| `/tm:show-task 1` | `taskgraph show 1,3,5` | Full details for each task |
|
|
120
|
+
| `/tm:to-in-progress 3`, then ask Claude to implement it | `taskgraph set-status --id=3 --status=in-progress` | Claude Code does the work, guided by the task |
|
|
121
|
+
| `/tm:to-done 3` | `taskgraph set-status --id=3 --status=done` | Updates status and unlocks dependent tasks |
|
|
122
|
+
| `/tm:expand-task 4` | `taskgraph expand --id=4` | Splits it into subtasks |
|
|
123
|
+
| `/tm:add-task <what you want>` | `taskgraph add-task --prompt="..."` | Creates a task with AI help |
|
|
124
|
+
| `/tm:update-task 5 we now use Postgres` | `taskgraph update-task --id=5 --prompt="..."` | Rewrites it for the new direction |
|
|
125
|
+
| (CLI only) | `taskgraph research "JWT best practices"` | Web research with project context |
|
|
126
|
+
|
|
127
|
+
The loop is simple: **next, implement, done, next.** Task IDs look like `3` for a task and `3.2` for a subtask.
|
|
128
|
+
|
|
129
|
+
If you use the MCP server instead, research, tags and the dependency tools are only loaded with `TASKGRAPH_TOOLS=all` (see [MCP tool tiers](#mcp-tool-tiers)); everything else here works with `standard`.
|
|
130
|
+
|
|
131
|
+
### 4. Keep it organized
|
|
132
|
+
|
|
133
|
+
- **Tags** keep separate task lists per branch, feature or experiment: `taskgraph tags`, `taskgraph tags add`, `taskgraph tags use` (MCP: `list_tags`, `add_tag`, `use_tag`).
|
|
134
|
+
- **Dependencies** decide what counts as "next". Run `/tm:validate-dependencies` or `/tm:fix-dependencies` if the graph looks wrong.
|
|
135
|
+
- **Statuses:** `pending`, `in-progress`, `done`, `review`, `deferred`, `cancelled`.
|
|
136
|
+
|
|
137
|
+
## Commands
|
|
138
|
+
|
|
139
|
+
Slash commands and the `taskgraph` CLI cover everything. The MCP server (optional) lets you do the same in plain language.
|
|
140
|
+
|
|
141
|
+
### Slash commands
|
|
142
|
+
|
|
143
|
+
After `taskgraph init --rules claude` they appear as `/tm:<name>` (type `/tm` to see them). The plugin provides the same set as `/taskgraph:<name>`.
|
|
144
|
+
|
|
145
|
+
| Purpose | Commands |
|
|
146
|
+
|---|---|
|
|
147
|
+
| Set up | `init-project`, `init-project-quick`, `install-taskgraph`, `setup-models`, `view-models` |
|
|
148
|
+
| Plan | `parse-prd`, `parse-prd-with-research`, `analyze-complexity`, `complexity-report`, `analyze-project` |
|
|
149
|
+
| See | `list-tasks`, `list-tasks-by-status`, `list-tasks-with-subtasks`, `next-task`, `show-task`, `project-status` |
|
|
150
|
+
| Change status | `to-pending`, `to-in-progress`, `to-done`, `to-review`, `to-deferred`, `to-cancelled` |
|
|
151
|
+
| Edit | `add-task`, `update-task`, `update-single-task`, `update-tasks-from-id`, `remove-task`, `convert-task-to-subtask` |
|
|
152
|
+
| Subtasks | `expand-task`, `expand-all-tasks`, `add-subtask`, `remove-subtask`, `remove-subtasks`, `remove-all-subtasks` |
|
|
153
|
+
| Dependencies | `add-dependency`, `remove-dependency`, `validate-dependencies`, `fix-dependencies` |
|
|
154
|
+
| Workflows | `smart-workflow`, `command-pipeline`, `auto-implement-tasks`, `sync-readme`, `learn`, `help` |
|
|
155
|
+
|
|
156
|
+
### CLI cheat sheet
|
|
157
|
+
|
|
158
|
+
```bash
|
|
159
|
+
taskgraph parse-prd .taskgraph/docs/prd.md # generate tasks from a PRD
|
|
160
|
+
taskgraph list # all tasks and their status
|
|
161
|
+
taskgraph next # next task to work on
|
|
162
|
+
taskgraph show 1,3,5 # one or more tasks
|
|
163
|
+
taskgraph set-status --id=3 --status=done # change status
|
|
164
|
+
taskgraph add-task --prompt="..." --research # add a task
|
|
165
|
+
taskgraph expand --id=4 --research # split into subtasks
|
|
166
|
+
taskgraph expand --all # expand every eligible task
|
|
167
|
+
taskgraph update-task --id=5 --prompt="..." # change one task
|
|
168
|
+
taskgraph update --from=5 --prompt="..." # change task 5 onward
|
|
169
|
+
taskgraph update-subtask --id=3.2 --prompt="notes"
|
|
170
|
+
taskgraph analyze-complexity --research
|
|
171
|
+
taskgraph complexity-report
|
|
172
|
+
taskgraph add-dependency --id=5 --depends-on=3
|
|
173
|
+
taskgraph validate-dependencies
|
|
174
|
+
taskgraph move --from=5 --from-tag=backlog --to-tag=in-progress
|
|
175
|
+
taskgraph research "latest JWT best practices"
|
|
176
|
+
taskgraph models --setup # choose models
|
|
177
|
+
```
|
|
178
|
+
|
|
179
|
+
Every command, flag and example is in the [command reference](docs/command-reference.md).
|
|
180
|
+
|
|
181
|
+
## MCP tool tiers
|
|
182
|
+
|
|
183
|
+
Only relevant if you added the optional MCP server. Each tool you load costs context. `TASKGRAPH_TOOLS` controls how many are registered. If it's unset, you get `core`.
|
|
184
|
+
|
|
185
|
+
| Value | Tools | Includes |
|
|
186
|
+
|---|---|---|
|
|
187
|
+
| `core` (default, alias `lean`) | 7 | `get_tasks`, `next_task`, `get_task`, `set_task_status`, `update_subtask`, `parse_prd`, `expand_task` |
|
|
188
|
+
| `standard` | 14 | core, plus `initialize_project`, `analyze_project_complexity`, `expand_all`, `add_subtask`, `remove_task`, `add_task`, `complexity_report` |
|
|
189
|
+
| `all` | 43 | everything: updates, dependencies, tags, `research`, `move_task`, `scope_up_task`, `scope_down_task`, `generate`, and the `autopilot_*` TDD workflow |
|
|
190
|
+
| a list | custom | e.g. `get_tasks,next_task,set_task_status` |
|
|
191
|
+
|
|
192
|
+
Set it when you add the server:
|
|
193
|
+
|
|
194
|
+
```bash
|
|
195
|
+
claude mcp add taskgraph-ai --scope user \
|
|
196
|
+
--env TASKGRAPH_TOOLS=all \
|
|
197
|
+
-- npx -y taskgraph-ai
|
|
198
|
+
```
|
|
199
|
+
|
|
200
|
+
Or edit the `env` block in `.mcp.json`, then restart Claude Code.
|
|
201
|
+
|
|
202
|
+
## Models
|
|
203
|
+
|
|
204
|
+
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.
|
|
205
|
+
|
|
206
|
+
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).
|
|
207
|
+
|
|
208
|
+
## Troubleshooting
|
|
209
|
+
|
|
210
|
+
- **`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).
|
|
211
|
+
- **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.
|
|
212
|
+
- **AI commands fail:** run `claude` once and make sure you're signed in.
|
|
213
|
+
- **Fewer tools than expected:** `TASKGRAPH_TOOLS` defaults to `core`. Set `standard` or `all`.
|
|
214
|
+
- **Commands behave oddly after `git pull`:** run `npm run build` again; the CLI and server run from `dist/`.
|
|
215
|
+
- **Task files look out of sync:** run `taskgraph fix-dependencies`, or ask Claude to fix dependencies.
|
|
216
|
+
- Don't hand-edit `.taskgraph/tasks/tasks.json` or `.taskgraph/config.json`; use the commands.
|
|
217
|
+
|
|
218
|
+
## Documentation
|
|
219
|
+
|
|
220
|
+
[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)
|
|
221
|
+
|
|
222
|
+
## Contributors
|
|
223
|
+
|
|
224
|
+
<a href="https://github.com/stephennmiller/taskgraph-ai/graphs/contributors">
|
|
225
|
+
<img src="https://contrib.rocks/image?repo=stephennmiller/taskgraph-ai" alt="TaskGraph project contributors" />
|
|
226
|
+
</a>
|
|
227
|
+
|
|
228
|
+
## Licensing
|
|
229
|
+
|
|
230
|
+
TaskGraph is licensed under the MIT License with Commons Clause, the same license as Task Master.
|
|
231
|
+
|
|
232
|
+
**Allowed:** use it for any purpose (personal, commercial, academic), modify it, distribute copies, and sell products built with it.
|
|
233
|
+
|
|
234
|
+
**Not allowed:** selling TaskGraph itself, offering it as a hosted service, or creating competing products based on it.
|
|
235
|
+
|
|
236
|
+
See [LICENSE](LICENSE) and [licensing details](docs/licensing.md).
|
|
@@ -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-Da0wEujO.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
|
+
|
|
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};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{a as e,i as t,n,r,t as i}from"./ai-services-unified-DbjBfAvG.js";import"./src-lvp18X-h.js";import"./config-manager-Da0wEujO.js";import"./git-utils-CrYiSKu0.js";export{i as generateObjectService,n as generateTextService,r as logAiUsage,t as streamObjectService,e as streamTextService};
|