solve merge conflics with next. not gonna deal with these much longer.
This commit is contained in:
288
.taskmaster/tasks/task_097.txt
Normal file
288
.taskmaster/tasks/task_097.txt
Normal file
@@ -0,0 +1,288 @@
|
||||
# Task ID: 97
|
||||
# Title: Implement Git Workflow Integration
|
||||
# Status: pending
|
||||
# Dependencies: None
|
||||
# Priority: high
|
||||
# Description: Add `task-master git` command suite to automate git workflows based on established patterns from Task 4, eliminating manual overhead and ensuring 100% consistency
|
||||
# Details:
|
||||
Create a comprehensive git workflow automation system that integrates deeply with TaskMaster's task management. The feature will:
|
||||
|
||||
1. **Automated Branch Management**:
|
||||
- Create branches following `task-{id}` naming convention
|
||||
- Validate branch names and prevent conflicts
|
||||
- Handle branch switching with uncommitted changes
|
||||
- Clean up local and remote branches post-merge
|
||||
|
||||
2. **Intelligent Commit Generation**:
|
||||
- Auto-detect commit type (feat/fix/test/refactor/docs) from file changes
|
||||
- Generate standardized commit messages with task context
|
||||
- Support subtask-specific commits with proper references
|
||||
- Include coverage delta in test commits
|
||||
|
||||
3. **PR Automation**:
|
||||
- Generate comprehensive PR descriptions from task/subtask data
|
||||
- Include implementation details, test coverage, breaking changes
|
||||
- Format using GitHub markdown with task hierarchy
|
||||
- Auto-populate PR template with relevant metadata
|
||||
|
||||
4. **Workflow State Management**:
|
||||
- Track current task branch and status
|
||||
- Validate task readiness before PR creation
|
||||
- Ensure all subtasks completed before finishing
|
||||
- Handle merge conflicts gracefully
|
||||
|
||||
5. **Integration Points**:
|
||||
- Seamless integration with existing task commands
|
||||
- MCP server support for IDE integrations
|
||||
- GitHub CLI (`gh`) authentication support
|
||||
- Coverage report parsing and display
|
||||
|
||||
**Technical Architecture**:
|
||||
- Modular command structure in `scripts/modules/task-manager/git-*`
|
||||
- Git operations wrapper using simple-git or native child_process
|
||||
- Template engine for commit/PR generation in `scripts/modules/`
|
||||
- State persistence in `.taskmaster/git-state.json`
|
||||
- Error recovery and rollback mechanisms
|
||||
|
||||
**Key Files to Create**:
|
||||
- `scripts/modules/task-manager/git-start.js` - Branch creation and task status update
|
||||
- `scripts/modules/task-manager/git-commit.js` - Intelligent commit message generation
|
||||
- `scripts/modules/task-manager/git-pr.js` - PR creation with auto-generated description
|
||||
- `scripts/modules/task-manager/git-finish.js` - Post-merge cleanup and status update
|
||||
- `scripts/modules/task-manager/git-status.js` - Current git workflow state display
|
||||
- `scripts/modules/git-operations.js` - Core git functionality wrapper
|
||||
- `scripts/modules/commit-analyzer.js` - File change analysis for commit types
|
||||
- `scripts/modules/pr-description-generator.js` - PR description template generator
|
||||
|
||||
**MCP Integration Files**:
|
||||
- `mcp-server/src/core/direct-functions/git-start.js`
|
||||
- `mcp-server/src/core/direct-functions/git-commit.js`
|
||||
- `mcp-server/src/core/direct-functions/git-pr.js`
|
||||
- `mcp-server/src/core/direct-functions/git-finish.js`
|
||||
- `mcp-server/src/core/direct-functions/git-status.js`
|
||||
- `mcp-server/src/tools/git-start.js`
|
||||
- `mcp-server/src/tools/git-commit.js`
|
||||
- `mcp-server/src/tools/git-pr.js`
|
||||
- `mcp-server/src/tools/git-finish.js`
|
||||
- `mcp-server/src/tools/git-status.js`
|
||||
|
||||
**Configuration**:
|
||||
- Add git workflow settings to `.taskmasterconfig`
|
||||
- Support for custom commit prefixes and PR templates
|
||||
- Branch naming pattern customization
|
||||
- Remote repository detection and validation
|
||||
|
||||
# Test Strategy:
|
||||
Implement comprehensive test suite following Task 4's TDD approach:
|
||||
|
||||
1. **Unit Tests** (target: 95%+ coverage):
|
||||
- Git operations wrapper with mocked git commands
|
||||
- Commit type detection with various file change scenarios
|
||||
- PR description generation with different task structures
|
||||
- Branch name validation and generation
|
||||
- State management and persistence
|
||||
|
||||
2. **Integration Tests**:
|
||||
- Full workflow simulation in test repository
|
||||
- Error handling for git conflicts and failures
|
||||
- Multi-task workflow scenarios
|
||||
- Coverage integration with real test runs
|
||||
- GitHub API interaction (mocked)
|
||||
|
||||
3. **E2E Tests**:
|
||||
- Complete task lifecycle from start to finish
|
||||
- Multiple developer workflow simulation
|
||||
- Merge conflict resolution scenarios
|
||||
- Branch protection and validation
|
||||
|
||||
4. **Test Implementation Details**:
|
||||
- Use Jest with git repository fixtures
|
||||
- Mock simple-git for isolated unit tests
|
||||
- Create test tasks.json scenarios
|
||||
- Validate all error messages and edge cases
|
||||
- Test rollback and recovery mechanisms
|
||||
|
||||
5. **Coverage Requirements**:
|
||||
- Minimum 90% overall coverage
|
||||
- 100% coverage for critical paths (branch creation, PR generation)
|
||||
- All error scenarios must be tested
|
||||
- Performance tests for large task hierarchies
|
||||
|
||||
# Subtasks:
|
||||
## 1. Design and implement core git operations wrapper [pending]
|
||||
### Dependencies: None
|
||||
### Description: Create a robust git operations layer that handles all git commands with proper error handling and state management
|
||||
### Details:
|
||||
Create `scripts/modules/git-operations.js` with methods for:
|
||||
- Branch creation/deletion (local and remote)
|
||||
- Commit operations with message formatting
|
||||
- Status checking and conflict detection
|
||||
- Remote operations (fetch, push, pull)
|
||||
- Repository validation and setup
|
||||
|
||||
Use simple-git library or child_process for git commands. Implement comprehensive error handling with specific error types for different git failures. Include retry logic for network operations.
|
||||
|
||||
## 2. Implement git start command [pending]
|
||||
### Dependencies: None
|
||||
### Description: Create the entry point for task-based git workflows with automated branch creation and task status updates
|
||||
### Details:
|
||||
Implement `scripts/modules/task-manager/git-start.js` with functionality to:
|
||||
- Validate task exists and is ready to start
|
||||
- Check for clean working directory
|
||||
- Create branch with `task-{id}` naming
|
||||
- Update task status to 'in-progress'
|
||||
- Store workflow state in `.taskmaster/git-state.json`
|
||||
- Handle existing branch scenarios
|
||||
- Support --force flag for branch recreation
|
||||
|
||||
Integrate with existing task-master commands and ensure MCP compatibility.
|
||||
|
||||
## 3. Build intelligent commit analyzer and generator [pending]
|
||||
### Dependencies: None
|
||||
### Description: Create a system that analyzes file changes to auto-detect commit types and generate standardized commit messages
|
||||
### Details:
|
||||
Develop `scripts/modules/commit-analyzer.js` with:
|
||||
- File change detection and categorization
|
||||
- Commit type inference rules:
|
||||
- feat: new files in scripts/, new functions
|
||||
- fix: changes to existing logic
|
||||
- test: changes in tests/ directory
|
||||
- docs: markdown and comment changes
|
||||
- refactor: file moves, renames, cleanup
|
||||
- Smart message generation with task context
|
||||
- Support for custom commit templates
|
||||
- Subtask reference inclusion
|
||||
|
||||
Create `scripts/modules/task-manager/git-commit.js` that uses the analyzer to generate commits with proper formatting.
|
||||
|
||||
## 4. Create PR description generator and command [pending]
|
||||
### Dependencies: None
|
||||
### Description: Build a comprehensive PR description generator that creates detailed, formatted descriptions from task data
|
||||
### Details:
|
||||
Implement `scripts/modules/pr-description-generator.js` to generate:
|
||||
- Task overview with full context
|
||||
- Subtask completion checklist
|
||||
- Implementation details summary
|
||||
- Test coverage metrics integration
|
||||
- Breaking changes section
|
||||
- Related tasks and dependencies
|
||||
|
||||
Create `scripts/modules/task-manager/git-pr.js` to:
|
||||
- Validate all subtasks are complete
|
||||
- Generate PR title and description
|
||||
- Use GitHub CLI for PR creation
|
||||
- Handle draft PR scenarios
|
||||
- Support custom PR templates
|
||||
- Include labels based on task metadata
|
||||
|
||||
## 5. Implement git finish command with cleanup [pending]
|
||||
### Dependencies: None
|
||||
### Description: Create the workflow completion command that handles post-merge cleanup and task status updates
|
||||
### Details:
|
||||
Build `scripts/modules/task-manager/git-finish.js` with:
|
||||
- PR merge verification via GitHub API
|
||||
- Local branch cleanup
|
||||
- Remote branch deletion (with confirmation)
|
||||
- Task status update to 'done'
|
||||
- Workflow state cleanup
|
||||
- Switch back to main branch
|
||||
- Pull latest changes
|
||||
|
||||
Handle scenarios where PR isn't merged yet or merge failed. Include --skip-cleanup flag for manual branch management.
|
||||
|
||||
## 6. Add git status command for workflow visibility [pending]
|
||||
### Dependencies: None
|
||||
### Description: Create a status command that shows current git workflow state with task context
|
||||
### Details:
|
||||
Implement `scripts/modules/task-manager/git-status.js` to display:
|
||||
- Current task and branch information
|
||||
- Subtask completion status
|
||||
- Uncommitted changes summary
|
||||
- PR status if exists
|
||||
- Coverage metrics comparison
|
||||
- Suggested next actions
|
||||
|
||||
Integrate with existing task status displays and provide actionable guidance based on workflow state.
|
||||
|
||||
## 7. Integrate with Commander.js and add command routing [pending]
|
||||
### Dependencies: None
|
||||
### Description: Add the git command suite to TaskMaster's CLI with proper help text and option handling
|
||||
### Details:
|
||||
Update `scripts/modules/commands.js` to:
|
||||
- Add 'git' command with subcommands
|
||||
- Implement option parsing for all git commands
|
||||
- Add comprehensive help text
|
||||
- Ensure proper error handling and display
|
||||
- Validate command prerequisites
|
||||
|
||||
Create proper command structure:
|
||||
- `task-master git start [taskId] [options]`
|
||||
- `task-master git commit [options]`
|
||||
- `task-master git pr [options]`
|
||||
- `task-master git finish [options]`
|
||||
- `task-master git status [options]`
|
||||
|
||||
## 8. Add MCP server integration for git commands [pending]
|
||||
### Dependencies: None
|
||||
### Description: Implement MCP tools and direct functions for git workflow commands to enable IDE integration
|
||||
### Details:
|
||||
Create MCP integration in:
|
||||
- `mcp-server/src/core/direct-functions/git-start.js`
|
||||
- `mcp-server/src/core/direct-functions/git-commit.js`
|
||||
- `mcp-server/src/core/direct-functions/git-pr.js`
|
||||
- `mcp-server/src/core/direct-functions/git-finish.js`
|
||||
- `mcp-server/src/core/direct-functions/git-status.js`
|
||||
- `mcp-server/src/tools/git-start.js`
|
||||
- `mcp-server/src/tools/git-commit.js`
|
||||
- `mcp-server/src/tools/git-pr.js`
|
||||
- `mcp-server/src/tools/git-finish.js`
|
||||
- `mcp-server/src/tools/git-status.js`
|
||||
|
||||
Implement tools for:
|
||||
- git_start_task
|
||||
- git_commit_task
|
||||
- git_create_pr
|
||||
- git_finish_task
|
||||
- git_workflow_status
|
||||
|
||||
Ensure proper error handling, logging, and response formatting. Include telemetry data for git operations.
|
||||
|
||||
## 9. Create comprehensive test suite [pending]
|
||||
### Dependencies: None
|
||||
### Description: Implement full test coverage following Task 4's high standards with unit, integration, and E2E tests
|
||||
### Details:
|
||||
Create test files:
|
||||
- `tests/unit/git/` - Unit tests for all git components
|
||||
- `tests/integration/git-workflow.test.js` - Full workflow tests
|
||||
- `tests/e2e/git-automation.test.js` - End-to-end scenarios
|
||||
|
||||
Implement:
|
||||
- Git repository fixtures and mocks
|
||||
- Coverage tracking and reporting
|
||||
- Performance benchmarks
|
||||
- Error scenario coverage
|
||||
- Multi-developer workflow simulations
|
||||
|
||||
Target 95%+ coverage with focus on critical paths.
|
||||
|
||||
## 10. Add configuration and documentation [pending]
|
||||
### Dependencies: None
|
||||
### Description: Create configuration options and comprehensive documentation for the git workflow feature
|
||||
### Details:
|
||||
Configuration tasks:
|
||||
- Add git workflow settings to `.taskmasterconfig`
|
||||
- Support environment variables for GitHub tokens
|
||||
- Create default PR and commit templates
|
||||
- Add branch naming customization
|
||||
|
||||
Documentation tasks:
|
||||
- Update README with git workflow section
|
||||
- Create `docs/git-workflow.md` guide
|
||||
- Add examples for common scenarios
|
||||
- Document configuration options
|
||||
- Create troubleshooting guide
|
||||
|
||||
Update rule files:
|
||||
- Create `.cursor/rules/git_workflow.mdc`
|
||||
- Update existing workflow rules
|
||||
|
||||
26
.taskmaster/tasks/task_098.txt
Normal file
26
.taskmaster/tasks/task_098.txt
Normal file
@@ -0,0 +1,26 @@
|
||||
# Task ID: 98
|
||||
# Title: Implement Standalone 'research' CLI Command for AI-Powered Queries
|
||||
# Status: pending
|
||||
# Dependencies: 2, 4, 16
|
||||
# Priority: medium
|
||||
# Description: Develop a new 'task-master research' (alias 'tm research') CLI command for fast, context-aware AI research queries using the ai-services-unified.js infrastructure.
|
||||
# Details:
|
||||
- Add a new CLI command 'research' to commands.js, following established CLI patterns and conventions.
|
||||
- Command should accept a research query as the main parameter, with optional flags for task IDs (--tasks), file paths (--files), custom context (--context), output detail level (--detail), and result saving (--save).
|
||||
- Integrate with ai-services-unified.js, invoking its research mode to process the query and context, leveraging project file tree and task context as needed.
|
||||
- Implement logic to gather and inject relevant context from specified tasks, files, or custom input, and generate a project file tree snapshot if required.
|
||||
- Ensure output is formatted for terminal readability, including citations and references where available.
|
||||
- Support saving research results to a specified file if --save is provided.
|
||||
- Provide both brief and comprehensive output modes, controlled by a flag.
|
||||
- Ensure the command is non-interactive (one-shot execution) and complements the existing 'explore' command.
|
||||
- Update help documentation and usage examples for the new command.
|
||||
|
||||
# Test Strategy:
|
||||
- Write unit and integration tests to verify correct parsing of command-line arguments and flags.
|
||||
- Test that the command invokes ai-services-unified.js in research mode with the correct parameters and context.
|
||||
- Validate that context from tasks, files, and custom input is correctly gathered and passed to the research engine.
|
||||
- Confirm that output is properly formatted, includes citations, and is displayed in the terminal as expected.
|
||||
- Test saving results to files and handling of file system errors.
|
||||
- Ensure the command works in both brief and comprehensive modes.
|
||||
- Verify that the command does not enter interactive mode and exits cleanly after execution.
|
||||
- Check help output and usage documentation for accuracy and completeness.
|
||||
File diff suppressed because one or more lines are too long
11438
context/chats/task-004.md
Normal file
11438
context/chats/task-004.md
Normal file
File diff suppressed because it is too large
Load Diff
1
package-lock.json
generated
1
package-lock.json
generated
@@ -40,6 +40,7 @@
|
||||
"ollama-ai-provider": "^1.2.0",
|
||||
"openai": "^4.89.0",
|
||||
"ora": "^8.2.0",
|
||||
"task-master-ai": "^0.15.0",
|
||||
"uuid": "^11.1.0",
|
||||
"zod": "^3.23.8"
|
||||
},
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
import path from 'path';
|
||||
import chalk from 'chalk';
|
||||
import boxen from 'boxen';
|
||||
import Table from 'cli-table3';
|
||||
import { z } from 'zod';
|
||||
import Fuse from 'fuse.js'; // Import Fuse.js for advanced fuzzy search
|
||||
import path from "path";
|
||||
import chalk from "chalk";
|
||||
import boxen from "boxen";
|
||||
import Table from "cli-table3";
|
||||
import { z } from "zod";
|
||||
import Fuse from "fuse.js"; // Import Fuse.js for advanced fuzzy search
|
||||
|
||||
import {
|
||||
displayBanner,
|
||||
@@ -12,31 +12,31 @@ import {
|
||||
stopLoadingIndicator,
|
||||
succeedLoadingIndicator,
|
||||
failLoadingIndicator,
|
||||
displayAiUsageSummary
|
||||
} from '../ui.js';
|
||||
import { readJSON, writeJSON, log as consoleLog, truncate } from '../utils.js';
|
||||
import { generateObjectService } from '../ai-services-unified.js';
|
||||
import { getDefaultPriority } from '../config-manager.js';
|
||||
import generateTaskFiles from './generate-task-files.js';
|
||||
displayAiUsageSummary,
|
||||
} from "../ui.js";
|
||||
import { readJSON, writeJSON, log as consoleLog, truncate } from "../utils.js";
|
||||
import { generateObjectService } from "../ai-services-unified.js";
|
||||
import { getDefaultPriority } from "../config-manager.js";
|
||||
import generateTaskFiles from "./generate-task-files.js";
|
||||
|
||||
// Define Zod schema for the expected AI output object
|
||||
const AiTaskDataSchema = z.object({
|
||||
title: z.string().describe('Clear, concise title for the task'),
|
||||
title: z.string().describe("Clear, concise title for the task"),
|
||||
description: z
|
||||
.string()
|
||||
.describe('A one or two sentence description of the task'),
|
||||
.describe("A one or two sentence description of the task"),
|
||||
details: z
|
||||
.string()
|
||||
.describe('In-depth implementation details, considerations, and guidance'),
|
||||
.describe("In-depth implementation details, considerations, and guidance"),
|
||||
testStrategy: z
|
||||
.string()
|
||||
.describe('Detailed approach for verifying task completion'),
|
||||
.describe("Detailed approach for verifying task completion"),
|
||||
dependencies: z
|
||||
.array(z.number())
|
||||
.optional()
|
||||
.describe(
|
||||
'Array of task IDs that this task depends on (must be completed before this task can start)'
|
||||
)
|
||||
"Array of task IDs that this task depends on (must be completed before this task can start)"
|
||||
),
|
||||
});
|
||||
|
||||
/**
|
||||
@@ -64,7 +64,7 @@ async function addTask(
|
||||
dependencies = [],
|
||||
priority = null,
|
||||
context = {},
|
||||
outputFormat = 'text', // Default to text for CLI
|
||||
outputFormat = "text", // Default to text for CLI
|
||||
manualTaskData = null,
|
||||
useResearch = false
|
||||
) {
|
||||
@@ -76,27 +76,27 @@ async function addTask(
|
||||
? mcpLog // Use MCP logger if provided
|
||||
: {
|
||||
// Create a wrapper around consoleLog for CLI
|
||||
info: (...args) => consoleLog('info', ...args),
|
||||
warn: (...args) => consoleLog('warn', ...args),
|
||||
error: (...args) => consoleLog('error', ...args),
|
||||
debug: (...args) => consoleLog('debug', ...args),
|
||||
success: (...args) => consoleLog('success', ...args)
|
||||
info: (...args) => consoleLog("info", ...args),
|
||||
warn: (...args) => consoleLog("warn", ...args),
|
||||
error: (...args) => consoleLog("error", ...args),
|
||||
debug: (...args) => consoleLog("debug", ...args),
|
||||
success: (...args) => consoleLog("success", ...args),
|
||||
};
|
||||
|
||||
const effectivePriority = priority || getDefaultPriority(projectRoot);
|
||||
|
||||
logFn.info(
|
||||
`Adding new task with prompt: "${prompt}", Priority: ${effectivePriority}, Dependencies: ${dependencies.join(', ') || 'None'}, Research: ${useResearch}, ProjectRoot: ${projectRoot}`
|
||||
`Adding new task with prompt: "${prompt}", Priority: ${effectivePriority}, Dependencies: ${dependencies.join(", ") || "None"}, Research: ${useResearch}, ProjectRoot: ${projectRoot}`
|
||||
);
|
||||
|
||||
let loadingIndicator = null;
|
||||
let aiServiceResponse = null; // To store the full response from AI service
|
||||
|
||||
// Create custom reporter that checks for MCP log
|
||||
const report = (message, level = 'info') => {
|
||||
const report = (message, level = "info") => {
|
||||
if (mcpLog) {
|
||||
mcpLog[level](message);
|
||||
} else if (outputFormat === 'text') {
|
||||
} else if (outputFormat === "text") {
|
||||
consoleLog(level, message);
|
||||
}
|
||||
};
|
||||
@@ -158,7 +158,7 @@ async function addTask(
|
||||
title: task.title,
|
||||
description: task.description,
|
||||
status: task.status,
|
||||
dependencies: dependencyData
|
||||
dependencies: dependencyData,
|
||||
};
|
||||
}
|
||||
|
||||
@@ -168,14 +168,14 @@ async function addTask(
|
||||
|
||||
// If tasks.json doesn't exist or is invalid, create a new one
|
||||
if (!data || !data.tasks) {
|
||||
report('tasks.json not found or invalid. Creating a new one.', 'info');
|
||||
report("tasks.json not found or invalid. Creating a new one.", "info");
|
||||
// Create default tasks data structure
|
||||
data = {
|
||||
tasks: []
|
||||
tasks: [],
|
||||
};
|
||||
// Ensure the directory exists and write the new file
|
||||
writeJSON(tasksPath, data);
|
||||
report('Created new tasks.json file with empty tasks array.', 'info');
|
||||
report("Created new tasks.json file with empty tasks array.", "info");
|
||||
}
|
||||
|
||||
// Find the highest task ID to determine the next ID
|
||||
@@ -184,13 +184,13 @@ async function addTask(
|
||||
const newTaskId = highestId + 1;
|
||||
|
||||
// Only show UI box for CLI mode
|
||||
if (outputFormat === 'text') {
|
||||
if (outputFormat === "text") {
|
||||
console.log(
|
||||
boxen(chalk.white.bold(`Creating New Task #${newTaskId}`), {
|
||||
padding: 1,
|
||||
borderColor: 'blue',
|
||||
borderStyle: 'round',
|
||||
margin: { top: 1, bottom: 1 }
|
||||
borderColor: "blue",
|
||||
borderStyle: "round",
|
||||
margin: { top: 1, bottom: 1 },
|
||||
})
|
||||
);
|
||||
}
|
||||
@@ -204,10 +204,10 @@ async function addTask(
|
||||
|
||||
if (invalidDeps.length > 0) {
|
||||
report(
|
||||
`The following dependencies do not exist or are invalid: ${invalidDeps.join(', ')}`,
|
||||
'warn'
|
||||
`The following dependencies do not exist or are invalid: ${invalidDeps.join(", ")}`,
|
||||
"warn"
|
||||
);
|
||||
report('Removing invalid dependencies...', 'info');
|
||||
report("Removing invalid dependencies...", "info");
|
||||
dependencies = dependencies.filter(
|
||||
(depId) => !invalidDeps.includes(depId)
|
||||
);
|
||||
@@ -242,28 +242,28 @@ async function addTask(
|
||||
|
||||
// Check if manual task data is provided
|
||||
if (manualTaskData) {
|
||||
report('Using manually provided task data', 'info');
|
||||
report("Using manually provided task data", "info");
|
||||
taskData = manualTaskData;
|
||||
report('DEBUG: Taking MANUAL task data path.', 'debug');
|
||||
report("DEBUG: Taking MANUAL task data path.", "debug");
|
||||
|
||||
// Basic validation for manual data
|
||||
if (
|
||||
!taskData.title ||
|
||||
typeof taskData.title !== 'string' ||
|
||||
typeof taskData.title !== "string" ||
|
||||
!taskData.description ||
|
||||
typeof taskData.description !== 'string'
|
||||
typeof taskData.description !== "string"
|
||||
) {
|
||||
throw new Error(
|
||||
'Manual task data must include at least a title and description.'
|
||||
"Manual task data must include at least a title and description."
|
||||
);
|
||||
}
|
||||
} else {
|
||||
report('DEBUG: Taking AI task generation path.', 'debug');
|
||||
report("DEBUG: Taking AI task generation path.", "debug");
|
||||
// --- Refactored AI Interaction ---
|
||||
report(`Generating task data with AI with prompt:\n${prompt}`, 'info');
|
||||
report(`Generating task data with AI with prompt:\n${prompt}`, "info");
|
||||
|
||||
// Create context string for task creation prompt
|
||||
let contextTasks = '';
|
||||
let contextTasks = "";
|
||||
|
||||
// Create a dependency map for better understanding of the task relationships
|
||||
const taskMap = {};
|
||||
@@ -274,18 +274,18 @@ async function addTask(
|
||||
title: t.title,
|
||||
description: t.description,
|
||||
dependencies: t.dependencies || [],
|
||||
status: t.status
|
||||
status: t.status,
|
||||
};
|
||||
});
|
||||
|
||||
// CLI-only feedback for the dependency analysis
|
||||
if (outputFormat === 'text') {
|
||||
if (outputFormat === "text") {
|
||||
console.log(
|
||||
boxen(chalk.cyan.bold('Task Context Analysis'), {
|
||||
boxen(chalk.cyan.bold("Task Context Analysis"), {
|
||||
padding: { top: 0, bottom: 0, left: 1, right: 1 },
|
||||
margin: { top: 0, bottom: 0 },
|
||||
borderColor: 'cyan',
|
||||
borderStyle: 'round'
|
||||
borderColor: "cyan",
|
||||
borderStyle: "round",
|
||||
})
|
||||
);
|
||||
}
|
||||
@@ -316,7 +316,7 @@ async function addTask(
|
||||
const directDeps = data.tasks.filter((t) =>
|
||||
numericDependencies.includes(t.id)
|
||||
);
|
||||
contextTasks += `\n${directDeps.map((t) => `- Task ${t.id}: ${t.title} - ${t.description}`).join('\n')}`;
|
||||
contextTasks += `\n${directDeps.map((t) => `- Task ${t.id}: ${t.title} - ${t.description}`).join("\n")}`;
|
||||
|
||||
// Add an overview of indirect dependencies if present
|
||||
const indirectDeps = dependentTasks.filter(
|
||||
@@ -327,7 +327,7 @@ async function addTask(
|
||||
contextTasks += `\n${indirectDeps
|
||||
.slice(0, 5)
|
||||
.map((t) => `- Task ${t.id}: ${t.title} - ${t.description}`)
|
||||
.join('\n')}`;
|
||||
.join("\n")}`;
|
||||
if (indirectDeps.length > 5) {
|
||||
contextTasks += `\n- ... and ${indirectDeps.length - 5} more indirect dependencies`;
|
||||
}
|
||||
@@ -338,15 +338,15 @@ async function addTask(
|
||||
for (const depTask of uniqueDetailedTasks) {
|
||||
const depthInfo = depthMap.get(depTask.id)
|
||||
? ` (depth: ${depthMap.get(depTask.id)})`
|
||||
: '';
|
||||
: "";
|
||||
const isDirect = numericDependencies.includes(depTask.id)
|
||||
? ' [DIRECT DEPENDENCY]'
|
||||
: '';
|
||||
? " [DIRECT DEPENDENCY]"
|
||||
: "";
|
||||
|
||||
contextTasks += `\n\n------ Task ${depTask.id}${isDirect}${depthInfo}: ${depTask.title} ------\n`;
|
||||
contextTasks += `Description: ${depTask.description}\n`;
|
||||
contextTasks += `Status: ${depTask.status || 'pending'}\n`;
|
||||
contextTasks += `Priority: ${depTask.priority || 'medium'}\n`;
|
||||
contextTasks += `Status: ${depTask.status || "pending"}\n`;
|
||||
contextTasks += `Priority: ${depTask.priority || "medium"}\n`;
|
||||
|
||||
// List its dependencies
|
||||
if (depTask.dependencies && depTask.dependencies.length > 0) {
|
||||
@@ -356,7 +356,7 @@ async function addTask(
|
||||
? `Task ${dId}: ${depDepTask.title}`
|
||||
: `Task ${dId}`;
|
||||
});
|
||||
contextTasks += `Dependencies: ${depDeps.join(', ')}\n`;
|
||||
contextTasks += `Dependencies: ${depDeps.join(", ")}\n`;
|
||||
} else {
|
||||
contextTasks += `Dependencies: None\n`;
|
||||
}
|
||||
@@ -365,7 +365,7 @@ async function addTask(
|
||||
if (depTask.details) {
|
||||
const truncatedDetails =
|
||||
depTask.details.length > 400
|
||||
? depTask.details.substring(0, 400) + '... (truncated)'
|
||||
? depTask.details.substring(0, 400) + "... (truncated)"
|
||||
: depTask.details;
|
||||
contextTasks += `Implementation Details: ${truncatedDetails}\n`;
|
||||
}
|
||||
@@ -373,19 +373,19 @@ async function addTask(
|
||||
|
||||
// Add dependency chain visualization
|
||||
if (dependencyGraphs.length > 0) {
|
||||
contextTasks += '\n\nDependency Chain Visualization:';
|
||||
contextTasks += "\n\nDependency Chain Visualization:";
|
||||
|
||||
// Helper function to format dependency chain as text
|
||||
function formatDependencyChain(
|
||||
node,
|
||||
prefix = '',
|
||||
prefix = "",
|
||||
isLast = true,
|
||||
depth = 0
|
||||
) {
|
||||
if (depth > 3) return ''; // Limit depth to avoid excessive nesting
|
||||
if (depth > 3) return ""; // Limit depth to avoid excessive nesting
|
||||
|
||||
const connector = isLast ? '└── ' : '├── ';
|
||||
const childPrefix = isLast ? ' ' : '│ ';
|
||||
const connector = isLast ? "└── " : "├── ";
|
||||
const childPrefix = isLast ? " " : "│ ";
|
||||
|
||||
let result = `\n${prefix}${connector}Task ${node.id}: ${node.title}`;
|
||||
|
||||
@@ -411,7 +411,7 @@ async function addTask(
|
||||
}
|
||||
|
||||
// Show dependency analysis in CLI mode
|
||||
if (outputFormat === 'text') {
|
||||
if (outputFormat === "text") {
|
||||
if (directDeps.length > 0) {
|
||||
console.log(chalk.gray(` Explicitly specified dependencies:`));
|
||||
directDeps.forEach((t) => {
|
||||
@@ -451,14 +451,14 @@ async function addTask(
|
||||
// Convert dependency graph to ASCII art for terminal
|
||||
function visualizeDependencyGraph(
|
||||
node,
|
||||
prefix = '',
|
||||
prefix = "",
|
||||
isLast = true,
|
||||
depth = 0
|
||||
) {
|
||||
if (depth > 2) return; // Limit depth for display
|
||||
|
||||
const connector = isLast ? '└── ' : '├── ';
|
||||
const childPrefix = isLast ? ' ' : '│ ';
|
||||
const connector = isLast ? "└── " : "├── ";
|
||||
const childPrefix = isLast ? " " : "│ ";
|
||||
|
||||
console.log(
|
||||
chalk.blue(
|
||||
@@ -494,18 +494,18 @@ async function addTask(
|
||||
includeScore: true, // Return match scores
|
||||
threshold: 0.4, // Lower threshold = stricter matching (range 0-1)
|
||||
keys: [
|
||||
{ name: 'title', weight: 1.5 }, // Title is most important
|
||||
{ name: 'description', weight: 2 }, // Description is very important
|
||||
{ name: 'details', weight: 3 }, // Details is most important
|
||||
{ name: "title", weight: 1.5 }, // Title is most important
|
||||
{ name: "description", weight: 2 }, // Description is very important
|
||||
{ name: "details", weight: 3 }, // Details is most important
|
||||
// Search dependencies to find tasks that depend on similar things
|
||||
{ name: 'dependencyTitles', weight: 0.5 }
|
||||
{ name: "dependencyTitles", weight: 0.5 },
|
||||
],
|
||||
// Sort matches by score (lower is better)
|
||||
shouldSort: true,
|
||||
// Allow searching in nested properties
|
||||
useExtendedSearch: true,
|
||||
// Return up to 50 matches
|
||||
limit: 50
|
||||
limit: 50,
|
||||
};
|
||||
|
||||
// Prepare task data with dependencies expanded as titles for better semantic search
|
||||
@@ -516,15 +516,15 @@ async function addTask(
|
||||
? task.dependencies
|
||||
.map((depId) => {
|
||||
const depTask = data.tasks.find((t) => t.id === depId);
|
||||
return depTask ? depTask.title : '';
|
||||
return depTask ? depTask.title : "";
|
||||
})
|
||||
.filter((title) => title)
|
||||
.join(' ')
|
||||
: '';
|
||||
.join(" ")
|
||||
: "";
|
||||
|
||||
return {
|
||||
...task,
|
||||
dependencyTitles
|
||||
dependencyTitles,
|
||||
};
|
||||
});
|
||||
|
||||
@@ -534,7 +534,7 @@ async function addTask(
|
||||
// Extract significant words and phrases from the prompt
|
||||
const promptWords = prompt
|
||||
.toLowerCase()
|
||||
.replace(/[^\w\s-]/g, ' ') // Replace non-alphanumeric chars with spaces
|
||||
.replace(/[^\w\s-]/g, " ") // Replace non-alphanumeric chars with spaces
|
||||
.split(/\s+/)
|
||||
.filter((word) => word.length > 3); // Words at least 4 chars
|
||||
|
||||
@@ -602,21 +602,21 @@ async function addTask(
|
||||
if (relatedTasks.length > 0) {
|
||||
contextTasks = `\nRelevant tasks identified by semantic similarity:\n${relatedTasks
|
||||
.map((t, i) => {
|
||||
const relevanceMarker = i < highRelevance.length ? '⭐ ' : '';
|
||||
const relevanceMarker = i < highRelevance.length ? "⭐ " : "";
|
||||
return `- ${relevanceMarker}Task ${t.id}: ${t.title} - ${t.description}`;
|
||||
})
|
||||
.join('\n')}`;
|
||||
.join("\n")}`;
|
||||
}
|
||||
|
||||
if (
|
||||
recentTasks.length > 0 &&
|
||||
!contextTasks.includes('Recently created tasks')
|
||||
!contextTasks.includes("Recently created tasks")
|
||||
) {
|
||||
contextTasks += `\n\nRecently created tasks:\n${recentTasks
|
||||
.filter((t) => !relatedTasks.some((rt) => rt.id === t.id))
|
||||
.slice(0, 3)
|
||||
.map((t) => `- Task ${t.id}: ${t.title} - ${t.description}`)
|
||||
.join('\n')}`;
|
||||
.join("\n")}`;
|
||||
}
|
||||
|
||||
// Add detailed information about the most relevant tasks
|
||||
@@ -630,8 +630,8 @@ async function addTask(
|
||||
for (const task of uniqueDetailedTasks) {
|
||||
contextTasks += `\n\n------ Task ${task.id}: ${task.title} ------\n`;
|
||||
contextTasks += `Description: ${task.description}\n`;
|
||||
contextTasks += `Status: ${task.status || 'pending'}\n`;
|
||||
contextTasks += `Priority: ${task.priority || 'medium'}\n`;
|
||||
contextTasks += `Status: ${task.status || "pending"}\n`;
|
||||
contextTasks += `Priority: ${task.priority || "medium"}\n`;
|
||||
if (task.dependencies && task.dependencies.length > 0) {
|
||||
// Format dependency list with titles
|
||||
const depList = task.dependencies.map((depId) => {
|
||||
@@ -640,13 +640,13 @@ async function addTask(
|
||||
? `Task ${depId} (${depTask.title})`
|
||||
: `Task ${depId}`;
|
||||
});
|
||||
contextTasks += `Dependencies: ${depList.join(', ')}\n`;
|
||||
contextTasks += `Dependencies: ${depList.join(", ")}\n`;
|
||||
}
|
||||
// Add implementation details but truncate if too long
|
||||
if (task.details) {
|
||||
const truncatedDetails =
|
||||
task.details.length > 400
|
||||
? task.details.substring(0, 400) + '... (truncated)'
|
||||
? task.details.substring(0, 400) + "... (truncated)"
|
||||
: task.details;
|
||||
contextTasks += `Implementation Details: ${truncatedDetails}\n`;
|
||||
}
|
||||
@@ -654,7 +654,7 @@ async function addTask(
|
||||
}
|
||||
|
||||
// Add a concise view of the task dependency structure
|
||||
contextTasks += '\n\nSummary of task dependencies in the project:';
|
||||
contextTasks += "\n\nSummary of task dependencies in the project:";
|
||||
|
||||
// Get pending/in-progress tasks that might be most relevant based on fuzzy search
|
||||
// Prioritize tasks from our similarity search
|
||||
@@ -662,7 +662,7 @@ async function addTask(
|
||||
const relevantPendingTasks = data.tasks
|
||||
.filter(
|
||||
(t) =>
|
||||
(t.status === 'pending' || t.status === 'in-progress') &&
|
||||
(t.status === "pending" || t.status === "in-progress") &&
|
||||
// Either in our relevant set OR has relevant words in title/description
|
||||
(relevantTaskIds.has(t.id) ||
|
||||
promptWords.some(
|
||||
@@ -676,8 +676,8 @@ async function addTask(
|
||||
for (const task of relevantPendingTasks) {
|
||||
const depsStr =
|
||||
task.dependencies && task.dependencies.length > 0
|
||||
? task.dependencies.join(', ')
|
||||
: 'None';
|
||||
? task.dependencies.join(", ")
|
||||
: "None";
|
||||
contextTasks += `\n- Task ${task.id}: depends on [${depsStr}]`;
|
||||
}
|
||||
|
||||
@@ -709,7 +709,7 @@ async function addTask(
|
||||
.slice(0, 10);
|
||||
|
||||
if (commonDeps.length > 0) {
|
||||
contextTasks += '\nMost common dependencies for similar tasks:';
|
||||
contextTasks += "\nMost common dependencies for similar tasks:";
|
||||
commonDeps.forEach(([depId, count]) => {
|
||||
const depTask = data.tasks.find((t) => t.id === parseInt(depId));
|
||||
if (depTask) {
|
||||
@@ -720,7 +720,7 @@ async function addTask(
|
||||
}
|
||||
|
||||
// Show fuzzy search analysis in CLI mode
|
||||
if (outputFormat === 'text') {
|
||||
if (outputFormat === "text") {
|
||||
console.log(
|
||||
chalk.gray(
|
||||
` Context search across ${data.tasks.length} tasks using full prompt and ${promptWords.length} keywords`
|
||||
@@ -777,7 +777,7 @@ async function addTask(
|
||||
const isHighRelevance = highRelevance.some(
|
||||
(ht) => ht.id === t.id
|
||||
);
|
||||
const relevanceIndicator = isHighRelevance ? '⭐ ' : '';
|
||||
const relevanceIndicator = isHighRelevance ? "⭐ " : "";
|
||||
console.log(
|
||||
chalk.cyan(
|
||||
` • ${relevanceIndicator}Task ${t.id}: ${truncate(t.title, 40)}`
|
||||
@@ -805,14 +805,14 @@ async function addTask(
|
||||
}
|
||||
|
||||
// Add a visual transition to show we're moving to AI generation - only for CLI
|
||||
if (outputFormat === 'text') {
|
||||
if (outputFormat === "text") {
|
||||
console.log(
|
||||
boxen(
|
||||
chalk.white.bold('AI Task Generation') +
|
||||
`\n\n${chalk.gray('Analyzing context and generating task details using AI...')}` +
|
||||
`\n${chalk.cyan('Context size: ')}${chalk.yellow(contextTasks.length.toLocaleString())} characters` +
|
||||
`\n${chalk.cyan('Dependency detection: ')}${chalk.yellow(numericDependencies.length > 0 ? 'Explicit dependencies' : 'Auto-discovery mode')}` +
|
||||
`\n${chalk.cyan('Detailed tasks: ')}${chalk.yellow(
|
||||
chalk.white.bold("AI Task Generation") +
|
||||
`\n\n${chalk.gray("Analyzing context and generating task details using AI...")}` +
|
||||
`\n${chalk.cyan("Context size: ")}${chalk.yellow(contextTasks.length.toLocaleString())} characters` +
|
||||
`\n${chalk.cyan("Dependency detection: ")}${chalk.yellow(numericDependencies.length > 0 ? "Explicit dependencies" : "Auto-discovery mode")}` +
|
||||
`\n${chalk.cyan("Detailed tasks: ")}${chalk.yellow(
|
||||
numericDependencies.length > 0
|
||||
? dependentTasks.length // Use length of tasks from explicit dependency path
|
||||
: uniqueDetailedTasks.length // Use length of tasks from fuzzy search path
|
||||
@@ -820,8 +820,8 @@ async function addTask(
|
||||
{
|
||||
padding: { top: 0, bottom: 1, left: 1, right: 1 },
|
||||
margin: { top: 1, bottom: 0 },
|
||||
borderColor: 'white',
|
||||
borderStyle: 'round'
|
||||
borderColor: "white",
|
||||
borderStyle: "round",
|
||||
}
|
||||
)
|
||||
);
|
||||
@@ -831,15 +831,15 @@ async function addTask(
|
||||
// System Prompt - Enhanced for dependency awareness
|
||||
const systemPrompt =
|
||||
"You are a helpful assistant that creates well-structured tasks for a software development project. Generate a single new task based on the user's description, adhering strictly to the provided JSON schema. Pay special attention to dependencies between tasks, ensuring the new task correctly references any tasks it depends on.\n\n" +
|
||||
'When determining dependencies for a new task, follow these principles:\n' +
|
||||
'1. Select dependencies based on logical requirements - what must be completed before this task can begin.\n' +
|
||||
'2. Prioritize task dependencies that are semantically related to the functionality being built.\n' +
|
||||
'3. Consider both direct dependencies (immediately prerequisite) and indirect dependencies.\n' +
|
||||
'4. Avoid adding unnecessary dependencies - only include tasks that are genuinely prerequisite.\n' +
|
||||
'5. Consider the current status of tasks - prefer completed tasks as dependencies when possible.\n' +
|
||||
"When determining dependencies for a new task, follow these principles:\n" +
|
||||
"1. Select dependencies based on logical requirements - what must be completed before this task can begin.\n" +
|
||||
"2. Prioritize task dependencies that are semantically related to the functionality being built.\n" +
|
||||
"3. Consider both direct dependencies (immediately prerequisite) and indirect dependencies.\n" +
|
||||
"4. Avoid adding unnecessary dependencies - only include tasks that are genuinely prerequisite.\n" +
|
||||
"5. Consider the current status of tasks - prefer completed tasks as dependencies when possible.\n" +
|
||||
"6. Pay special attention to foundation tasks (1-5) but don't automatically include them without reason.\n" +
|
||||
'7. Recent tasks (higher ID numbers) may be more relevant for newer functionality.\n\n' +
|
||||
'The dependencies array should contain task IDs (numbers) of prerequisite tasks.\n';
|
||||
"7. Recent tasks (higher ID numbers) may be more relevant for newer functionality.\n\n" +
|
||||
"The dependencies array should contain task IDs (numbers) of prerequisite tasks.\n";
|
||||
|
||||
// Task Structure Description (for user prompt)
|
||||
const taskStructureDesc = `
|
||||
@@ -853,7 +853,7 @@ async function addTask(
|
||||
`;
|
||||
|
||||
// Add any manually provided details to the prompt for context
|
||||
let contextFromArgs = '';
|
||||
let contextFromArgs = "";
|
||||
if (manualTaskData?.title)
|
||||
contextFromArgs += `\n- Suggested Title: "${manualTaskData.title}"`;
|
||||
if (manualTaskData?.description)
|
||||
@@ -867,7 +867,7 @@ async function addTask(
|
||||
const userPrompt = `You are generating the details for Task #${newTaskId}. Based on the user's request: "${prompt}", create a comprehensive new task for a software development project.
|
||||
|
||||
${contextTasks}
|
||||
${contextFromArgs ? `\nConsider these additional details provided by the user:${contextFromArgs}` : ''}
|
||||
${contextFromArgs ? `\nConsider these additional details provided by the user:${contextFromArgs}` : ""}
|
||||
|
||||
Based on the information about existing tasks provided above, include appropriate dependencies in the "dependencies" array. Only include task IDs that this new task directly depends on.
|
||||
|
||||
@@ -878,15 +878,15 @@ async function addTask(
|
||||
`;
|
||||
|
||||
// Start the loading indicator - only for text mode
|
||||
if (outputFormat === 'text') {
|
||||
if (outputFormat === "text") {
|
||||
loadingIndicator = startLoadingIndicator(
|
||||
`Generating new task with ${useResearch ? 'Research' : 'Main'} AI... \n`
|
||||
`Generating new task with ${useResearch ? "Research" : "Main"} AI... \n`
|
||||
);
|
||||
}
|
||||
|
||||
try {
|
||||
const serviceRole = useResearch ? 'research' : 'main';
|
||||
report('DEBUG: Calling generateObjectService...', 'debug');
|
||||
const serviceRole = useResearch ? "research" : "main";
|
||||
report("DEBUG: Calling generateObjectService...", "debug");
|
||||
|
||||
aiServiceResponse = await generateObjectService({
|
||||
// Capture the full response
|
||||
@@ -894,17 +894,17 @@ async function addTask(
|
||||
session: session,
|
||||
projectRoot: projectRoot,
|
||||
schema: AiTaskDataSchema,
|
||||
objectName: 'newTaskData',
|
||||
objectName: "newTaskData",
|
||||
systemPrompt: systemPrompt,
|
||||
prompt: userPrompt,
|
||||
commandName: commandName || 'add-task', // Use passed commandName or default
|
||||
outputType: outputType || (isMCP ? 'mcp' : 'cli') // Use passed outputType or derive
|
||||
commandName: commandName || "add-task", // Use passed commandName or default
|
||||
outputType: outputType || (isMCP ? "mcp" : "cli"), // Use passed outputType or derive
|
||||
});
|
||||
report('DEBUG: generateObjectService returned successfully.', 'debug');
|
||||
report("DEBUG: generateObjectService returned successfully.", "debug");
|
||||
|
||||
if (!aiServiceResponse || !aiServiceResponse.mainResult) {
|
||||
throw new Error(
|
||||
'AI service did not return the expected object structure.'
|
||||
"AI service did not return the expected object structure."
|
||||
);
|
||||
}
|
||||
|
||||
@@ -921,33 +921,33 @@ async function addTask(
|
||||
) {
|
||||
taskData = aiServiceResponse.mainResult.object;
|
||||
} else {
|
||||
throw new Error('AI service did not return a valid task object.');
|
||||
throw new Error("AI service did not return a valid task object.");
|
||||
}
|
||||
|
||||
report('Successfully generated task data from AI.', 'success');
|
||||
report("Successfully generated task data from AI.", "success");
|
||||
|
||||
// Success! Show checkmark
|
||||
if (loadingIndicator) {
|
||||
succeedLoadingIndicator(
|
||||
loadingIndicator,
|
||||
'Task generated successfully'
|
||||
"Task generated successfully"
|
||||
);
|
||||
loadingIndicator = null; // Clear it
|
||||
}
|
||||
} catch (error) {
|
||||
// Failure! Show X
|
||||
if (loadingIndicator) {
|
||||
failLoadingIndicator(loadingIndicator, 'AI generation failed');
|
||||
failLoadingIndicator(loadingIndicator, "AI generation failed");
|
||||
loadingIndicator = null;
|
||||
}
|
||||
report(
|
||||
`DEBUG: generateObjectService caught error: ${error.message}`,
|
||||
'debug'
|
||||
"debug"
|
||||
);
|
||||
report(`Error generating task with AI: ${error.message}`, 'error');
|
||||
report(`Error generating task with AI: ${error.message}`, "error");
|
||||
throw error; // Re-throw error after logging
|
||||
} finally {
|
||||
report('DEBUG: generateObjectService finally block reached.', 'debug');
|
||||
report("DEBUG: generateObjectService finally block reached.", "debug");
|
||||
// Clean up if somehow still running
|
||||
if (loadingIndicator) {
|
||||
stopLoadingIndicator(loadingIndicator);
|
||||
@@ -961,14 +961,14 @@ async function addTask(
|
||||
id: newTaskId,
|
||||
title: taskData.title,
|
||||
description: taskData.description,
|
||||
details: taskData.details || '',
|
||||
testStrategy: taskData.testStrategy || '',
|
||||
status: 'pending',
|
||||
details: taskData.details || "",
|
||||
testStrategy: taskData.testStrategy || "",
|
||||
status: "pending",
|
||||
dependencies: taskData.dependencies?.length
|
||||
? taskData.dependencies
|
||||
: numericDependencies, // Use AI-suggested dependencies if available, fallback to manually specified
|
||||
priority: effectivePriority,
|
||||
subtasks: [] // Initialize with empty subtasks array
|
||||
subtasks: [], // Initialize with empty subtasks array
|
||||
};
|
||||
|
||||
// Additional check: validate all dependencies in the AI response
|
||||
@@ -980,8 +980,8 @@ async function addTask(
|
||||
|
||||
if (!allValidDeps) {
|
||||
report(
|
||||
'AI suggested invalid dependencies. Filtering them out...',
|
||||
'warn'
|
||||
"AI suggested invalid dependencies. Filtering them out...",
|
||||
"warn"
|
||||
);
|
||||
newTask.dependencies = taskData.dependencies.filter((depId) => {
|
||||
const numDepId = parseInt(depId, 10);
|
||||
@@ -993,48 +993,48 @@ async function addTask(
|
||||
// Add the task to the tasks array
|
||||
data.tasks.push(newTask);
|
||||
|
||||
report('DEBUG: Writing tasks.json...', 'debug');
|
||||
report("DEBUG: Writing tasks.json...", "debug");
|
||||
// Write the updated tasks to the file
|
||||
writeJSON(tasksPath, data);
|
||||
report('DEBUG: tasks.json written.', 'debug');
|
||||
report("DEBUG: tasks.json written.", "debug");
|
||||
|
||||
// Generate markdown task files
|
||||
report('Generating task files...', 'info');
|
||||
report('DEBUG: Calling generateTaskFiles...', 'debug');
|
||||
report("Generating task files...", "info");
|
||||
report("DEBUG: Calling generateTaskFiles...", "debug");
|
||||
// Pass mcpLog if available to generateTaskFiles
|
||||
await generateTaskFiles(tasksPath, path.dirname(tasksPath), { mcpLog });
|
||||
report('DEBUG: generateTaskFiles finished.', 'debug');
|
||||
report("DEBUG: generateTaskFiles finished.", "debug");
|
||||
|
||||
// Show success message - only for text output (CLI)
|
||||
if (outputFormat === 'text') {
|
||||
if (outputFormat === "text") {
|
||||
const table = new Table({
|
||||
head: [
|
||||
chalk.cyan.bold('ID'),
|
||||
chalk.cyan.bold('Title'),
|
||||
chalk.cyan.bold('Description')
|
||||
chalk.cyan.bold("ID"),
|
||||
chalk.cyan.bold("Title"),
|
||||
chalk.cyan.bold("Description"),
|
||||
],
|
||||
colWidths: [5, 30, 50] // Adjust widths as needed
|
||||
colWidths: [5, 30, 50], // Adjust widths as needed
|
||||
});
|
||||
|
||||
table.push([
|
||||
newTask.id,
|
||||
truncate(newTask.title, 27),
|
||||
truncate(newTask.description, 47)
|
||||
truncate(newTask.description, 47),
|
||||
]);
|
||||
|
||||
console.log(chalk.green('✓ New task created successfully:'));
|
||||
console.log(chalk.green("✓ New task created successfully:"));
|
||||
console.log(table.toString());
|
||||
|
||||
// Helper to get priority color
|
||||
const getPriorityColor = (p) => {
|
||||
switch (p?.toLowerCase()) {
|
||||
case 'high':
|
||||
return 'red';
|
||||
case 'low':
|
||||
return 'gray';
|
||||
case 'medium':
|
||||
case "high":
|
||||
return "red";
|
||||
case "low":
|
||||
return "gray";
|
||||
case "medium":
|
||||
default:
|
||||
return 'yellow';
|
||||
return "yellow";
|
||||
}
|
||||
};
|
||||
|
||||
@@ -1058,49 +1058,49 @@ async function addTask(
|
||||
});
|
||||
|
||||
// Prepare dependency display string
|
||||
let dependencyDisplay = '';
|
||||
let dependencyDisplay = "";
|
||||
if (newTask.dependencies.length > 0) {
|
||||
dependencyDisplay = chalk.white('Dependencies:') + '\n';
|
||||
dependencyDisplay = chalk.white("Dependencies:") + "\n";
|
||||
newTask.dependencies.forEach((dep) => {
|
||||
const isAiAdded = aiAddedDeps.includes(dep);
|
||||
const depType = isAiAdded ? chalk.yellow(' (AI suggested)') : '';
|
||||
const depType = isAiAdded ? chalk.yellow(" (AI suggested)") : "";
|
||||
dependencyDisplay +=
|
||||
chalk.white(
|
||||
` - ${dep}: ${depTitles[dep] || 'Unknown task'}${depType}`
|
||||
) + '\n';
|
||||
` - ${dep}: ${depTitles[dep] || "Unknown task"}${depType}`
|
||||
) + "\n";
|
||||
});
|
||||
} else {
|
||||
dependencyDisplay = chalk.white('Dependencies: None') + '\n';
|
||||
dependencyDisplay = chalk.white("Dependencies: None") + "\n";
|
||||
}
|
||||
|
||||
// Add info about removed dependencies if any
|
||||
if (aiRemovedDeps.length > 0) {
|
||||
dependencyDisplay +=
|
||||
chalk.gray('\nUser-specified dependencies that were not used:') +
|
||||
'\n';
|
||||
chalk.gray("\nUser-specified dependencies that were not used:") +
|
||||
"\n";
|
||||
aiRemovedDeps.forEach((dep) => {
|
||||
const depTask = data.tasks.find((t) => t.id === dep);
|
||||
const title = depTask ? truncate(depTask.title, 30) : 'Unknown task';
|
||||
dependencyDisplay += chalk.gray(` - ${dep}: ${title}`) + '\n';
|
||||
const title = depTask ? truncate(depTask.title, 30) : "Unknown task";
|
||||
dependencyDisplay += chalk.gray(` - ${dep}: ${title}`) + "\n";
|
||||
});
|
||||
}
|
||||
|
||||
// Add dependency analysis summary
|
||||
let dependencyAnalysis = '';
|
||||
let dependencyAnalysis = "";
|
||||
if (aiAddedDeps.length > 0 || aiRemovedDeps.length > 0) {
|
||||
dependencyAnalysis =
|
||||
'\n' + chalk.white.bold('Dependency Analysis:') + '\n';
|
||||
"\n" + chalk.white.bold("Dependency Analysis:") + "\n";
|
||||
if (aiAddedDeps.length > 0) {
|
||||
dependencyAnalysis +=
|
||||
chalk.green(
|
||||
`AI identified ${aiAddedDeps.length} additional dependencies`
|
||||
) + '\n';
|
||||
) + "\n";
|
||||
}
|
||||
if (aiRemovedDeps.length > 0) {
|
||||
dependencyAnalysis +=
|
||||
chalk.yellow(
|
||||
`AI excluded ${aiRemovedDeps.length} user-provided dependencies`
|
||||
) + '\n';
|
||||
) + "\n";
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1108,32 +1108,32 @@ async function addTask(
|
||||
console.log(
|
||||
boxen(
|
||||
chalk.white.bold(`Task ${newTaskId} Created Successfully`) +
|
||||
'\n\n' +
|
||||
"\n\n" +
|
||||
chalk.white(`Title: ${newTask.title}`) +
|
||||
'\n' +
|
||||
"\n" +
|
||||
chalk.white(`Status: ${getStatusWithColor(newTask.status)}`) +
|
||||
'\n' +
|
||||
"\n" +
|
||||
chalk.white(
|
||||
`Priority: ${chalk[getPriorityColor(newTask.priority)](newTask.priority)}`
|
||||
) +
|
||||
'\n\n' +
|
||||
"\n\n" +
|
||||
dependencyDisplay +
|
||||
dependencyAnalysis +
|
||||
'\n' +
|
||||
chalk.white.bold('Next Steps:') +
|
||||
'\n' +
|
||||
"\n" +
|
||||
chalk.white.bold("Next Steps:") +
|
||||
"\n" +
|
||||
chalk.cyan(
|
||||
`1. Run ${chalk.yellow(`task-master show ${newTaskId}`)} to see complete task details`
|
||||
) +
|
||||
'\n' +
|
||||
"\n" +
|
||||
chalk.cyan(
|
||||
`2. Run ${chalk.yellow(`task-master set-status --id=${newTaskId} --status=in-progress`)} to start working on it`
|
||||
) +
|
||||
'\n' +
|
||||
"\n" +
|
||||
chalk.cyan(
|
||||
`3. Run ${chalk.yellow(`task-master expand --id=${newTaskId}`)} to break it down into subtasks`
|
||||
),
|
||||
{ padding: 1, borderColor: 'green', borderStyle: 'round' }
|
||||
{ padding: 1, borderColor: "green", borderStyle: "round" }
|
||||
)
|
||||
);
|
||||
|
||||
@@ -1141,19 +1141,19 @@ async function addTask(
|
||||
if (
|
||||
aiServiceResponse &&
|
||||
aiServiceResponse.telemetryData &&
|
||||
(outputType === 'cli' || outputType === 'text')
|
||||
(outputType === "cli" || outputType === "text")
|
||||
) {
|
||||
displayAiUsageSummary(aiServiceResponse.telemetryData, 'cli');
|
||||
displayAiUsageSummary(aiServiceResponse.telemetryData, "cli");
|
||||
}
|
||||
}
|
||||
|
||||
report(
|
||||
`DEBUG: Returning new task ID: ${newTaskId} and telemetry.`,
|
||||
'debug'
|
||||
"debug"
|
||||
);
|
||||
return {
|
||||
newTaskId: newTaskId,
|
||||
telemetryData: aiServiceResponse ? aiServiceResponse.telemetryData : null
|
||||
telemetryData: aiServiceResponse ? aiServiceResponse.telemetryData : null,
|
||||
};
|
||||
} catch (error) {
|
||||
// Stop any loading indicator on error
|
||||
@@ -1161,8 +1161,8 @@ async function addTask(
|
||||
stopLoadingIndicator(loadingIndicator);
|
||||
}
|
||||
|
||||
report(`Error adding task: ${error.message}`, 'error');
|
||||
if (outputFormat === 'text') {
|
||||
report(`Error adding task: ${error.message}`, "error");
|
||||
if (outputFormat === "text") {
|
||||
console.error(chalk.red(`Error: ${error.message}`));
|
||||
}
|
||||
// In MCP mode, we let the direct function handler catch and format
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
{
|
||||
"meta": {
|
||||
"generatedAt": "2025-05-27T16:34:53.088Z",
|
||||
"generatedAt": "2025-05-24T17:50:20.773Z",
|
||||
"tasksAnalyzed": 1,
|
||||
"totalTasks": 84,
|
||||
"analysisCount": 45,
|
||||
"totalTasks": 88,
|
||||
"analysisCount": 44,
|
||||
"thresholdScore": 5,
|
||||
"projectName": "Taskmaster",
|
||||
"usedResearch": true
|
||||
@@ -313,6 +313,14 @@
|
||||
"expansionPrompt": "Break down the update of ai-services-unified.js for dynamic token limits into subtasks such as: (1) Import and integrate the token counting utility, (2) Refactor _unifiedServiceRunner to calculate and enforce dynamic token limits, (3) Update error handling for token limit violations, (4) Add and verify logging for token usage, (5) Write and execute tests for various prompt and model scenarios.",
|
||||
"reasoning": "This task involves significant code changes to a core function, integration of a new utility, dynamic logic for multiple models, and robust error handling. It also requires comprehensive testing for edge cases and integration, making it moderately complex and best managed by splitting into focused subtasks."
|
||||
},
|
||||
{
|
||||
"taskId": 86,
|
||||
"taskTitle": "Update .taskmasterconfig schema and user guide",
|
||||
"complexityScore": 6,
|
||||
"recommendedSubtasks": 4,
|
||||
"expansionPrompt": "Expand this task into subtasks: (1) Draft a migration guide for users, (2) Update user documentation to explain new config fields, (3) Modify schema validation logic in config-manager.js, (4) Test and validate backward compatibility and error messaging.",
|
||||
"reasoning": "The task spans documentation, schema changes, migration guidance, and validation logic. While not algorithmically complex, it requires careful coordination and thorough testing to ensure a smooth user transition and robust validation."
|
||||
},
|
||||
{
|
||||
"taskId": 87,
|
||||
"taskTitle": "Implement validation and error handling",
|
||||
@@ -352,22 +360,6 @@
|
||||
"recommendedSubtasks": 7,
|
||||
"expansionPrompt": "Break down the implementation of the global --joke flag into the following subtasks: (1) Update CLI foundation to support global flags, (2) Develop the joke-service module with joke management and category support, (3) Integrate joke output into existing output utilities, (4) Update all CLI commands for joke flag compatibility, (5) Add configuration options for joke categories and custom jokes, (6) Implement comprehensive testing (flag recognition, output, content, integration, performance, regression), (7) Update documentation and usage examples.",
|
||||
"reasoning": "This task requires changes across the CLI foundation, output utilities, all command modules, and configuration management. It introduces a new service module, global flag handling, and output logic that must not interfere with existing features (including JSON output). The need for robust testing and backward compatibility further increases complexity. The scope spans multiple code areas and requires careful integration, justifying a high complexity score and a detailed subtask breakdown to manage risk and ensure maintainability.[2][3][5]"
|
||||
},
|
||||
{
|
||||
"taskId": 94,
|
||||
"taskTitle": "Implement Standalone 'research' CLI Command for AI-Powered Queries",
|
||||
"complexityScore": 7,
|
||||
"recommendedSubtasks": 6,
|
||||
"expansionPrompt": "Break down the implementation of the 'research' CLI command into logical subtasks covering command registration, parameter handling, context gathering, AI service integration, output formatting, and documentation.",
|
||||
"reasoning": "This task has moderate to high complexity (7/10) due to multiple interconnected components: CLI argument parsing, integration with AI services, context gathering from various sources, and output formatting with different modes. The cyclomatic complexity would be significant with multiple decision paths for handling different flags and options. The task requires understanding existing patterns and extending the codebase in a consistent manner, suggesting the need for careful decomposition into manageable subtasks."
|
||||
},
|
||||
{
|
||||
"taskId": 86,
|
||||
"taskTitle": "Implement GitHub Issue Export Feature",
|
||||
"complexityScore": 9,
|
||||
"recommendedSubtasks": 10,
|
||||
"expansionPrompt": "Break down the implementation of the GitHub Issue Export Feature into detailed subtasks covering: command structure and CLI integration, GitHub API client development, authentication and error handling, task-to-issue mapping logic, content formatting and markdown conversion, bidirectional linking and metadata management, extensible architecture and adapter interfaces, configuration and settings management, documentation, and comprehensive testing (unit, integration, edge cases, performance).",
|
||||
"reasoning": "This task involves designing and implementing a robust, extensible export system with deep integration into GitHub, including bidirectional workflows, complex data mapping, error handling, and support for future platforms. The requirements span CLI design, API integration, content transformation, metadata management, extensibility, configuration, and extensive testing. The breadth and depth of these requirements, along with the need for maintainability and future extensibility, place this task at a high complexity level. Breaking it into at least 10 subtasks will ensure each major component and concern is addressed systematically, reducing risk and improving quality."
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user