diff --git a/src/core/task/Task.ts b/src/core/task/Task.ts index 31260cd6fa..15f7f1cb0e 100644 --- a/src/core/task/Task.ts +++ b/src/core/task/Task.ts @@ -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 { 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`) diff --git a/src/core/task/TaskComplexityAnalyzer.ts b/src/core/task/TaskComplexityAnalyzer.ts new file mode 100644 index 0000000000..fff1c1a51a --- /dev/null +++ b/src/core/task/TaskComplexityAnalyzer.ts @@ -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 = {}) { + 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 { + 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): void { + this.config = { ...this.config, ...newConfig } + } + + /** + * Gets the current configuration + */ + getConfig(): AutoTodoConfig { + return { ...this.config } + } +} diff --git a/src/tests/task/Task-AutoTodo.test.ts b/src/tests/task/Task-AutoTodo.test.ts new file mode 100644 index 0000000000..2a6a1a0843 --- /dev/null +++ b/src/tests/task/Task-AutoTodo.test.ts @@ -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() + }) +}) diff --git a/src/tests/task/TaskComplexityAnalyzer.test.ts b/src/tests/task/TaskComplexityAnalyzer.test.ts new file mode 100644 index 0000000000..4ced16d33e --- /dev/null +++ b/src/tests/task/TaskComplexityAnalyzer.test.ts @@ -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) + }) +})