Compare commits

..

2 Commits

Author SHA1 Message Date
Ralph Khreish
ea23e756f6 chore: fix format 2025-08-02 23:23:57 +03:00
Ralph Khreish
dc992a85ea chore: exit pre 2025-08-02 23:21:21 +03:00
33 changed files with 180 additions and 855 deletions

View File

@@ -0,0 +1,5 @@
---
"task-master-ai": patch
---
Fix for tasks not found when using string IDs

View File

@@ -0,0 +1,7 @@
---
"task-master-ai": patch
---
Fix tag-specific complexity report detection in expand command
The expand command now correctly finds and uses tag-specific complexity reports (e.g., `task-complexity-report_feature-xyz.json`) when operating in a tag context. Previously, it would always look for the generic `task-complexity-report.json` file due to a default value in the CLI option definition.

View File

@@ -0,0 +1,38 @@
---
"task-master-ai": minor
---
Add new `scope-up` and `scope-down` commands for dynamic task complexity adjustment
This release introduces two powerful new commands that allow you to dynamically adjust the complexity of your tasks and subtasks without recreating them from scratch.
**New CLI Commands:**
- `task-master scope-up` - Increase task complexity (add more detail, requirements, or implementation steps)
- `task-master scope-down` - Decrease task complexity (simplify, remove unnecessary details, or streamline)
**Key Features:**
- **Multiple tasks**: Support comma-separated IDs to adjust multiple tasks at once (`--id=5,7,12`)
- **Strength levels**: Choose adjustment intensity with `--strength=light|regular|heavy` (defaults to regular)
- **Custom prompts**: Use `--prompt` flag to specify exactly how you want tasks adjusted
- **MCP integration**: Available as `scope_up_task` and `scope_down_task` tools in Cursor and other MCP environments
- **Smart context**: AI considers your project context and task dependencies when making adjustments
**Usage Examples:**
```bash
# Make a task more detailed
task-master scope-up --id=5
# Simplify multiple tasks with light touch
task-master scope-down --id=10,11,12 --strength=light
# Custom adjustment with specific instructions
task-master scope-up --id=7 --prompt="Add more error handling and edge cases"
```
**Why use this?**
- **Iterative refinement**: Adjust task complexity as your understanding evolves
- **Project phase adaptation**: Scale tasks up for implementation, down for planning
- **Team coordination**: Adjust complexity based on team member experience levels
- **Milestone alignment**: Fine-tune tasks to match project phase requirements
Perfect for agile workflows where task requirements change as you learn more about the problem space.

View File

@@ -1,8 +0,0 @@
---
"task-master-ai": patch
---
Fix scope-up/down prompts to include all required fields for better AI model compatibility
- Added missing `priority` field to scope adjustment prompts to prevent validation errors with Claude-code and other models
- Ensures generated JSON includes all fields required by the schema

View File

@@ -1,9 +0,0 @@
---
"task-master-ai": minor
---
Enhanced Claude Code provider with codebase-aware task generation
- Added automatic codebase analysis for Claude Code provider in `parse-prd`, `expand-task`, and `analyze-complexity` commands
- When using Claude Code as the AI provider, Task Master now instructs the AI to analyze the project structure, existing implementations, and patterns before generating tasks or subtasks
- Tasks and subtasks generated by Claude Code are now informed by actual codebase analysis, resulting in more accurate and contextual outputs

View File

@@ -2,12 +2,13 @@
"mode": "exit",
"tag": "rc",
"initialVersions": {
"task-master-ai": "0.23.0",
"extension": "0.23.0"
"task-master-ai": "0.22.0",
"extension": "0.20.0"
},
"changesets": [
"fuzzy-words-count",
"tender-trams-refuse",
"vast-sites-leave"
"eleven-horses-shop",
"fix-tag-complexity-detection",
"floppy-news-buy-1",
"sour-pans-beam-1"
]
}

View File

@@ -0,0 +1,42 @@
---
"extension": minor
---
🎉 **Introducing TaskMaster Extension!**
We're thrilled to launch the first version of our Code extension, bringing the power of TaskMaster directly into your favorite code editor. While this is our initial release and we've kept things focused, it already packs powerful features to supercharge your development workflow.
## ✨ Key Features
### 📋 Visual Task Management
- **Kanban Board View**: Visualize all your tasks in an intuitive board layout directly in VS Code
- **Drag & Drop**: Easily change task status by dragging cards between columns
- **Real-time Updates**: See changes instantly as you work through your project
### 🏷️ Multi-Context Support
- **Tag Switching**: Seamlessly switch between different project contexts/tags
- **Isolated Workflows**: Keep different features or experiments organized separately
### 🤖 AI-Powered Task Updates
- **Smart Updates**: Use TaskMaster's AI capabilities to update tasks and subtasks
- **Context-Aware**: Leverages your existing TaskMaster configuration and models
### 📊 Rich Task Information
- **Complexity Scores**: See task complexity ratings at a glance
- **Subtask Visualization**: Expand tasks to view and manage subtasks
- **Dependency Graphs**: Understand task relationships and dependencies visually
### ⚙️ Configuration Management
- **Visual Config Editor**: View and understand your `.taskmaster/config.json` settings
- **Easy Access**: No more manual JSON editing for common configuration tasks
### 🚀 Quick Actions
- **Status Updates**: Change task status with a single click
- **Task Details**: Access full task information without leaving VS Code
- **Integrated Commands**: All TaskMaster commands available through the command palette
## 🎯 What's Next?
This is just the beginning! We wanted to get a solid foundation into your hands quickly. The extension will evolve rapidly with your feedback, adding more advanced features, better visualizations, and deeper integration with your development workflow.
Thank you for being part of the TaskMaster journey. Your workflow has never looked better! 🚀

View File

@@ -1,8 +0,0 @@
---
"task-master-ai": patch
---
Fix MCP scope-up/down tools not finding tasks
- Fixed task ID parsing in MCP layer - now correctly converts string IDs to numbers
- scope_up_task and scope_down_task MCP tools now work properly

View File

@@ -1,11 +0,0 @@
---
"task-master-ai": patch
---
Improve AI provider compatibility for JSON generation
- Fixed schema compatibility issues between Perplexity and OpenAI o3 models
- Removed nullable/default modifiers from Zod schemas for broader compatibility
- Added automatic JSON repair for malformed AI responses (handles cases like missing array values)
- Perplexity now uses JSON mode for more reliable structured output
- Post-processing handles default values separately from schema validation

View File

@@ -1,37 +1,15 @@
#!/usr/bin/env node
import assert from 'node:assert/strict';
import { spawnSync } from 'node:child_process';
import { readFileSync, existsSync } from 'node:fs';
import { join, dirname, resolve } from 'node:path';
import { readFileSync } from 'node:fs';
import { join, dirname } from 'node:path';
import { fileURLToPath } from 'node:url';
const __filename = fileURLToPath(import.meta.url);
const __dirname = dirname(__filename);
// Find the root directory by looking for package.json
function findRootDir(startDir) {
let currentDir = resolve(startDir);
while (currentDir !== '/') {
if (existsSync(join(currentDir, 'package.json'))) {
// Verify it's the root package.json by checking for expected fields
try {
const pkg = JSON.parse(
readFileSync(join(currentDir, 'package.json'), 'utf8')
);
if (pkg.name === 'task-master-ai' || pkg.repository) {
return currentDir;
}
} catch {}
}
currentDir = dirname(currentDir);
}
throw new Error('Could not find root directory');
}
const rootDir = findRootDir(__dirname);
// Read the extension's package.json
const extensionDir = join(rootDir, 'apps', 'extension');
const extensionDir = join(__dirname, '..', 'apps', 'extension');
const pkgPath = join(extensionDir, 'package.json');
let pkg;
@@ -44,7 +22,7 @@ try {
}
// Read root package.json for repository info
const rootPkgPath = join(rootDir, 'package.json');
const rootPkgPath = join(__dirname, '..', 'package.json');
let rootPkg;
try {
const rootPkgContent = readFileSync(rootPkgPath, 'utf8');
@@ -62,51 +40,13 @@ assert(rootPkg.repository, 'root package.json must have a repository field');
const tag = `${pkg.name}@${pkg.version}`;
// Get repository URL from root package.json
// Get repository URL and clean it up for git ls-remote
let repoUrl = rootPkg.repository.url || rootPkg.repository;
if (typeof repoUrl === 'string') {
// Convert git+https://github.com/... to https://github.com/...
repoUrl = repoUrl.replace(/^git\+/, '');
// Ensure it ends with .git for proper remote access
if (!repoUrl.endsWith('.git')) {
repoUrl += '.git';
}
}
const repoUrl = rootPkg.repository.url;
console.log(`Checking remote repository: ${repoUrl} for tag: ${tag}`);
const { status, stdout, error } = spawnSync('git', ['ls-remote', repoUrl, tag]);
let gitResult = spawnSync('git', ['ls-remote', repoUrl, tag], {
encoding: 'utf8',
env: { ...process.env }
});
assert.equal(status, 0, error);
if (gitResult.status !== 0) {
console.error('Git ls-remote failed:');
console.error('Exit code:', gitResult.status);
console.error('Error:', gitResult.error);
console.error('Stderr:', gitResult.stderr);
console.error('Command:', `git ls-remote ${repoUrl} ${tag}`);
// For CI environments, try using origin instead of the full URL
if (process.env.CI) {
console.log('Retrying with origin remote...');
gitResult = spawnSync('git', ['ls-remote', 'origin', tag], {
encoding: 'utf8'
});
if (gitResult.status !== 0) {
throw new Error(
`Failed to check remote for tag ${tag}. Exit code: ${gitResult.status}`
);
}
} else {
throw new Error(
`Failed to check remote for tag ${tag}. Exit code: ${gitResult.status}`
);
}
}
const exists = String(gitResult.stdout).trim() !== '';
const exists = String(stdout).trim() !== '';
if (!exists) {
console.log(`Creating new extension tag: ${tag}`);

View File

@@ -3,12 +3,11 @@ name: Pre-Release (RC)
on:
workflow_dispatch: # Allows manual triggering from GitHub UI/API
concurrency: pre-release-${{ github.ref_name }}
concurrency: pre-release-${{ github.ref }}
jobs:
rc:
runs-on: ubuntu-latest
# Only allow pre-releases on non-main branches
if: github.ref != 'refs/heads/main'
steps:
- uses: actions/checkout@v4
with:

View File

@@ -1,46 +0,0 @@
name: Release Check
on:
pull_request:
branches:
- main
concurrency:
group: release-check-${{ github.head_ref }}
cancel-in-progress: true
jobs:
check-release-mode:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Check release mode
run: |
set -euo pipefail
echo "🔍 Checking if branch is in pre-release mode..."
if [[ -f .changeset/pre.json ]]; then
if ! PRE_MODE=$(jq -r '.mode' .changeset/pre.json 2>/dev/null); then
echo "❌ ERROR: Unable to parse .changeset/pre.json aborting merge."
exit 1
fi
if [[ "$PRE_MODE" == "pre" ]]; then
echo "❌ ERROR: This branch is in active pre-release mode!"
echo ""
echo "Pre-release mode must be exited before merging to main."
echo ""
echo "To fix this, run the following commands in your branch:"
echo " npx changeset pre exit"
echo " git add -u"
echo " git commit -m 'chore: exit pre-release mode'"
echo " git push"
echo ""
echo "Then update this pull request."
exit 1
fi
fi
echo "✅ Not in active pre-release mode - PR can be merged"

View File

@@ -38,27 +38,27 @@ jobs:
run: npm ci
timeout-minutes: 2
- name: Check pre-release mode
- name: Exit pre-release mode and clean up
run: |
set -euo pipefail
echo "🔍 Checking pre-release mode status..."
if [[ -f .changeset/pre.json ]]; then
echo "❌ ERROR: Main branch is in pre-release mode!"
echo ""
echo "Pre-release mode should only be used on feature branches, not main."
echo ""
echo "To fix this, run the following commands locally:"
echo " npx changeset pre exit"
echo " git add -u"
echo " git commit -m 'chore: exit pre-release mode'"
echo " git push origin main"
echo ""
echo "Then re-run this workflow."
echo "🔄 Ensuring we're not in pre-release mode for main branch..."
# Exit pre-release mode if we're in it
npx changeset pre exit || echo "Not in pre-release mode"
# Remove pre.json file if it exists (belt and suspenders approach)
if [ -f .changeset/pre.json ]; then
echo "🧹 Removing pre.json file..."
rm -f .changeset/pre.json
fi
# Verify the file is gone
if [ ! -f .changeset/pre.json ]; then
echo "✅ pre.json successfully removed"
else
echo "❌ Failed to remove pre.json"
exit 1
fi
echo "✅ Not in pre-release mode - proceeding with release"
- name: Create Release Pull Request or Publish to npm
uses: changesets/action@v1
with:

View File

@@ -1,343 +0,0 @@
# Product Requirements Document: tm-core Package - Parse PRD Feature
## Project Overview
Create a TypeScript package named `tm-core` at `packages/tm-core` that implements parse-prd functionality using class-based architecture similar to the existing AI providers pattern.
## Design Patterns & Architecture
### Patterns to Apply
1. **Factory Pattern**: Use for `ProviderFactory` to create AI provider instances
2. **Strategy Pattern**: Use for `IAIProvider` implementations and `IStorage` implementations
3. **Facade Pattern**: Use for `TaskMasterCore` as the main API entry point
4. **Template Method Pattern**: Use for `BaseProvider` abstract class
5. **Dependency Injection**: Use throughout for testability (pass dependencies via constructor)
6. **Repository Pattern**: Use for `FileStorage` to abstract data persistence
### Naming Conventions
- **Files**: kebab-case (e.g., `task-parser.ts`, `file-storage.ts`)
- **Classes**: PascalCase (e.g., `TaskParser`, `FileStorage`)
- **Interfaces**: PascalCase with 'I' prefix (e.g., `IStorage`, `IAIProvider`)
- **Methods**: camelCase (e.g., `parsePRD`, `loadTasks`)
- **Constants**: UPPER_SNAKE_CASE (e.g., `DEFAULT_MODEL`)
- **Type aliases**: PascalCase (e.g., `TaskStatus`, `ParseOptions`)
## Exact Folder Structure Required
```
packages/tm-core/
├── src/
│ ├── index.ts
│ ├── types/
│ │ └── index.ts
│ ├── interfaces/
│ │ ├── index.ts # Barrel export
│ │ ├── storage.interface.ts
│ │ ├── ai-provider.interface.ts
│ │ └── configuration.interface.ts
│ ├── tasks/
│ │ ├── index.ts # Barrel export
│ │ └── task-parser.ts
│ ├── ai/
│ │ ├── index.ts # Barrel export
│ │ ├── base-provider.ts
│ │ ├── provider-factory.ts
│ │ ├── prompt-builder.ts
│ │ └── providers/
│ │ ├── index.ts # Barrel export
│ │ ├── anthropic-provider.ts
│ │ ├── openai-provider.ts
│ │ └── google-provider.ts
│ ├── storage/
│ │ ├── index.ts # Barrel export
│ │ └── file-storage.ts
│ ├── config/
│ │ ├── index.ts # Barrel export
│ │ └── config-manager.ts
│ ├── utils/
│ │ ├── index.ts # Barrel export
│ │ └── id-generator.ts
│ └── errors/
│ ├── index.ts # Barrel export
│ └── task-master-error.ts
├── tests/
│ ├── task-parser.test.ts
│ ├── integration/
│ │ └── parse-prd.test.ts
│ └── mocks/
│ └── mock-provider.ts
├── package.json
├── tsconfig.json
├── tsup.config.js
└── jest.config.js
```
## Specific Implementation Requirements
### 1. Create types/index.ts
Define these exact TypeScript interfaces:
- `Task` interface with fields: id, title, description, status, priority, complexity, dependencies, subtasks, metadata, createdAt, updatedAt, source
- `Subtask` interface with fields: id, title, description, completed
- `TaskMetadata` interface with fields: parsedFrom, aiProvider, version, tags (optional)
- Type literals: `TaskStatus` = 'pending' | 'in-progress' | 'completed' | 'blocked'
- Type literals: `TaskPriority` = 'low' | 'medium' | 'high' | 'critical'
- Type literals: `TaskComplexity` = 'simple' | 'moderate' | 'complex'
- `ParseOptions` interface with fields: dryRun (optional), additionalContext (optional), tag (optional), maxTasks (optional)
### 2. Create interfaces/storage.interface.ts
Define `IStorage` interface with these exact methods:
- `loadTasks(tag?: string): Promise<Task[]>`
- `saveTasks(tasks: Task[], tag?: string): Promise<void>`
- `appendTasks(tasks: Task[], tag?: string): Promise<void>`
- `updateTask(id: string, task: Partial<Task>, tag?: string): Promise<void>`
- `deleteTask(id: string, tag?: string): Promise<void>`
- `exists(tag?: string): Promise<boolean>`
### 3. Create interfaces/ai-provider.interface.ts
Define `IAIProvider` interface with these exact methods:
- `generateCompletion(prompt: string, options?: AIOptions): Promise<string>`
- `calculateTokens(text: string): number`
- `getName(): string`
- `getModel(): string`
Define `AIOptions` interface with fields: temperature (optional), maxTokens (optional), systemPrompt (optional)
### 4. Create interfaces/configuration.interface.ts
Define `IConfiguration` interface with fields:
- `projectPath: string`
- `aiProvider: string`
- `apiKey?: string`
- `aiOptions?: AIOptions`
- `mainModel?: string`
- `researchModel?: string`
- `fallbackModel?: string`
- `tasksPath?: string`
- `enableTags?: boolean`
### 5. Create tasks/task-parser.ts
Create class `TaskParser` with:
- Constructor accepting `aiProvider: IAIProvider` and `config: IConfiguration`
- Private property `promptBuilder: PromptBuilder`
- Public method `parsePRD(prdPath: string, options: ParseOptions = {}): Promise<Task[]>`
- Private method `readPRD(prdPath: string): Promise<string>`
- Private method `extractTasks(aiResponse: string): Partial<Task>[]`
- Private method `enrichTasks(rawTasks: Partial<Task>[], prdPath: string): Task[]`
- Apply **Dependency Injection** pattern via constructor
### 6. Create ai/base-provider.ts
Copy existing base-provider.js and convert to TypeScript abstract class:
- Abstract class `BaseProvider` implementing `IAIProvider`
- Protected properties: `apiKey: string`, `model: string`
- Constructor accepting `apiKey: string` and `options: { model?: string }`
- Abstract methods matching IAIProvider interface
- Abstract method `getDefaultModel(): string`
- Apply **Template Method** pattern for common provider logic
### 7. Create ai/provider-factory.ts
Create class `ProviderFactory` with:
- Static method `create(config: { provider: string; apiKey?: string; model?: string }): Promise<IAIProvider>`
- Switch statement for providers: 'anthropic', 'openai', 'google'
- Dynamic imports for each provider
- Throw error for unknown providers
- Apply **Factory** pattern for creating provider instances
Example implementation structure:
```typescript
switch (provider.toLowerCase()) {
case 'anthropic':
const { AnthropicProvider } = await import('./providers/anthropic-provider.js');
return new AnthropicProvider(apiKey, { model });
}
```
### 8. Create ai/providers/anthropic-provider.ts
Create class `AnthropicProvider` extending `BaseProvider`:
- Import Anthropic SDK: `import { Anthropic } from '@anthropic-ai/sdk'`
- Private property `client: Anthropic`
- Implement all abstract methods from BaseProvider
- Default model: 'claude-3-sonnet-20240229'
- Handle API errors and wrap with meaningful messages
### 9. Create ai/providers/openai-provider.ts (placeholder)
Create class `OpenAIProvider` extending `BaseProvider`:
- Import OpenAI SDK when implemented
- For now, throw error: "OpenAI provider not yet implemented"
### 10. Create ai/providers/google-provider.ts (placeholder)
Create class `GoogleProvider` extending `BaseProvider`:
- Import Google Generative AI SDK when implemented
- For now, throw error: "Google provider not yet implemented"
### 11. Create ai/prompt-builder.ts
Create class `PromptBuilder` with:
- Method `buildParsePrompt(prdContent: string, options: ParseOptions = {}): string`
- Method `buildExpandPrompt(task: string, context?: string): string`
- Use template literals for prompt construction
- Include specific JSON format instructions in prompts
### 9. Create storage/file-storage.ts
Create class `FileStorage` implementing `IStorage`:
- Private property `basePath: string` set to `{projectPath}/.taskmaster`
- Constructor accepting `projectPath: string`
- Private method `getTasksPath(tag?: string): string` returning correct path based on tag
- Private method `ensureDirectory(dir: string): Promise<void>`
- Implement all IStorage methods
- Handle ENOENT errors by returning empty arrays
- Use JSON format with structure: `{ tasks: Task[], metadata: { version: string, lastModified: string } }`
- Apply **Repository** pattern for data access abstraction
### 10. Create config/config-manager.ts
Create class `ConfigManager`:
- Private property `config: IConfiguration`
- Constructor accepting `options: Partial<IConfiguration>`
- Use Zod for validation with schema matching IConfiguration
- Method `get<K extends keyof IConfiguration>(key: K): IConfiguration[K]`
- Method `getAll(): IConfiguration`
- Method `validate(): boolean`
- Default values: projectPath = process.cwd(), aiProvider = 'anthropic', enableTags = true
### 11. Create utils/id-generator.ts
Export functions:
- `generateTaskId(index: number = 0): string` returning format `task_{timestamp}_{index}_{random}`
- `generateSubtaskId(parentId: string, index: number = 0): string` returning format `{parentId}_sub_{index}_{random}`
### 16. Create src/index.ts
Create main class `TaskMasterCore`:
- Private properties: `config: ConfigManager`, `storage: IStorage`, `aiProvider?: IAIProvider`, `parser?: TaskParser`
- Constructor accepting `options: Partial<IConfiguration>`
- Method `initialize(): Promise<void>` for lazy loading
- Method `parsePRD(prdPath: string, options: ParseOptions = {}): Promise<Task[]>`
- Method `getTasks(tag?: string): Promise<Task[]>`
- Apply **Facade** pattern to provide simple API over complex subsystems
Export:
- Class `TaskMasterCore`
- Function `createTaskMaster(options: Partial<IConfiguration>): TaskMasterCore`
- All types from './types'
- All interfaces from './interfaces/*'
Import statements should use kebab-case:
```typescript
import { TaskParser } from './tasks/task-parser';
import { FileStorage } from './storage/file-storage';
import { ConfigManager } from './config/config-manager';
import { ProviderFactory } from './ai/provider-factory';
```
### 17. Configure package.json
Create package.json with:
- name: "@task-master/core"
- version: "0.1.0"
- type: "module"
- main: "./dist/index.js"
- module: "./dist/index.mjs"
- types: "./dist/index.d.ts"
- exports map for proper ESM/CJS support
- scripts: build (tsup), dev (tsup --watch), test (jest), typecheck (tsc --noEmit)
- dependencies: zod@^3.23.8
- peerDependencies: @anthropic-ai/sdk, openai, @google/generative-ai
- devDependencies: typescript, tsup, jest, ts-jest, @types/node, @types/jest
### 18. Configure TypeScript
Create tsconfig.json with:
- target: "ES2022"
- module: "ESNext"
- strict: true (with all strict flags enabled)
- declaration: true
- outDir: "./dist"
- rootDir: "./src"
### 19. Configure tsup
Create tsup.config.js with:
- entry: ['src/index.ts']
- format: ['cjs', 'esm']
- dts: true
- sourcemap: true
- clean: true
- external: AI provider SDKs
### 20. Configure Jest
Create jest.config.js with:
- preset: 'ts-jest'
- testEnvironment: 'node'
- Coverage threshold: 80% for all metrics
## Build Process
1. Use tsup to compile TypeScript to both CommonJS and ESM
2. Generate .d.ts files for TypeScript consumers
3. Output to dist/ directory
4. Ensure tree-shaking works properly
## Testing Requirements
- Create unit tests for TaskParser in tests/task-parser.test.ts
- Create MockProvider class in tests/mocks/mock-provider.ts for testing without API calls
- Test error scenarios (file not found, invalid JSON, etc.)
- Create integration test in tests/integration/parse-prd.test.ts
- Follow kebab-case naming for all test files
## Success Criteria
- TypeScript compilation with zero errors
- No use of 'any' type
- All interfaces properly exported
- Compatible with existing tasks.json format
- Feature flag support via USE_TM_CORE environment variable
## Import/Export Conventions
- Use named exports for all classes and interfaces
- Use barrel exports (index.ts) in each directory
- Import types/interfaces with type-only imports: `import type { Task } from '../types'`
- Group imports in order: Node built-ins, external packages, internal packages, relative imports
- Use .js extension in import paths for ESM compatibility
## Error Handling Patterns
- Create custom error classes in `src/errors/` directory
- All public methods should catch and wrap errors with context
- Use error codes for different error types (e.g., 'FILE_NOT_FOUND', 'PARSE_ERROR')
- Never expose internal implementation details in error messages
- Log errors to console.error only in development mode
## Barrel Exports Content
### interfaces/index.ts
```typescript
export type { IStorage } from './storage.interface';
export type { IAIProvider, AIOptions } from './ai-provider.interface';
export type { IConfiguration } from './configuration.interface';
```
### tasks/index.ts
```typescript
export { TaskParser } from './task-parser';
```
### ai/index.ts
```typescript
export { BaseProvider } from './base-provider';
export { ProviderFactory } from './provider-factory';
export { PromptBuilder } from './prompt-builder';
```
### ai/providers/index.ts
```typescript
export { AnthropicProvider } from './anthropic-provider';
export { OpenAIProvider } from './openai-provider';
export { GoogleProvider } from './google-provider';
```
### storage/index.ts
```typescript
export { FileStorage } from './file-storage';
```
### config/index.ts
```typescript
export { ConfigManager } from './config-manager';
```
### utils/index.ts
```typescript
export { generateTaskId, generateSubtaskId } from './id-generator';
```
### errors/index.ts
```typescript
export { TaskMasterError } from './task-master-error';
```

View File

@@ -1,72 +1,5 @@
# task-master-ai
## 0.23.1-rc.0
### Patch Changes
- [#1079](https://github.com/eyaltoledano/claude-task-master/pull/1079) [`e495b2b`](https://github.com/eyaltoledano/claude-task-master/commit/e495b2b55950ee54c7d0f1817d8530e28bd79c05) Thanks [@Crunchyman-ralph](https://github.com/Crunchyman-ralph)! - Fix scope-up/down prompts to include all required fields for better AI model compatibility
- Added missing `priority` field to scope adjustment prompts to prevent validation errors with Claude-code and other models
- Ensures generated JSON includes all fields required by the schema
- [#1079](https://github.com/eyaltoledano/claude-task-master/pull/1079) [`e495b2b`](https://github.com/eyaltoledano/claude-task-master/commit/e495b2b55950ee54c7d0f1817d8530e28bd79c05) Thanks [@Crunchyman-ralph](https://github.com/Crunchyman-ralph)! - Fix MCP scope-up/down tools not finding tasks
- Fixed task ID parsing in MCP layer - now correctly converts string IDs to numbers
- scope_up_task and scope_down_task MCP tools now work properly
- [#1079](https://github.com/eyaltoledano/claude-task-master/pull/1079) [`e495b2b`](https://github.com/eyaltoledano/claude-task-master/commit/e495b2b55950ee54c7d0f1817d8530e28bd79c05) Thanks [@Crunchyman-ralph](https://github.com/Crunchyman-ralph)! - Improve AI provider compatibility for JSON generation
- Fixed schema compatibility issues between Perplexity and OpenAI o3 models
- Removed nullable/default modifiers from Zod schemas for broader compatibility
- Added automatic JSON repair for malformed AI responses (handles cases like missing array values)
- Perplexity now uses JSON mode for more reliable structured output
- Post-processing handles default values separately from schema validation
## 0.23.0
### Minor Changes
- [#1064](https://github.com/eyaltoledano/claude-task-master/pull/1064) [`53903f1`](https://github.com/eyaltoledano/claude-task-master/commit/53903f1e8eee23ac512eb13a6d81d8cbcfe658cb) Thanks [@eyaltoledano](https://github.com/eyaltoledano)! - Add new `scope-up` and `scope-down` commands for dynamic task complexity adjustment
This release introduces two powerful new commands that allow you to dynamically adjust the complexity of your tasks and subtasks without recreating them from scratch.
**New CLI Commands:**
- `task-master scope-up` - Increase task complexity (add more detail, requirements, or implementation steps)
- `task-master scope-down` - Decrease task complexity (simplify, remove unnecessary details, or streamline)
**Key Features:**
- **Multiple tasks**: Support comma-separated IDs to adjust multiple tasks at once (`--id=5,7,12`)
- **Strength levels**: Choose adjustment intensity with `--strength=light|regular|heavy` (defaults to regular)
- **Custom prompts**: Use `--prompt` flag to specify exactly how you want tasks adjusted
- **MCP integration**: Available as `scope_up_task` and `scope_down_task` tools in Cursor and other MCP environments
- **Smart context**: AI considers your project context and task dependencies when making adjustments
**Usage Examples:**
```bash
# Make a task more detailed
task-master scope-up --id=5
# Simplify multiple tasks with light touch
task-master scope-down --id=10,11,12 --strength=light
# Custom adjustment with specific instructions
task-master scope-up --id=7 --prompt="Add more error handling and edge cases"
```
**Why use this?**
- **Iterative refinement**: Adjust task complexity as your understanding evolves
- **Project phase adaptation**: Scale tasks up for implementation, down for planning
- **Team coordination**: Adjust complexity based on team member experience levels
- **Milestone alignment**: Fine-tune tasks to match project phase requirements
Perfect for agile workflows where task requirements change as you learn more about the problem space.
### Patch Changes
- [#1063](https://github.com/eyaltoledano/claude-task-master/pull/1063) [`2ae6e7e`](https://github.com/eyaltoledano/claude-task-master/commit/2ae6e7e6be3605c3c4d353f34666e54750dba973) Thanks [@Crunchyman-ralph](https://github.com/Crunchyman-ralph)! - Fix for tasks not found when using string IDs
- [#1049](https://github.com/eyaltoledano/claude-task-master/pull/1049) [`45a14c3`](https://github.com/eyaltoledano/claude-task-master/commit/45a14c323d21071c15106335e89ad1f4a20976ab) Thanks [@ben-vargas](https://github.com/ben-vargas)! - Fix tag-specific complexity report detection in expand command
The expand command now correctly finds and uses tag-specific complexity reports (e.g., `task-complexity-report_feature-xyz.json`) when operating in a tag context. Previously, it would always look for the generic `task-complexity-report.json` file due to a default value in the CLI option definition.
## 0.23.0-rc.2
### Minor Changes

View File

@@ -1,48 +1,5 @@
# Change Log
## 0.23.0
### Minor Changes
- [#1064](https://github.com/eyaltoledano/claude-task-master/pull/1064) [`b82d858`](https://github.com/eyaltoledano/claude-task-master/commit/b82d858f81a1e702ad59d84d5ae8a2ca84359a83) Thanks [@Crunchyman-ralph](https://github.com/Crunchyman-ralph)! - 🎉 **Introducing TaskMaster Extension!**
We're thrilled to launch the first version of our Code extension, bringing the power of TaskMaster directly into your favorite code editor. While this is our initial release and we've kept things focused, it already packs powerful features to supercharge your development workflow.
## ✨ Key Features
### 📋 Visual Task Management
- **Kanban Board View**: Visualize all your tasks in an intuitive board layout directly in VS Code
- **Drag & Drop**: Easily change task status by dragging cards between columns
- **Real-time Updates**: See changes instantly as you work through your project
### 🏷️ Multi-Context Support
- **Tag Switching**: Seamlessly switch between different project contexts/tags
- **Isolated Workflows**: Keep different features or experiments organized separately
### 🤖 AI-Powered Task Updates
- **Smart Updates**: Use TaskMaster's AI capabilities to update tasks and subtasks
- **Context-Aware**: Leverages your existing TaskMaster configuration and models
### 📊 Rich Task Information
- **Complexity Scores**: See task complexity ratings at a glance
- **Subtask Visualization**: Expand tasks to view and manage subtasks
- **Dependency Graphs**: Understand task relationships and dependencies visually
### ⚙️ Configuration Management
- **Visual Config Editor**: View and understand your `.taskmaster/config.json` settings
- **Easy Access**: No more manual JSON editing for common configuration tasks
### 🚀 Quick Actions
- **Status Updates**: Change task status with a single click
- **Task Details**: Access full task information without leaving VS Code
- **Integrated Commands**: All TaskMaster commands available through the command palette
## 🎯 What's Next?
This is just the beginning! We wanted to get a solid foundation into your hands quickly. The extension will evolve rapidly with your feedback, adding more advanced features, better visualizations, and deeper integration with your development workflow.
Thank you for being part of the TaskMaster journey. Your workflow has never looked better! 🚀
## 0.23.0-rc.1
### Minor Changes

View File

@@ -3,7 +3,7 @@
"private": true,
"displayName": "TaskMaster",
"description": "A visual Kanban board interface for TaskMaster projects in VS Code",
"version": "0.23.0",
"version": "0.23.0-rc.1",
"publisher": "Hamster",
"icon": "assets/icon.png",
"engines": {

View File

@@ -71,8 +71,8 @@ export async function scopeDownDirect(args, log, context = {}) {
};
}
// Parse task IDs - convert to numbers as expected by scopeDownTask
const taskIds = id.split(',').map((taskId) => parseInt(taskId.trim(), 10));
// Parse task IDs
const taskIds = id.split(',').map((taskId) => taskId.trim());
log.info(
`Scoping down tasks: ${taskIds.join(', ')}, strength: ${strength}, research: ${research}`
@@ -90,10 +90,10 @@ export async function scopeDownDirect(args, log, context = {}) {
projectRoot,
commandName: 'scope-down',
outputType: 'mcp',
tag,
research
tag
},
'json' // outputFormat
'json', // outputFormat
research
);
// Restore normal logging

View File

@@ -71,8 +71,8 @@ export async function scopeUpDirect(args, log, context = {}) {
};
}
// Parse task IDs - convert to numbers as expected by scopeUpTask
const taskIds = id.split(',').map((taskId) => parseInt(taskId.trim(), 10));
// Parse task IDs
const taskIds = id.split(',').map((taskId) => taskId.trim());
log.info(
`Scoping up tasks: ${taskIds.join(', ')}, strength: ${strength}, research: ${research}`
@@ -90,10 +90,10 @@ export async function scopeUpDirect(args, log, context = {}) {
projectRoot,
commandName: 'scope-up',
outputType: 'mcp',
tag,
research
tag
},
'json' // outputFormat
'json', // outputFormat
research
);
// Restore normal logging

16
package-lock.json generated
View File

@@ -1,12 +1,12 @@
{
"name": "task-master-ai",
"version": "0.23.0",
"version": "0.22.1-rc.0",
"lockfileVersion": 3,
"requires": true,
"packages": {
"": {
"name": "task-master-ai",
"version": "0.23.0",
"version": "0.22.1-rc.0",
"license": "MIT WITH Commons-Clause",
"workspaces": [
"apps/*",
@@ -46,7 +46,6 @@
"helmet": "^8.1.0",
"inquirer": "^12.5.0",
"jsonc-parser": "^3.3.1",
"jsonrepair": "^3.13.0",
"jsonwebtoken": "^9.0.2",
"lru-cache": "^10.2.0",
"ollama-ai-provider": "^1.2.0",
@@ -85,7 +84,7 @@
}
},
"apps/extension": {
"version": "0.23.0",
"version": "0.22.3",
"devDependencies": {
"@dnd-kit/core": "^6.3.1",
"@dnd-kit/modifiers": "^9.0.0",
@@ -14943,15 +14942,6 @@
"graceful-fs": "^4.1.6"
}
},
"node_modules/jsonrepair": {
"version": "3.13.0",
"resolved": "https://registry.npmjs.org/jsonrepair/-/jsonrepair-3.13.0.tgz",
"integrity": "sha512-5YRzlAQ7tuzV1nAJu3LvDlrKtBFIALHN2+a+I1MGJCt3ldRDBF/bZuvIPzae8Epot6KBXd0awRZZcuoeAsZ/mw==",
"license": "ISC",
"bin": {
"jsonrepair": "bin/cli.js"
}
},
"node_modules/jsonwebtoken": {
"version": "9.0.2",
"resolved": "https://registry.npmjs.org/jsonwebtoken/-/jsonwebtoken-9.0.2.tgz",

View File

@@ -1,6 +1,6 @@
{
"name": "task-master-ai",
"version": "0.23.1-rc.0",
"version": "0.23.0-rc.2",
"description": "A task management system for ambitious AI-driven development that doesn't overwhelm and confuse Cursor.",
"main": "index.js",
"type": "module",
@@ -73,7 +73,6 @@
"helmet": "^8.1.0",
"inquirer": "^12.5.0",
"jsonc-parser": "^3.3.1",
"jsonrepair": "^3.13.0",
"jsonwebtoken": "^9.0.2",
"lru-cache": "^10.2.0",
"ollama-ai-provider": "^1.2.0",

View File

@@ -1479,8 +1479,7 @@ function registerCommands(programInstance) {
projectRoot: taskMaster.getProjectRoot(),
tag,
commandName: 'scope-up',
outputType: 'cli',
research: options.research || false
outputType: 'cli'
};
const result = await scopeUpTask(
@@ -1606,8 +1605,7 @@ function registerCommands(programInstance) {
projectRoot: taskMaster.getProjectRoot(),
tag,
commandName: 'scope-down',
outputType: 'cli',
research: options.research || false
outputType: 'cli'
};
const result = await scopeDownTask(

View File

@@ -13,18 +13,12 @@ import {
import { generateTextService } from '../ai-services-unified.js';
import {
getDebugFlag,
getProjectName,
getMainProvider,
getResearchProvider
} from '../config-manager.js';
import { getDebugFlag, getProjectName } from '../config-manager.js';
import { getPromptManager } from '../prompt-manager.js';
import {
COMPLEXITY_REPORT_FILE,
LEGACY_TASKS_FILE
} from '../../../src/constants/paths.js';
import { CUSTOM_PROVIDERS } from '../../../src/constants/providers.js';
import { resolveComplexityReportOutputPath } from '../../../src/utils/path-utils.js';
import { ContextGatherer } from '../utils/contextGatherer.js';
import { FuzzyTaskSearch } from '../utils/fuzzyTaskSearch.js';
@@ -414,18 +408,10 @@ async function analyzeTaskComplexity(options, context = {}) {
// Load prompts using PromptManager
const promptManager = getPromptManager();
// Check if Claude Code is being used as the provider
const currentProvider = useResearch
? getResearchProvider(projectRoot)
: getMainProvider(projectRoot);
const isClaudeCode = currentProvider === CUSTOM_PROVIDERS.CLAUDE_CODE;
const promptParams = {
tasks: tasksData.tasks,
gatheredContext: gatheredContext || '',
useResearch: useResearch,
isClaudeCode: isClaudeCode,
projectRoot: projectRoot || ''
useResearch: useResearch
};
const { systemPrompt, userPrompt: prompt } = await promptManager.loadPrompt(

View File

@@ -18,16 +18,10 @@ import {
import { generateTextService } from '../ai-services-unified.js';
import {
getDefaultSubtasks,
getDebugFlag,
getMainProvider,
getResearchProvider
} from '../config-manager.js';
import { getDefaultSubtasks, getDebugFlag } from '../config-manager.js';
import { getPromptManager } from '../prompt-manager.js';
import generateTaskFiles from './generate-task-files.js';
import { COMPLEXITY_REPORT_FILE } from '../../../src/constants/paths.js';
import { CUSTOM_PROVIDERS } from '../../../src/constants/providers.js';
import { ContextGatherer } from '../utils/contextGatherer.js';
import { FuzzyTaskSearch } from '../utils/fuzzyTaskSearch.js';
import { flattenTasksWithSubtasks, findProjectRoot } from '../utils.js';
@@ -457,12 +451,6 @@ async function expandTask(
// Load prompts using PromptManager
const promptManager = getPromptManager();
// Check if Claude Code is being used as the provider
const currentProvider = useResearch
? getResearchProvider(projectRoot)
: getMainProvider(projectRoot);
const isClaudeCode = currentProvider === CUSTOM_PROVIDERS.CLAUDE_CODE;
// Combine all context sources into a single additionalContext parameter
let combinedAdditionalContext = '';
if (additionalContext || complexityReasoningContext) {
@@ -507,9 +495,7 @@ async function expandTask(
complexityReasoningContext: complexityReasoningContext,
gatheredContext: gatheredContextText || '',
useResearch: useResearch,
expansionPrompt: expansionPromptText || undefined,
isClaudeCode: isClaudeCode,
projectRoot: projectRoot || ''
expansionPrompt: expansionPromptText || undefined
};
let variantKey = 'default';

View File

@@ -17,26 +17,20 @@ import {
} from '../utils.js';
import { generateObjectService } from '../ai-services-unified.js';
import {
getDebugFlag,
getMainProvider,
getResearchProvider,
getDefaultPriority
} from '../config-manager.js';
import { getDebugFlag } from '../config-manager.js';
import { getPromptManager } from '../prompt-manager.js';
import { displayAiUsageSummary } from '../ui.js';
import { CUSTOM_PROVIDERS } from '../../../src/constants/providers.js';
// Define the Zod schema for a SINGLE task object
const prdSingleTaskSchema = z.object({
id: z.number(),
id: z.number().int().positive(),
title: z.string().min(1),
description: z.string().min(1),
details: z.string(),
testStrategy: z.string(),
priority: z.enum(['high', 'medium', 'low']),
dependencies: z.array(z.number()),
status: z.string()
details: z.string().nullable(),
testStrategy: z.string().nullable(),
priority: z.enum(['high', 'medium', 'low']).nullable(),
dependencies: z.array(z.number().int().positive()).nullable(),
status: z.string().nullable()
});
// Define the Zod schema for the ENTIRE expected AI response object
@@ -180,14 +174,9 @@ async function parsePRD(prdPath, tasksPath, numTasks, options = {}) {
const promptManager = getPromptManager();
// Get defaultTaskPriority from config
const { getDefaultPriority } = await import('../config-manager.js');
const defaultTaskPriority = getDefaultPriority(projectRoot) || 'medium';
// Check if Claude Code is being used as the provider
const currentProvider = research
? getResearchProvider(projectRoot)
: getMainProvider(projectRoot);
const isClaudeCode = currentProvider === CUSTOM_PROVIDERS.CLAUDE_CODE;
const { systemPrompt, userPrompt } = await promptManager.loadPrompt(
'parse-prd',
{
@@ -196,9 +185,7 @@ async function parsePRD(prdPath, tasksPath, numTasks, options = {}) {
nextId,
prdContent,
prdPath,
defaultTaskPriority,
isClaudeCode,
projectRoot: projectRoot || ''
defaultTaskPriority
}
);
@@ -270,15 +257,10 @@ async function parsePRD(prdPath, tasksPath, numTasks, options = {}) {
return {
...task,
id: newId,
status: task.status || 'pending',
status: 'pending',
priority: task.priority || 'medium',
dependencies: Array.isArray(task.dependencies) ? task.dependencies : [],
subtasks: [],
// Ensure all required fields have values (even if empty strings)
title: task.title || '',
description: task.description || '',
details: task.details || '',
testStrategy: task.testStrategy || ''
subtasks: []
};
});

View File

@@ -337,7 +337,7 @@ ${
}
Return a JSON object with a "subtasks" array. Each subtask should have:
- id: Sequential NUMBER starting from 1 (e.g., 1, 2, 3 - NOT "1", "2", "3")
- id: Sequential number starting from 1
- title: Clear, specific title
- description: Detailed description
- dependencies: Array of dependency IDs as STRINGS (use format ["${task.id}.1", "${task.id}.2"] for siblings, or empty array [] for no dependencies)
@@ -345,9 +345,7 @@ Return a JSON object with a "subtasks" array. Each subtask should have:
- status: "pending"
- testStrategy: Testing approach
IMPORTANT:
- The 'id' field must be a NUMBER, not a string!
- Dependencies must be strings, not numbers!
IMPORTANT: Dependencies must be strings, not numbers!
Ensure the JSON is valid and properly formatted.`;
@@ -360,14 +358,14 @@ Ensure the JSON is valid and properly formatted.`;
description: z.string().min(10),
dependencies: z.array(z.string()),
details: z.string().min(20),
status: z.string(),
testStrategy: z.string()
status: z.string().default('pending'),
testStrategy: z.string().nullable().default('')
})
)
});
const aiResult = await generateObjectService({
role: context.research ? 'research' : 'main',
role: 'main',
session: context.session,
systemPrompt,
prompt,
@@ -379,21 +377,14 @@ Ensure the JSON is valid and properly formatted.`;
const generatedSubtasks = aiResult.mainResult.subtasks || [];
// Post-process generated subtasks to ensure defaults
const processedGeneratedSubtasks = generatedSubtasks.map((subtask) => ({
...subtask,
status: subtask.status || 'pending',
testStrategy: subtask.testStrategy || ''
}));
// Update task with preserved subtasks + newly generated ones
task.subtasks = [...preservedSubtasks, ...processedGeneratedSubtasks];
task.subtasks = [...preservedSubtasks, ...generatedSubtasks];
return {
updatedTask: task,
regenerated: true,
preserved: preservedSubtasks.length,
generated: processedGeneratedSubtasks.length
generated: generatedSubtasks.length
};
} catch (error) {
log(
@@ -466,7 +457,6 @@ ADJUSTMENT REQUIREMENTS:
- description: Updated task description
- details: Updated implementation details
- testStrategy: Updated test strategy
- priority: Task priority ('low', 'medium', or 'high')
Ensure the JSON is valid and properly formatted.`;
@@ -511,11 +501,14 @@ async function adjustTaskComplexity(
.string()
.min(1)
.describe('Updated testing approach for the adjusted scope'),
priority: z.enum(['low', 'medium', 'high']).describe('Task priority level')
priority: z
.enum(['low', 'medium', 'high'])
.optional()
.describe('Task priority level')
});
const aiResult = await generateObjectService({
role: context.research ? 'research' : 'main',
role: 'main',
session: context.session,
systemPrompt,
prompt,
@@ -527,16 +520,10 @@ async function adjustTaskComplexity(
const updatedTaskData = aiResult.mainResult;
// Ensure priority has a value (in case AI didn't provide one)
const processedTaskData = {
...updatedTaskData,
priority: updatedTaskData.priority || task.priority || 'medium'
};
return {
updatedTask: {
...task,
...processedTaskData
...updatedTaskData
},
telemetryData: aiResult.telemetryData
};

View File

@@ -1,12 +1,4 @@
import {
generateObject,
generateText,
streamText,
zodSchema,
JSONParseError,
NoObjectGeneratedError
} from 'ai';
import { jsonrepair } from 'jsonrepair';
import { generateObject, generateText, streamText } from 'ai';
import { log } from '../../scripts/modules/utils.js';
/**
@@ -214,8 +206,8 @@ export class BaseAIProvider {
const result = await generateObject({
model: client(params.modelId),
messages: params.messages,
schema: zodSchema(params.schema),
mode: params.mode || 'auto',
schema: params.schema,
mode: 'auto',
maxTokens: params.maxTokens,
temperature: params.temperature
});
@@ -234,43 +226,6 @@ export class BaseAIProvider {
}
};
} catch (error) {
// Check if this is a JSON parsing error that we can potentially fix
if (
NoObjectGeneratedError.isInstance(error) &&
JSONParseError.isInstance(error.cause) &&
error.cause.text
) {
log(
'warn',
`${this.name} generated malformed JSON, attempting to repair...`
);
try {
// Use jsonrepair to fix the malformed JSON
const repairedJson = jsonrepair(error.cause.text);
const parsed = JSON.parse(repairedJson);
log('info', `Successfully repaired ${this.name} JSON output`);
// Return in the expected format
return {
object: parsed,
usage: {
// Extract usage information from the error if available
inputTokens: error.usage?.promptTokens || 0,
outputTokens: error.usage?.completionTokens || 0,
totalTokens: error.usage?.totalTokens || 0
}
};
} catch (repairError) {
log(
'error',
`Failed to repair ${this.name} JSON: ${repairError.message}`
);
// Fall through to handleError with original error
}
}
this.handleError('object generation', error);
}
}

View File

@@ -44,21 +44,4 @@ export class PerplexityAIProvider extends BaseAIProvider {
this.handleError('client initialization', error);
}
}
/**
* Override generateObject to use JSON mode for Perplexity
*
* NOTE: Perplexity models (especially sonar models) have known issues
* generating valid JSON, particularly with array fields. They often
* generate malformed JSON like "dependencies": , instead of "dependencies": []
*
* The base provider now handles JSON repair automatically for all providers.
*/
async generateObject(params) {
// Force JSON mode for Perplexity as it may help with reliability
return super.generateObject({
...params,
mode: 'json'
});
}
}

View File

@@ -30,22 +30,12 @@
"type": "boolean",
"default": false,
"description": "Use research mode for deeper analysis"
},
"isClaudeCode": {
"type": "boolean",
"default": false,
"description": "Whether Claude Code is being used as the provider"
},
"projectRoot": {
"type": "string",
"default": "",
"description": "Project root path for context"
}
},
"prompts": {
"default": {
"system": "You are an expert software architect and project manager analyzing task complexity. Respond only with the requested valid JSON array.",
"user": "{{#if isClaudeCode}}## IMPORTANT: Codebase Analysis Required\n\nYou have access to powerful codebase analysis tools. Before analyzing task complexity:\n\n1. Use the Glob tool to explore the project structure and understand the codebase size\n2. Use the Grep tool to search for existing implementations related to each task\n3. Use the Read tool to examine key files that would be affected by these tasks\n4. Understand the current implementation state, patterns used, and technical debt\n\nBased on your codebase analysis:\n- Assess complexity based on ACTUAL code that needs to be modified/created\n- Consider existing abstractions and patterns that could simplify implementation\n- Identify tasks that require refactoring vs. greenfield development\n- Factor in dependencies between existing code and new features\n- Provide more accurate subtask recommendations based on real code structure\n\nProject Root: {{projectRoot}}\n\n{{/if}}Analyze the following tasks to determine their complexity (1-10 scale) and recommend the number of subtasks for expansion. Provide a brief reasoning and an initial expansion prompt for each.{{#if useResearch}} Consider current best practices, common implementation patterns, and industry standards in your analysis.{{/if}}\n\nTasks:\n{{{json tasks}}}\n{{#if gatheredContext}}\n\n# Project Context\n\n{{gatheredContext}}\n{{/if}}\n\nRespond ONLY with a valid JSON array matching the schema:\n[\n {\n \"taskId\": <number>,\n \"taskTitle\": \"<string>\",\n \"complexityScore\": <number 1-10>,\n \"recommendedSubtasks\": <number>,\n \"expansionPrompt\": \"<string>\",\n \"reasoning\": \"<string>\"\n },\n ...\n]\n\nDo not include any explanatory text, markdown formatting, or code block markers before or after the JSON array."
"user": "Analyze the following tasks to determine their complexity (1-10 scale) and recommend the number of subtasks for expansion. Provide a brief reasoning and an initial expansion prompt for each.{{#if useResearch}} Consider current best practices, common implementation patterns, and industry standards in your analysis.{{/if}}\n\nTasks:\n{{{json tasks}}}\n{{#if gatheredContext}}\n\n# Project Context\n\n{{gatheredContext}}\n{{/if}}\n\nRespond ONLY with a valid JSON array matching the schema:\n[\n {\n \"taskId\": <number>,\n \"taskTitle\": \"<string>\",\n \"complexityScore\": <number 1-10>,\n \"recommendedSubtasks\": <number>,\n \"expansionPrompt\": \"<string>\",\n \"reasoning\": \"<string>\"\n },\n ...\n]\n\nDo not include any explanatory text, markdown formatting, or code block markers before or after the JSON array."
}
}
}

View File

@@ -51,34 +51,22 @@
"required": false,
"default": "",
"description": "Gathered project context"
},
"isClaudeCode": {
"type": "boolean",
"required": false,
"default": false,
"description": "Whether Claude Code is being used as the provider"
},
"projectRoot": {
"type": "string",
"required": false,
"default": "",
"description": "Project root path for context"
}
},
"prompts": {
"complexity-report": {
"condition": "expansionPrompt",
"system": "You are an AI assistant helping with task breakdown. Generate {{#if (gt subtaskCount 0)}}exactly {{subtaskCount}}{{else}}an appropriate number of{{/if}} subtasks based on the provided prompt and context.\nRespond ONLY with a valid JSON object containing a single key \"subtasks\" whose value is an array of the generated subtask objects.\nEach subtask object in the array must have keys: \"id\", \"title\", \"description\", \"dependencies\", \"details\", \"status\".\nEnsure the 'id' starts from {{nextSubtaskId}} and is sequential.\nFor 'dependencies', use the full subtask ID format: \"{{task.id}}.1\", \"{{task.id}}.2\", etc. Only reference subtasks within this same task.\nEnsure 'status' is 'pending'.\nDo not include any other text or explanation.",
"user": "{{#if isClaudeCode}}## IMPORTANT: Codebase Analysis Required\n\nYou have access to powerful codebase analysis tools. Before generating subtasks:\n\n1. Use the Glob tool to explore relevant files for this task (e.g., \"**/*.js\", \"src/**/*.ts\")\n2. Use the Grep tool to search for existing implementations related to this task\n3. Use the Read tool to examine files that would be affected by this task\n4. Understand the current implementation state and patterns used\n\nBased on your analysis:\n- Identify existing code that relates to this task\n- Understand patterns and conventions to follow\n- Generate subtasks that integrate smoothly with existing code\n- Ensure subtasks are specific and actionable based on the actual codebase\n\nProject Root: {{projectRoot}}\n\n{{/if}}{{expansionPrompt}}{{#if additionalContext}}\n\n{{additionalContext}}{{/if}}{{#if complexityReasoningContext}}\n\n{{complexityReasoningContext}}{{/if}}{{#if gatheredContext}}\n\n# Project Context\n\n{{gatheredContext}}{{/if}}"
"user": "{{expansionPrompt}}{{#if additionalContext}}\n\n{{additionalContext}}{{/if}}{{#if complexityReasoningContext}}\n\n{{complexityReasoningContext}}{{/if}}{{#if gatheredContext}}\n\n# Project Context\n\n{{gatheredContext}}{{/if}}"
},
"research": {
"condition": "useResearch === true && !expansionPrompt",
"system": "You are an AI assistant that responds ONLY with valid JSON objects as requested. The object should contain a 'subtasks' array.",
"user": "{{#if isClaudeCode}}## IMPORTANT: Codebase Analysis Required\n\nYou have access to powerful codebase analysis tools. Before generating subtasks:\n\n1. Use the Glob tool to explore relevant files for this task (e.g., \"**/*.js\", \"src/**/*.ts\")\n2. Use the Grep tool to search for existing implementations related to this task\n3. Use the Read tool to examine files that would be affected by this task\n4. Understand the current implementation state and patterns used\n\nBased on your analysis:\n- Identify existing code that relates to this task\n- Understand patterns and conventions to follow\n- Generate subtasks that integrate smoothly with existing code\n- Ensure subtasks are specific and actionable based on the actual codebase\n\nProject Root: {{projectRoot}}\n\n{{/if}}Analyze the following task and break it down into {{#if (gt subtaskCount 0)}}exactly {{subtaskCount}}{{else}}an appropriate number of{{/if}} specific subtasks using your research capabilities. Assign sequential IDs starting from {{nextSubtaskId}}.\n\nParent Task:\nID: {{task.id}}\nTitle: {{task.title}}\nDescription: {{task.description}}\nCurrent details: {{#if task.details}}{{task.details}}{{else}}None{{/if}}{{#if additionalContext}}\nConsider this context: {{additionalContext}}{{/if}}{{#if complexityReasoningContext}}\nComplexity Analysis Reasoning: {{complexityReasoningContext}}{{/if}}{{#if gatheredContext}}\n\n# Project Context\n\n{{gatheredContext}}{{/if}}\n\nCRITICAL: Respond ONLY with a valid JSON object containing a single key \"subtasks\". The value must be an array of the generated subtasks, strictly matching this structure:\n\n{\n \"subtasks\": [\n {\n \"id\": <number>, // Sequential ID starting from {{nextSubtaskId}}\n \"title\": \"<string>\",\n \"description\": \"<string>\",\n \"dependencies\": [\"<string>\"], // Use full subtask IDs like [\"{{task.id}}.1\", \"{{task.id}}.2\"]. If no dependencies, use an empty array [].\n \"details\": \"<string>\",\n \"testStrategy\": \"<string>\" // Optional\n },\n // ... (repeat for {{#if (gt subtaskCount 0)}}{{subtaskCount}}{{else}}appropriate number of{{/if}} subtasks)\n ]\n}\n\nImportant: For the 'dependencies' field, if a subtask has no dependencies, you MUST use an empty array, for example: \"dependencies\": []. Do not use null or omit the field.\n\nDo not include ANY explanatory text, markdown, or code block markers. Just the JSON object."
"user": "Analyze the following task and break it down into {{#if (gt subtaskCount 0)}}exactly {{subtaskCount}}{{else}}an appropriate number of{{/if}} specific subtasks using your research capabilities. Assign sequential IDs starting from {{nextSubtaskId}}.\n\nParent Task:\nID: {{task.id}}\nTitle: {{task.title}}\nDescription: {{task.description}}\nCurrent details: {{#if task.details}}{{task.details}}{{else}}None{{/if}}{{#if additionalContext}}\nConsider this context: {{additionalContext}}{{/if}}{{#if complexityReasoningContext}}\nComplexity Analysis Reasoning: {{complexityReasoningContext}}{{/if}}{{#if gatheredContext}}\n\n# Project Context\n\n{{gatheredContext}}{{/if}}\n\nCRITICAL: Respond ONLY with a valid JSON object containing a single key \"subtasks\". The value must be an array of the generated subtasks, strictly matching this structure:\n\n{\n \"subtasks\": [\n {\n \"id\": <number>, // Sequential ID starting from {{nextSubtaskId}}\n \"title\": \"<string>\",\n \"description\": \"<string>\",\n \"dependencies\": [\"<string>\"], // Use full subtask IDs like [\"{{task.id}}.1\", \"{{task.id}}.2\"]. If no dependencies, use an empty array [].\n \"details\": \"<string>\",\n \"testStrategy\": \"<string>\" // Optional\n },\n // ... (repeat for {{#if (gt subtaskCount 0)}}{{subtaskCount}}{{else}}appropriate number of{{/if}} subtasks)\n ]\n}\n\nImportant: For the 'dependencies' field, if a subtask has no dependencies, you MUST use an empty array, for example: \"dependencies\": []. Do not use null or omit the field.\n\nDo not include ANY explanatory text, markdown, or code block markers. Just the JSON object."
},
"default": {
"system": "You are an AI assistant helping with task breakdown for software development.\nYou need to break down a high-level task into {{#if (gt subtaskCount 0)}}{{subtaskCount}}{{else}}an appropriate number of{{/if}} specific subtasks that can be implemented one by one.\n\nSubtasks should:\n1. Be specific and actionable implementation steps\n2. Follow a logical sequence\n3. Each handle a distinct part of the parent task\n4. Include clear guidance on implementation approach\n5. Have appropriate dependency chains between subtasks (using full subtask IDs)\n6. Collectively cover all aspects of the parent task\n\nFor each subtask, provide:\n- id: Sequential integer starting from the provided nextSubtaskId\n- title: Clear, specific title\n- description: Detailed description\n- dependencies: Array of prerequisite subtask IDs using full format like [\"{{task.id}}.1\", \"{{task.id}}.2\"]\n- details: Implementation details, the output should be in string\n- testStrategy: Optional testing approach\n\nRespond ONLY with a valid JSON object containing a single key \"subtasks\" whose value is an array matching the structure described. Do not include any explanatory text, markdown formatting, or code block markers.",
"user": "{{#if isClaudeCode}}## IMPORTANT: Codebase Analysis Required\n\nYou have access to powerful codebase analysis tools. Before generating subtasks:\n\n1. Use the Glob tool to explore relevant files for this task (e.g., \"**/*.js\", \"src/**/*.ts\")\n2. Use the Grep tool to search for existing implementations related to this task\n3. Use the Read tool to examine files that would be affected by this task\n4. Understand the current implementation state and patterns used\n\nBased on your analysis:\n- Identify existing code that relates to this task\n- Understand patterns and conventions to follow\n- Generate subtasks that integrate smoothly with existing code\n- Ensure subtasks are specific and actionable based on the actual codebase\n\nProject Root: {{projectRoot}}\n\n{{/if}}Break down this task into {{#if (gt subtaskCount 0)}}exactly {{subtaskCount}}{{else}}an appropriate number of{{/if}} specific subtasks:\n\nTask ID: {{task.id}}\nTitle: {{task.title}}\nDescription: {{task.description}}\nCurrent details: {{#if task.details}}{{task.details}}{{else}}None{{/if}}{{#if additionalContext}}\nAdditional context: {{additionalContext}}{{/if}}{{#if complexityReasoningContext}}\nComplexity Analysis Reasoning: {{complexityReasoningContext}}{{/if}}{{#if gatheredContext}}\n\n# Project Context\n\n{{gatheredContext}}{{/if}}\n\nReturn ONLY the JSON object containing the \"subtasks\" array, matching this structure:\n\n{\n \"subtasks\": [\n {\n \"id\": {{nextSubtaskId}}, // First subtask ID\n \"title\": \"Specific subtask title\",\n \"description\": \"Detailed description\",\n \"dependencies\": [], // e.g., [\"{{task.id}}.1\", \"{{task.id}}.2\"] for dependencies. Use empty array [] if no dependencies\n \"details\": \"Implementation guidance\",\n \"testStrategy\": \"Optional testing approach\"\n },\n // ... (repeat for {{#if (gt subtaskCount 0)}}a total of {{subtaskCount}}{{else}}an appropriate number of{{/if}} subtasks with sequential IDs)\n ]\n}"
"user": "Break down this task into {{#if (gt subtaskCount 0)}}exactly {{subtaskCount}}{{else}}an appropriate number of{{/if}} specific subtasks:\n\nTask ID: {{task.id}}\nTitle: {{task.title}}\nDescription: {{task.description}}\nCurrent details: {{#if task.details}}{{task.details}}{{else}}None{{/if}}{{#if additionalContext}}\nAdditional context: {{additionalContext}}{{/if}}{{#if complexityReasoningContext}}\nComplexity Analysis Reasoning: {{complexityReasoningContext}}{{/if}}{{#if gatheredContext}}\n\n# Project Context\n\n{{gatheredContext}}{{/if}}\n\nReturn ONLY the JSON object containing the \"subtasks\" array, matching this structure:\n\n{\n \"subtasks\": [\n {\n \"id\": {{nextSubtaskId}}, // First subtask ID\n \"title\": \"Specific subtask title\",\n \"description\": \"Detailed description\",\n \"dependencies\": [], // e.g., [\"{{task.id}}.1\", \"{{task.id}}.2\"] for dependencies. Use empty array [] if no dependencies\n \"details\": \"Implementation guidance\",\n \"testStrategy\": \"Optional testing approach\"\n },\n // ... (repeat for {{#if (gt subtaskCount 0)}}a total of {{subtaskCount}}{{else}}an appropriate number of{{/if}} subtasks with sequential IDs)\n ]\n}"
}
}
}

View File

@@ -40,24 +40,12 @@
"default": "medium",
"enum": ["high", "medium", "low"],
"description": "Default priority for generated tasks"
},
"isClaudeCode": {
"type": "boolean",
"required": false,
"default": false,
"description": "Whether Claude Code is being used as the provider"
},
"projectRoot": {
"type": "string",
"required": false,
"default": "",
"description": "Project root path for context"
}
},
"prompts": {
"default": {
"system": "You are an AI assistant specialized in analyzing Product Requirements Documents (PRDs) and generating a structured, logically ordered, dependency-aware and sequenced list of development tasks in JSON format.{{#if research}}\nBefore breaking down the PRD into tasks, you will:\n1. Research and analyze the latest technologies, libraries, frameworks, and best practices that would be appropriate for this project\n2. Identify any potential technical challenges, security concerns, or scalability issues not explicitly mentioned in the PRD without discarding any explicit requirements or going overboard with complexity -- always aim to provide the most direct path to implementation, avoiding over-engineering or roundabout approaches\n3. Consider current industry standards and evolving trends relevant to this project (this step aims to solve LLM hallucinations and out of date information due to training data cutoff dates)\n4. Evaluate alternative implementation approaches and recommend the most efficient path\n5. Include specific library versions, helpful APIs, and concrete implementation guidance based on your research\n6. Always aim to provide the most direct path to implementation, avoiding over-engineering or roundabout approaches\n\nYour task breakdown should incorporate this research, resulting in more detailed implementation guidance, more accurate dependency mapping, and more precise technology recommendations than would be possible from the PRD text alone, while maintaining all explicit requirements and best practices and all details and nuances of the PRD.{{/if}}\n\nAnalyze the provided PRD content and generate {{#if (gt numTasks 0)}}approximately {{numTasks}}{{else}}an appropriate number of{{/if}} top-level development tasks. If the complexity or the level of detail of the PRD is high, generate more tasks relative to the complexity of the PRD\nEach task should represent a logical unit of work needed to implement the requirements and focus on the most direct and effective way to implement the requirements without unnecessary complexity or overengineering. Include pseudo-code, implementation details, and test strategy for each task. Find the most up to date information to implement each task.\nAssign sequential IDs starting from {{nextId}}. Infer title, description, details, and test strategy for each task based *only* on the PRD content.\nSet status to 'pending', dependencies to an empty array [], and priority to '{{defaultTaskPriority}}' initially for all tasks.\nRespond ONLY with a valid JSON object containing a single key \"tasks\", where the value is an array of task objects adhering to the provided Zod schema. Do not include any explanation or markdown formatting.\n\nEach task should follow this JSON structure:\n{\n\t\"id\": number,\n\t\"title\": string,\n\t\"description\": string,\n\t\"status\": \"pending\",\n\t\"dependencies\": number[] (IDs of tasks this depends on),\n\t\"priority\": \"high\" | \"medium\" | \"low\",\n\t\"details\": string (implementation details),\n\t\"testStrategy\": string (validation approach)\n}\n\nGuidelines:\n1. {{#if (gt numTasks 0)}}Unless complexity warrants otherwise{{else}}Depending on the complexity{{/if}}, create {{#if (gt numTasks 0)}}exactly {{numTasks}}{{else}}an appropriate number of{{/if}} tasks, numbered sequentially starting from {{nextId}}\n2. Each task should be atomic and focused on a single responsibility following the most up to date best practices and standards\n3. Order tasks logically - consider dependencies and implementation sequence\n4. Early tasks should focus on setup, core functionality first, then advanced features\n5. Include clear validation/testing approach for each task\n6. Set appropriate dependency IDs (a task can only depend on tasks with lower IDs, potentially including existing tasks with IDs less than {{nextId}} if applicable)\n7. Assign priority (high/medium/low) based on criticality and dependency order\n8. Include detailed implementation guidance in the \"details\" field{{#if research}}, with specific libraries and version recommendations based on your research{{/if}}\n9. If the PRD contains specific requirements for libraries, database schemas, frameworks, tech stacks, or any other implementation details, STRICTLY ADHERE to these requirements in your task breakdown and do not discard them under any circumstance\n10. Focus on filling in any gaps left by the PRD or areas that aren't fully specified, while preserving all explicit requirements\n11. Always aim to provide the most direct path to implementation, avoiding over-engineering or roundabout approaches{{#if research}}\n12. For each task, include specific, actionable guidance based on current industry standards and best practices discovered through research{{/if}}",
"user": "{{#if isClaudeCode}}## IMPORTANT: Codebase Analysis Required\n\nYou have access to powerful codebase analysis tools. Before generating tasks:\n\n1. Use the Glob tool to explore the project structure (e.g., \"**/*.js\", \"**/*.json\", \"**/README.md\")\n2. Use the Grep tool to search for existing implementations, patterns, and technologies\n3. Use the Read tool to examine key files like package.json, README.md, and main entry points\n4. Analyze the current state of implementation to understand what already exists\n\nBased on your analysis:\n- Identify what components/features are already implemented\n- Understand the technology stack, frameworks, and patterns in use\n- Generate tasks that build upon the existing codebase rather than duplicating work\n- Ensure tasks align with the project's current architecture and conventions\n\nProject Root: {{projectRoot}}\n\n{{/if}}Here's the Product Requirements Document (PRD) to break down into {{#if (gt numTasks 0)}}approximately {{numTasks}}{{else}}an appropriate number of{{/if}} tasks, starting IDs from {{nextId}}:{{#if research}}\n\nRemember to thoroughly research current best practices and technologies before task breakdown to provide specific, actionable implementation details.{{/if}}\n\n{{prdContent}}\n\n\n\t\tReturn your response in this format:\n{\n \"tasks\": [\n {\n \"id\": 1,\n \"title\": \"Setup Project Repository\",\n \"description\": \"...\",\n ...\n },\n ...\n ],\n \"metadata\": {\n \"projectName\": \"PRD Implementation\",\n \"totalTasks\": {{#if (gt numTasks 0)}}{{numTasks}}{{else}}{number of tasks}{{/if}},\n \"sourceFile\": \"{{prdPath}}\",\n \"generatedAt\": \"YYYY-MM-DD\"\n }\n}"
"user": "Here's the Product Requirements Document (PRD) to break down into {{#if (gt numTasks 0)}}approximately {{numTasks}}{{else}}an appropriate number of{{/if}} tasks, starting IDs from {{nextId}}:{{#if research}}\n\nRemember to thoroughly research current best practices and technologies before task breakdown to provide specific, actionable implementation details.{{/if}}\n\n{{prdContent}}\n\n\n\t\tReturn your response in this format:\n{\n \"tasks\": [\n {\n \"id\": 1,\n \"title\": \"Setup Project Repository\",\n \"description\": \"...\",\n ...\n },\n ...\n ],\n \"metadata\": {\n \"projectName\": \"PRD Implementation\",\n \"totalTasks\": {{#if (gt numTasks 0)}}{{numTasks}}{{else}}{number of tasks}{{/if}},\n \"sourceFile\": \"{{prdPath}}\",\n \"generatedAt\": \"YYYY-MM-DD\"\n }\n}"
}
}
}

View File

@@ -123,9 +123,7 @@ jest.unstable_mockModule(
() => ({
getDefaultSubtasks: jest.fn(() => 3),
getDebugFlag: jest.fn(() => false),
getDefaultNumTasks: jest.fn(() => 10),
getMainProvider: jest.fn(() => 'openai'),
getResearchProvider: jest.fn(() => 'perplexity')
getDefaultNumTasks: jest.fn(() => 10)
})
);

View File

@@ -49,9 +49,7 @@ jest.unstable_mockModule(
() => ({
getDebugFlag: jest.fn(() => false),
getDefaultNumTasks: jest.fn(() => 10),
getDefaultPriority: jest.fn(() => 'medium'),
getMainProvider: jest.fn(() => 'openai'),
getResearchProvider: jest.fn(() => 'perplexity')
getDefaultPriority: jest.fn(() => 'medium')
})
);