feat: implement automatic TODO list creation for complex tasks (#5470)

- Add TaskComplexityAnalyzer module to analyze task complexity using keyword analysis, pattern matching, and structural analysis
- Integrate automatic TODO creation into Task.startTask() method without manual user intervention
- Generate contextual TODO items based on task type (API development, UI components, bug fixes, etc.)
- Add comprehensive test coverage with 12 passing tests
- Maintain backward compatibility with existing TODO list functionality
- Follow existing codebase patterns and TypeScript best practices

Fixes #5470
This commit is contained in:
Roo Code 2025-07-08 17:02:59 +00:00
parent 6ab57fae43
commit 37e0eac77e
4 changed files with 846 additions and 0 deletions

View file

@ -87,6 +87,7 @@ import { ApiMessage } from "../task-persistence/apiMessages"
import { getMessagesSinceLastSummary, summarizeConversation } from "../condense"
import { maybeRemoveImageBlocks } from "../../api/transform/image-cleaning"
import { restoreTodoListForTask } from "../tools/updateTodoListTool"
import { TaskComplexityAnalyzer, DEFAULT_AUTO_TODO_CONFIG } from "./TaskComplexityAnalyzer"
// Constants
const MAX_EXPONENTIAL_BACKOFF_SECONDS = 600 // 10 minutes
@ -743,6 +744,32 @@ export class Task extends EventEmitter<ClineEvents> {
await this.say("text", task, images)
this.isInitialized = true
// Check if we should automatically create a TODO list for this task
if (task) {
try {
const analyzer = new TaskComplexityAnalyzer(DEFAULT_AUTO_TODO_CONFIG)
const analysis = analyzer.analyzeTask(task)
if (analysis.shouldCreateTodos && analysis.suggestedTodos.length > 0) {
// Create automatic TODO list without user intervention
this.todoList = analysis.suggestedTodos.map((todo, index) => ({
id: `auto-${index + 1}`,
content: todo,
status: "pending" as const,
}))
// Notify user that automatic TODO list was created
await this.say(
"text",
`📋 **Automatic TODO List Created**\n\nBased on the task complexity, I've created a TODO list to help track progress:\n\n${analysis.suggestedTodos.map((todo, i) => `${i + 1}. ${todo}`).join("\n")}\n\nI'll update this list as I work through the task.`,
)
}
} catch (error) {
// Don't let TODO creation errors interrupt task execution
console.warn("Failed to create automatic TODO list:", error)
}
}
let imageBlocks: Anthropic.ImageBlockParam[] = formatResponse.imageBlocks(images)
console.log(`[subtasks] task ${this.taskId}.${this.instanceId} starting`)

View file

@ -0,0 +1,391 @@
import { TodoItem } from "@roo-code/types"
import { addTodoToTask } from "../tools/updateTodoListTool"
import { Task } from "./Task"
/**
* Configuration for automatic TODO list creation
*/
export interface AutoTodoConfig {
enabled: boolean
complexityThreshold: number
minTaskLength: number
maxInitialTodos: number
}
/**
* Default configuration for automatic TODO list creation
*/
export const DEFAULT_AUTO_TODO_CONFIG: AutoTodoConfig = {
enabled: true,
complexityThreshold: 3, // Minimum complexity score to trigger auto TODO
minTaskLength: 50, // Minimum task description length
maxInitialTodos: 8, // Maximum number of initial TODOs to create
}
/**
* Keywords that indicate task complexity and suggest multiple steps
*/
const COMPLEXITY_KEYWORDS = {
// High complexity indicators (weight: 3)
high: [
"create",
"build",
"implement",
"develop",
"design",
"architect",
"full-stack",
"end-to-end",
"complete",
"entire",
"comprehensive",
"system",
"application",
"project",
"framework",
"platform",
"integrate",
"configure",
"setup",
"install",
"deploy",
],
// Medium complexity indicators (weight: 2)
medium: [
"add",
"update",
"modify",
"refactor",
"optimize",
"improve",
"enhance",
"extend",
"migrate",
"convert",
"transform",
"test",
"debug",
"fix",
"resolve",
"handle",
"manage",
],
// Step indicators (weight: 2)
steps: [
"step",
"steps",
"phase",
"phases",
"stage",
"stages",
"first",
"then",
"next",
"after",
"before",
"finally",
"initially",
"subsequently",
"process",
"workflow",
],
// Multiple item indicators (weight: 1)
multiple: [
"multiple",
"several",
"various",
"different",
"many",
"all",
"each",
"every",
"both",
"and",
"also",
"plus",
],
}
/**
* Patterns that suggest multiple steps or complex workflows
*/
const COMPLEXITY_PATTERNS = [
// Lists or enumerations
/\d+\.\s+/g, // "1. ", "2. ", etc.
/[-*]\s+/g, // "- " or "* " bullet points
/\b(first|second|third|fourth|fifth|then|next|after|finally)\b/gi,
// Conditional or branching logic
/\b(if|when|unless|depending|based on|according to)\b/gi,
// Multiple technologies or components
/\b(with|using|and|plus|\+|&)\s+\w+/gi,
// Authentication, database, API patterns
/\b(auth|database|api|frontend|backend|server|client)\b/gi,
]
/**
* Analyzes task description to determine complexity and suggest initial TODOs
*/
export class TaskComplexityAnalyzer {
private config: AutoTodoConfig
constructor(config: Partial<AutoTodoConfig> = {}) {
this.config = { ...DEFAULT_AUTO_TODO_CONFIG, ...config }
}
/**
* Analyzes a task description and returns complexity score and suggested TODOs
*/
analyzeTask(taskDescription: string): {
complexityScore: number
shouldCreateTodos: boolean
suggestedTodos: string[]
reasoning: string[]
} {
if (!taskDescription || taskDescription.length < this.config.minTaskLength) {
return {
complexityScore: 0,
shouldCreateTodos: false,
suggestedTodos: [],
reasoning: ["Task description too short for complexity analysis"],
}
}
const reasoning: string[] = []
let complexityScore = 0
// Analyze keyword complexity
const keywordScore = this.analyzeKeywords(taskDescription, reasoning)
complexityScore += keywordScore
// Analyze pattern complexity
const patternScore = this.analyzePatterns(taskDescription, reasoning)
complexityScore += patternScore
// Analyze length and structure
const structureScore = this.analyzeStructure(taskDescription, reasoning)
complexityScore += structureScore
// Generate suggested TODOs based on the task
const suggestedTodos = this.generateSuggestedTodos(taskDescription, complexityScore)
const shouldCreateTodos =
this.config.enabled && complexityScore >= this.config.complexityThreshold && suggestedTodos.length > 0
reasoning.push(`Total complexity score: ${complexityScore}`)
reasoning.push(`Threshold: ${this.config.complexityThreshold}`)
reasoning.push(`Should create TODOs: ${shouldCreateTodos}`)
return {
complexityScore,
shouldCreateTodos,
suggestedTodos,
reasoning,
}
}
/**
* Analyzes keywords in the task description
*/
private analyzeKeywords(task: string, reasoning: string[]): number {
const lowerTask = task.toLowerCase()
let score = 0
// Check high complexity keywords
const highMatches = COMPLEXITY_KEYWORDS.high.filter((keyword) => lowerTask.includes(keyword))
if (highMatches.length > 0) {
score += highMatches.length * 3
reasoning.push(`High complexity keywords found: ${highMatches.join(", ")} (+${highMatches.length * 3})`)
}
// Check medium complexity keywords
const mediumMatches = COMPLEXITY_KEYWORDS.medium.filter((keyword) => lowerTask.includes(keyword))
if (mediumMatches.length > 0) {
score += mediumMatches.length * 2
reasoning.push(
`Medium complexity keywords found: ${mediumMatches.join(", ")} (+${mediumMatches.length * 2})`,
)
}
// Check step indicators
const stepMatches = COMPLEXITY_KEYWORDS.steps.filter((keyword) => lowerTask.includes(keyword))
if (stepMatches.length > 0) {
score += stepMatches.length * 2
reasoning.push(`Step indicators found: ${stepMatches.join(", ")} (+${stepMatches.length * 2})`)
}
// Check multiple item indicators
const multipleMatches = COMPLEXITY_KEYWORDS.multiple.filter((keyword) => lowerTask.includes(keyword))
if (multipleMatches.length > 0) {
score += multipleMatches.length * 1
reasoning.push(`Multiple item indicators found: ${multipleMatches.join(", ")} (+${multipleMatches.length})`)
}
return score
}
/**
* Analyzes patterns that suggest complexity
*/
private analyzePatterns(task: string, reasoning: string[]): number {
let score = 0
for (const pattern of COMPLEXITY_PATTERNS) {
const matches = task.match(pattern)
if (matches && matches.length > 0) {
score += matches.length
reasoning.push(`Pattern matches for ${pattern.source}: ${matches.length} (+${matches.length})`)
}
}
return Math.min(score, 10) // Cap pattern score at 10
}
/**
* Analyzes task structure and length
*/
private analyzeStructure(task: string, reasoning: string[]): number {
let score = 0
// Length-based scoring
if (task.length > 200) {
score += 2
reasoning.push("Long task description (+2)")
} else if (task.length > 100) {
score += 1
reasoning.push("Medium task description (+1)")
}
// Sentence count
const sentences = task.split(/[.!?]+/).filter((s) => s.trim().length > 0)
if (sentences.length > 3) {
score += 2
reasoning.push(`Multiple sentences: ${sentences.length} (+2)`)
}
// Line breaks suggest structured content
const lines = task.split(/\n/).filter((l) => l.trim().length > 0)
if (lines.length > 2) {
score += 1
reasoning.push(`Multiple lines: ${lines.length} (+1)`)
}
return score
}
/**
* Generates suggested TODO items based on task analysis
*/
private generateSuggestedTodos(task: string, complexityScore: number): string[] {
const todos: string[] = []
const lowerTask = task.toLowerCase()
// Common patterns for different types of tasks
if (this.containsAny(lowerTask, ["create", "build", "develop", "implement"])) {
if (this.containsAny(lowerTask, ["app", "application", "website", "system"])) {
todos.push("Analyze requirements and define scope")
todos.push("Design system architecture")
todos.push("Set up project structure")
todos.push("Implement core functionality")
todos.push("Add error handling and validation")
todos.push("Write tests")
todos.push("Update documentation")
} else if (this.containsAny(lowerTask, ["api", "endpoint", "service"])) {
todos.push("Define API specification")
todos.push("Set up routing and middleware")
todos.push("Implement endpoint logic")
todos.push("Add authentication and authorization")
todos.push("Write API tests")
todos.push("Update API documentation")
} else if (this.containsAny(lowerTask, ["component", "ui", "interface"])) {
todos.push("Design component interface")
todos.push("Implement component logic")
todos.push("Add styling and responsive design")
todos.push("Handle user interactions")
todos.push("Write component tests")
todos.push("Update component documentation")
}
}
if (this.containsAny(lowerTask, ["fix", "debug", "resolve", "issue"])) {
todos.push("Reproduce the issue")
todos.push("Identify root cause")
todos.push("Implement fix")
todos.push("Test the solution")
todos.push("Verify no regression")
}
if (this.containsAny(lowerTask, ["refactor", "optimize", "improve"])) {
todos.push("Analyze current implementation")
todos.push("Identify improvement opportunities")
todos.push("Plan refactoring approach")
todos.push("Implement improvements")
todos.push("Test refactored code")
todos.push("Update related documentation")
}
if (this.containsAny(lowerTask, ["setup", "configure", "install"])) {
todos.push("Review setup requirements")
todos.push("Install dependencies")
todos.push("Configure environment")
todos.push("Test configuration")
todos.push("Document setup process")
}
// If no specific patterns matched, create generic todos based on complexity
if (todos.length === 0 && complexityScore >= this.config.complexityThreshold) {
todos.push("Break down the task into smaller steps")
todos.push("Analyze requirements and constraints")
todos.push("Plan implementation approach")
todos.push("Execute the main task")
todos.push("Test and verify results")
}
// Limit the number of initial todos
return todos.slice(0, this.config.maxInitialTodos)
}
/**
* Helper method to check if text contains any of the given keywords
*/
private containsAny(text: string, keywords: string[]): boolean {
return keywords.some((keyword) => text.includes(keyword))
}
/**
* Creates automatic TODO list for a task if complexity threshold is met
*/
async createAutomaticTodoList(cline: Task, taskDescription: string): Promise<boolean> {
const analysis = this.analyzeTask(taskDescription)
if (!analysis.shouldCreateTodos) {
return false
}
// Create TODO items
for (const todoContent of analysis.suggestedTodos) {
addTodoToTask(cline, todoContent, "pending")
}
// Log the automatic TODO creation
await cline.say(
"text",
`🎯 **Automatic TODO List Created**\n\nDetected complex task requiring step-by-step tracking. Created ${analysis.suggestedTodos.length} initial TODO items:\n\n${analysis.suggestedTodos.map((todo, i) => `${i + 1}. ${todo}`).join("\n")}\n\n*You can update this list as the task progresses using the update_todo_list tool.*`,
)
return true
}
/**
* Updates the configuration
*/
updateConfig(newConfig: Partial<AutoTodoConfig>): void {
this.config = { ...this.config, ...newConfig }
}
/**
* Gets the current configuration
*/
getConfig(): AutoTodoConfig {
return { ...this.config }
}
}

View file

@ -0,0 +1,229 @@
import { describe, test, expect, vi, beforeEach } from "vitest"
import { Task } from "../../core/task/Task"
import { ClineProvider } from "../../core/webview/ClineProvider"
// Mock the ClineProvider and its dependencies
vi.mock("../../core/webview/ClineProvider")
vi.mock("vscode", () => ({
workspace: {
workspaceFolders: [],
onDidChangeWorkspaceFolders: vi.fn(),
createFileSystemWatcher: vi.fn(() => ({
dispose: vi.fn(),
onDidChange: vi.fn(),
onDidCreate: vi.fn(),
onDidDelete: vi.fn(),
})),
},
window: {
createTextEditorDecorationType: vi.fn(() => ({
dispose: vi.fn(),
})),
showInformationMessage: vi.fn(),
showErrorMessage: vi.fn(),
showWarningMessage: vi.fn(),
createWebviewPanel: vi.fn(),
registerWebviewViewProvider: vi.fn(),
onDidChangeActiveTextEditor: vi.fn(),
activeTextEditor: undefined,
},
Uri: {
file: vi.fn((path) => ({ fsPath: path, path })),
},
RelativePattern: vi.fn(),
FileSystemWatcher: vi.fn(),
EventEmitter: vi.fn(() => ({
event: vi.fn(),
fire: vi.fn(),
dispose: vi.fn(),
})),
ExtensionContext: vi.fn(),
ViewColumn: {
One: 1,
Two: 2,
Three: 3,
},
TextEditorRevealType: {
Default: 0,
InCenter: 1,
InCenterIfOutsideViewport: 2,
},
}))
// Mock other dependencies
vi.mock("../../services/mcp/McpServerManager", () => ({
McpServerManager: {
getInstance: vi.fn(() => Promise.resolve(null)),
},
}))
vi.mock("../../core/prompts/system", () => ({
SYSTEM_PROMPT: vi.fn(() => "test system prompt"),
}))
vi.mock("../../core/environment/getEnvironmentDetails", () => ({
getEnvironmentDetails: vi.fn(() => Promise.resolve("test environment")),
}))
vi.mock("@roo-code/telemetry", () => ({
TelemetryService: {
instance: {
captureTaskCreated: vi.fn(),
captureTaskRestarted: vi.fn(),
captureConversationMessage: vi.fn(),
captureLlmCompletion: vi.fn(),
captureConsecutiveMistakeError: vi.fn(),
},
},
}))
vi.mock("@roo-code/cloud", () => ({
CloudService: {
isEnabled: vi.fn(() => false),
instance: {
captureEvent: vi.fn(),
},
},
}))
describe("Task Auto TODO Integration", () => {
let mockProvider: any
beforeEach(() => {
vi.clearAllMocks()
mockProvider = {
context: {
globalStorageUri: { fsPath: "/tmp/test" },
subscriptions: [],
},
getState: vi.fn(() =>
Promise.resolve({
mode: "code",
experiments: {},
browserViewportSize: "1024x768",
}),
),
postStateToWebview: vi.fn(),
postMessageToWebview: vi.fn(),
updateTaskHistory: vi.fn(),
log: vi.fn(),
providerSettingsManager: {
getProfile: vi.fn(),
},
}
})
test("should create automatic TODO list for complex tasks", async () => {
const complexTask = `
Create a comprehensive web application with the following features:
1. User authentication system with login and registration
2. Dashboard with real-time analytics
3. Settings page with user preferences
4. API integration with external services
5. Mobile responsive design
6. Comprehensive testing suite
`
// Mock the say method to capture TODO creation message
const sayMock = vi.fn()
// Use Task.create to properly start the task
const [task, taskPromise] = Task.create({
provider: mockProvider as ClineProvider,
apiConfiguration: {
apiProvider: "anthropic",
apiKey: "test-key",
apiModelId: "claude-3-sonnet-20240229",
},
task: complexTask,
})
// Replace the say method after creation but before task starts
task.say = sayMock
// Wait for task to start (this will trigger the automatic TODO creation)
await taskPromise.catch(() => {
// Ignore errors from the task execution since we're just testing TODO creation
})
// Verify that a TODO list was created
expect(task.todoList).toBeDefined()
expect(task.todoList!.length).toBeGreaterThan(0)
// Verify that all TODO items have the correct structure
task.todoList!.forEach((todo) => {
expect(todo).toHaveProperty("id")
expect(todo).toHaveProperty("content")
expect(todo).toHaveProperty("status")
expect(todo.status).toBe("pending")
})
// Verify that a notification message was sent about TODO creation
expect(sayMock).toHaveBeenCalledWith("text", expect.stringContaining("Automatic TODO List Created"))
})
test("should not create TODO list for simple tasks", async () => {
const simpleTask = "Fix the typo in README.md"
// Mock the say method to capture TODO creation message
const sayMock = vi.fn()
// Use Task.create to properly start the task
const [task, taskPromise] = Task.create({
provider: mockProvider as ClineProvider,
apiConfiguration: {
apiProvider: "anthropic",
apiKey: "test-key",
apiModelId: "claude-3-sonnet-20240229",
},
task: simpleTask,
})
// Replace the say method after creation but before task starts
task.say = sayMock
// Wait for task to start
await taskPromise.catch(() => {
// Ignore errors from the task execution since we're just testing TODO creation
})
// Verify that no TODO list was created
expect(task.todoList).toBeUndefined()
// Verify that no TODO creation message was sent
expect(sayMock).not.toHaveBeenCalledWith("text", expect.stringContaining("Automatic TODO List Created"))
})
test("should handle TODO creation errors gracefully", async () => {
const complexTask = "Create a comprehensive application with multiple features and integrations"
// Mock console.warn to capture error handling
const warnMock = vi.spyOn(console, "warn").mockImplementation(() => {})
// Mock the say method to capture TODO creation message
const sayMock = vi.fn()
// Use Task.create to properly start the task
const [task, taskPromise] = Task.create({
provider: mockProvider as ClineProvider,
apiConfiguration: {
apiProvider: "anthropic",
apiKey: "test-key",
apiModelId: "claude-3-sonnet-20240229",
},
task: complexTask,
})
// Replace the say method after creation but before task starts
task.say = sayMock
// Should not throw an error even if TODO creation fails
await expect(taskPromise).rejects.toThrow() // Task will fail due to mocking, but that's expected
// The task should still be created even if it fails later
expect(task).toBeDefined()
warnMock.mockRestore()
})
})

View file

@ -0,0 +1,199 @@
import { describe, test, expect } from "vitest"
import { TaskComplexityAnalyzer, DEFAULT_AUTO_TODO_CONFIG } from "../../core/task/TaskComplexityAnalyzer"
describe("TaskComplexityAnalyzer", () => {
test("should detect simple tasks and not create TODOs", () => {
const analyzer = new TaskComplexityAnalyzer(DEFAULT_AUTO_TODO_CONFIG)
const result = analyzer.analyzeTask("Fix the typo in the README file")
expect(result.shouldCreateTodos).toBe(false)
expect(result.complexityScore).toBeLessThan(DEFAULT_AUTO_TODO_CONFIG.complexityThreshold)
expect(result.suggestedTodos).toHaveLength(0)
})
test("should detect complex tasks and create TODOs", () => {
const analyzer = new TaskComplexityAnalyzer(DEFAULT_AUTO_TODO_CONFIG)
const complexTask = `
Create a new React component for user authentication that includes:
1. Login form with email and password validation
2. Registration form with email verification
3. Password reset functionality
4. Integration with backend API
5. Error handling and loading states
6. Unit tests for all components
7. Documentation and examples
`
const result = analyzer.analyzeTask(complexTask)
expect(result.shouldCreateTodos).toBe(true)
expect(result.complexityScore).toBeGreaterThanOrEqual(DEFAULT_AUTO_TODO_CONFIG.complexityThreshold)
expect(result.suggestedTodos.length).toBeGreaterThan(0)
expect(result.reasoning.length).toBeGreaterThan(0)
})
test("should detect multi-step tasks", () => {
const analyzer = new TaskComplexityAnalyzer(DEFAULT_AUTO_TODO_CONFIG)
const multiStepTask = `
First, analyze the existing codebase structure.
Then, implement the new feature.
Next, write comprehensive tests.
Finally, update the documentation.
`
const result = analyzer.analyzeTask(multiStepTask)
expect(result.shouldCreateTodos).toBe(true)
expect(result.complexityScore).toBeGreaterThanOrEqual(DEFAULT_AUTO_TODO_CONFIG.complexityThreshold)
expect(result.suggestedTodos.length).toBeGreaterThan(0)
// The analyzer generates contextual TODOs based on keywords, not exact text
expect(result.suggestedTodos.some((todo) => todo.toLowerCase().includes("implement"))).toBe(true)
})
test("should detect numbered lists", () => {
const analyzer = new TaskComplexityAnalyzer(DEFAULT_AUTO_TODO_CONFIG)
const numberedTask = `
Please complete the following tasks:
1. Set up the development environment
2. Create the database schema
3. Implement the API endpoints
4. Build the frontend interface
5. Deploy to staging environment
`
const result = analyzer.analyzeTask(numberedTask)
expect(result.shouldCreateTodos).toBe(true)
expect(result.complexityScore).toBeGreaterThanOrEqual(DEFAULT_AUTO_TODO_CONFIG.complexityThreshold)
expect(result.suggestedTodos.length).toBeGreaterThan(0)
// The analyzer detects "implement" and "api" keywords and generates contextual TODOs
expect(result.suggestedTodos.some((todo) => todo.toLowerCase().includes("api"))).toBe(true)
})
test("should detect bullet point lists", () => {
const analyzer = new TaskComplexityAnalyzer(DEFAULT_AUTO_TODO_CONFIG)
const bulletTask = `
Create a new feature that includes:
- User authentication system
- Dashboard with analytics
- Settings page with preferences
- Email notification system
- Mobile responsive design
`
const result = analyzer.analyzeTask(bulletTask)
expect(result.shouldCreateTodos).toBe(true)
expect(result.complexityScore).toBeGreaterThanOrEqual(DEFAULT_AUTO_TODO_CONFIG.complexityThreshold)
expect(result.suggestedTodos.length).toBeGreaterThan(0)
// The analyzer detects "create" keyword and generates contextual TODOs for applications
expect(
result.suggestedTodos.some(
(todo) =>
todo.toLowerCase().includes("implement") ||
todo.toLowerCase().includes("design") ||
todo.toLowerCase().includes("analyze"),
),
).toBe(true)
})
test("should handle custom configuration", () => {
const customConfig = {
enabled: true,
complexityThreshold: 10,
minTaskLength: 20,
maxInitialTodos: 3,
}
const analyzer = new TaskComplexityAnalyzer(customConfig)
const task = "Implement a new feature and create comprehensive tests"
const result = analyzer.analyzeTask(task)
expect(result.complexityScore).toBeGreaterThan(0)
expect(result.suggestedTodos.length).toBeLessThanOrEqual(customConfig.maxInitialTodos)
})
test("should respect enabled setting", () => {
const disabledConfig = {
...DEFAULT_AUTO_TODO_CONFIG,
enabled: false,
}
const analyzer = new TaskComplexityAnalyzer(disabledConfig)
const complexTask = `
Create a comprehensive web application with:
1. Frontend React components
2. Backend API with authentication
3. Database design and implementation
4. Testing suite
5. Documentation
`
const result = analyzer.analyzeTask(complexTask)
expect(result.shouldCreateTodos).toBe(false)
// TODOs may still be generated for analysis, but shouldCreateTodos should be false
expect(result.complexityScore).toBeGreaterThan(0)
})
test("should generate contextual TODOs based on task type", () => {
const analyzer = new TaskComplexityAnalyzer(DEFAULT_AUTO_TODO_CONFIG)
// Bug fix task
const bugTask = "Fix the authentication bug where users cannot log in with special characters in their password"
const bugResult = analyzer.analyzeTask(bugTask)
if (bugResult.shouldCreateTodos) {
expect(
bugResult.suggestedTodos.some(
(todo) =>
todo.toLowerCase().includes("reproduce") ||
todo.toLowerCase().includes("identify") ||
todo.toLowerCase().includes("test"),
),
).toBe(true)
}
// Feature task
const featureTask = "Implement a new user dashboard with analytics, charts, and user management capabilities"
const featureResult = analyzer.analyzeTask(featureTask)
if (featureResult.shouldCreateTodos) {
expect(
featureResult.suggestedTodos.some(
(todo) =>
todo.toLowerCase().includes("design") ||
todo.toLowerCase().includes("implement") ||
todo.toLowerCase().includes("test"),
),
).toBe(true)
}
})
test("should limit number of suggested TODOs", () => {
const analyzer = new TaskComplexityAnalyzer(DEFAULT_AUTO_TODO_CONFIG)
const longTask = `
Create a massive application with:
1. User authentication
2. User profiles
3. Dashboard
4. Analytics
5. Reporting
6. Settings
7. Admin panel
8. API documentation
9. Testing suite
10. Deployment scripts
11. Monitoring
12. Logging
13. Error handling
14. Performance optimization
15. Security audit
`
const result = analyzer.analyzeTask(longTask)
expect(result.suggestedTodos.length).toBeLessThanOrEqual(DEFAULT_AUTO_TODO_CONFIG.maxInitialTodos)
})
})