Compare commits

..

2 Commits

Author SHA1 Message Date
Ralph Khreish
33386cdce8 chore: apply requested changes 2025-10-03 16:14:08 +02:00
Ralph Khreish
f3deacb74e fix: pricing show 0 when it is defined 2025-10-02 16:47:45 +02:00
22 changed files with 38 additions and 516 deletions

View File

@@ -1,5 +0,0 @@
---
"task-master-ai": patch
---
Do a quick fix on build

View File

@@ -1,22 +0,0 @@
{
"mode": "pre",
"tag": "rc",
"initialVersions": {
"task-master-ai": "0.27.3",
"docs": "0.0.4",
"extension": "0.25.4"
},
"changesets": [
"chore-fix-docs",
"cursor-slash-commands",
"curvy-weeks-flow",
"flat-cities-say",
"forty-tables-invite",
"gentle-cats-dance",
"mcp-timeout-configuration",
"petite-ideas-grab",
"silly-pandas-find",
"sweet-maps-rule",
"whole-pigs-say"
]
}

View File

@@ -1,8 +0,0 @@
---
"task-master-ai": patch
---
Fix complexity score not showing for `task-master show` and `task-master list`
- Added complexity score on "next task" when running `task-master list`
- Added colors to complexity to reflect complexity (easy, medium, hard)

View File

@@ -1,71 +1,5 @@
# task-master-ai
## 0.28.0-rc.0
### Minor Changes
- [#1215](https://github.com/eyaltoledano/claude-task-master/pull/1215) [`0079b7d`](https://github.com/eyaltoledano/claude-task-master/commit/0079b7defdad550811f704c470fdd01955d91d4d) Thanks [@joedanz](https://github.com/joedanz)! - Add Cursor IDE custom slash command support
Expose Task Master commands as Cursor slash commands by copying assets/claude/commands to .cursor/commands on profile add and cleaning up on remove.
- [#1246](https://github.com/eyaltoledano/claude-task-master/pull/1246) [`18aa416`](https://github.com/eyaltoledano/claude-task-master/commit/18aa416035f44345bde1c7321490345733a5d042) Thanks [@Crunchyman-ralph](https://github.com/Crunchyman-ralph)! - Added api keys page on docs website: docs.task-master.dev/getting-started/api-keys
- [#1246](https://github.com/eyaltoledano/claude-task-master/pull/1246) [`18aa416`](https://github.com/eyaltoledano/claude-task-master/commit/18aa416035f44345bde1c7321490345733a5d042) Thanks [@Crunchyman-ralph](https://github.com/Crunchyman-ralph)! - Move to AI SDK v5:
- Works better with claude-code and gemini-cli as ai providers
- Improved openai model family compatibility
- Migrate ollama provider to v2
- Closes #1223, #1013, #1161, #1174
- [#1262](https://github.com/eyaltoledano/claude-task-master/pull/1262) [`738ec51`](https://github.com/eyaltoledano/claude-task-master/commit/738ec51c049a295a12839b2dfddaf05e23b8fede) Thanks [@Crunchyman-ralph](https://github.com/Crunchyman-ralph)! - Migrate AI services to use generateObject for structured data generation
This update migrates all AI service calls from generateText to generateObject, ensuring more reliable and structured responses across all commands.
### Key Changes:
- **Unified AI Service**: Replaced separate generateText implementations with a single generateObjectService that handles structured data generation
- **JSON Mode Support**: Added proper JSON mode configuration for providers that support it (OpenAI, Anthropic, Google, Groq)
- **Schema Validation**: Integrated Zod schemas for all AI-generated content with automatic validation
- **Provider Compatibility**: Maintained compatibility with all existing providers while leveraging their native structured output capabilities
- **Improved Reliability**: Structured output generation reduces parsing errors and ensures consistent data formats
### Technical Improvements:
- Centralized provider configuration in `ai-providers-unified.js`
- Added `generateObject` support detection for each provider
- Implemented proper error handling for schema validation failures
- Maintained backward compatibility with existing prompt structures
### Bug Fixes:
- Fixed subtask ID numbering issue where AI was generating inconsistent IDs (101-105, 601-603) instead of sequential numbering (1, 2, 3...)
- Enhanced prompt instructions to enforce proper ID generation patterns
- Ensured subtasks display correctly as X.1, X.2, X.3 format
This migration improves the reliability and consistency of AI-generated content throughout the Task Master application.
- [#1112](https://github.com/eyaltoledano/claude-task-master/pull/1112) [`d67b81d`](https://github.com/eyaltoledano/claude-task-master/commit/d67b81d25ddd927fabb6f5deb368e8993519c541) Thanks [@olssonsten](https://github.com/olssonsten)! - Enhanced Roo Code profile with MCP timeout configuration for improved reliability during long-running AI operations. The Roo profile now automatically configures a 300-second timeout for MCP server operations, preventing timeouts during complex tasks like `parse-prd`, `expand-all`, `analyze-complexity`, and `research` operations. This change also replaces static MCP configuration files with programmatic generation for better maintainability.
**What's New:**
- 300-second timeout for MCP operations (up from default 60 seconds)
- Programmatic MCP configuration generation (replaces static asset files)
- Enhanced reliability for AI-powered operations
- Consistent with other AI coding assistant profiles
**Migration:** No user action required - existing Roo Code installations will automatically receive the enhanced MCP configuration on next initialization.
- [#1246](https://github.com/eyaltoledano/claude-task-master/pull/1246) [`986ac11`](https://github.com/eyaltoledano/claude-task-master/commit/986ac117aee00bcd3e6830a0f76e1ad6d10e0bca) Thanks [@Crunchyman-ralph](https://github.com/Crunchyman-ralph)! - Upgrade grok-cli ai provider to ai sdk v5
### Patch Changes
- [#1235](https://github.com/eyaltoledano/claude-task-master/pull/1235) [`aaacc3d`](https://github.com/eyaltoledano/claude-task-master/commit/aaacc3dae36247b4de72b2d2697f49e5df6d01e3) Thanks [@Crunchyman-ralph](https://github.com/Crunchyman-ralph)! - Improve `analyze-complexity` cli docs and `--research` flag documentation
- [#1251](https://github.com/eyaltoledano/claude-task-master/pull/1251) [`0b2c696`](https://github.com/eyaltoledano/claude-task-master/commit/0b2c6967c4605c33a100cff16f6ce8ff09ad06f0) Thanks [@Crunchyman-ralph](https://github.com/Crunchyman-ralph)! - Change parent task back to "pending" when all subtasks are in "pending" state
- [#1172](https://github.com/eyaltoledano/claude-task-master/pull/1172) [`b5fe723`](https://github.com/eyaltoledano/claude-task-master/commit/b5fe723f8ead928e9f2dbde13b833ee70ac3382d) Thanks [@jujax](https://github.com/jujax)! - Fix Claude Code settings validation for pathToClaudeCodeExecutable
- [#1192](https://github.com/eyaltoledano/claude-task-master/pull/1192) [`2b69936`](https://github.com/eyaltoledano/claude-task-master/commit/2b69936ee7b34346d6de5175af20e077359e2e2a) Thanks [@nukunga](https://github.com/nukunga)! - Fix sonar deep research model failing, should be called `sonar-deep-research`
- [#1270](https://github.com/eyaltoledano/claude-task-master/pull/1270) [`20004a3`](https://github.com/eyaltoledano/claude-task-master/commit/20004a39ea848f747e1ff48981bfe176554e4055) Thanks [@Crunchyman-ralph](https://github.com/Crunchyman-ralph)! - Fix complexity score not showing for `task-master show` and `task-master list`
- Added complexity score on "next task" when running `task-master list`
- Added colors to complexity to reflect complexity (easy, medium, hard)
## 0.27.3
### Patch Changes

View File

@@ -281,14 +281,9 @@ export class ListTasksCommand extends Command {
const priorityBreakdown = getPriorityBreakdown(tasks);
// Find next task following the same logic as findNextTask
const nextTaskInfo = this.findNextTask(tasks);
const nextTask = this.findNextTask(tasks);
// Get the full task object with complexity data already included
const nextTask = nextTaskInfo
? tasks.find((t) => String(t.id) === String(nextTaskInfo.id))
: undefined;
// Display dashboard boxes (nextTask already has complexity from storage enrichment)
// Display dashboard boxes
displayDashboards(
taskStats,
subtaskStats,
@@ -308,16 +303,14 @@ export class ListTasksCommand extends Command {
// Display recommended next task section immediately after table
if (nextTask) {
const description = getTaskDescription(nextTask);
// Find the full task object to get description
const fullTask = tasks.find((t) => String(t.id) === String(nextTask.id));
const description = fullTask ? getTaskDescription(fullTask) : undefined;
displayRecommendedNextTask({
id: nextTask.id,
title: nextTask.title,
priority: nextTask.priority,
status: nextTask.status,
dependencies: nextTask.dependencies,
description,
complexity: nextTask.complexity as number | undefined
...nextTask,
status: 'pending', // Next task is typically pending
description
});
} else {
displayRecommendedNextTask(undefined);

View File

@@ -6,7 +6,6 @@
import chalk from 'chalk';
import boxen from 'boxen';
import type { Task, TaskPriority } from '@tm/core/types';
import { getComplexityWithColor } from '../../utils/ui.js';
/**
* Statistics for task collection
@@ -480,7 +479,7 @@ export function displayDependencyDashboard(
? chalk.cyan(nextTask.dependencies.join(', '))
: chalk.gray('None')
}\n` +
`Complexity: ${nextTask?.complexity !== undefined ? getComplexityWithColor(nextTask.complexity) : chalk.gray('N/A')}`;
`Complexity: ${nextTask?.complexity || chalk.gray('N/A')}`;
return content;
}

View File

@@ -6,7 +6,6 @@
import chalk from 'chalk';
import boxen from 'boxen';
import type { Task } from '@tm/core/types';
import { getComplexityWithColor } from '../../utils/ui.js';
/**
* Next task display options
@@ -18,7 +17,6 @@ export interface NextTaskDisplayOptions {
status?: string;
dependencies?: (string | number)[];
description?: string;
complexity?: number;
}
/**
@@ -84,11 +82,6 @@ export function displayRecommendedNextTask(
: chalk.cyan(task.dependencies.join(', '));
content.push(`Dependencies: ${depsDisplay}`);
// Complexity with color and label
if (typeof task.complexity === 'number') {
content.push(`Complexity: ${getComplexityWithColor(task.complexity)}`);
}
// Description if available
if (task.description) {
content.push('');

View File

@@ -9,11 +9,7 @@ import Table from 'cli-table3';
import { marked, MarkedExtension } from 'marked';
import { markedTerminal } from 'marked-terminal';
import type { Task } from '@tm/core/types';
import {
getStatusWithColor,
getPriorityWithColor,
getComplexityWithColor
} from '../../utils/ui.js';
import { getStatusWithColor, getPriorityWithColor } from '../../utils/ui.js';
// Configure marked to use terminal renderer with subtle colors
marked.use(
@@ -112,9 +108,7 @@ export function displayTaskProperties(task: Task): void {
getStatusWithColor(task.status),
getPriorityWithColor(task.priority),
deps,
typeof task.complexity === 'number'
? getComplexityWithColor(task.complexity)
: chalk.gray('N/A'),
'N/A',
task.description || ''
].join('\n');

View File

@@ -84,23 +84,7 @@ export function getPriorityWithColor(priority: TaskPriority): string {
}
/**
* Get complexity color and label based on score thresholds
*/
function getComplexityLevel(score: number): {
color: (text: string) => string;
label: string;
} {
if (score >= 7) {
return { color: chalk.hex('#CC0000'), label: 'High' };
} else if (score >= 4) {
return { color: chalk.hex('#FF8800'), label: 'Medium' };
} else {
return { color: chalk.green, label: 'Low' };
}
}
/**
* Get colored complexity display with dot indicator (simple format)
* Get colored complexity display
*/
export function getComplexityWithColor(complexity: number | string): string {
const score =
@@ -110,20 +94,13 @@ export function getComplexityWithColor(complexity: number | string): string {
return chalk.gray('N/A');
}
const { color } = getComplexityLevel(score);
return color(`${score}`);
}
/**
* Get colored complexity display with /10 format (for dashboards)
*/
export function getComplexityWithScore(complexity: number | undefined): string {
if (typeof complexity !== 'number') {
return chalk.gray('N/A');
if (score >= 8) {
return chalk.red.bold(`${score} (High)`);
} else if (score >= 5) {
return chalk.yellow(`${score} (Medium)`);
} else {
return chalk.green(`${score} (Low)`);
}
const { color, label } = getComplexityLevel(complexity);
return color(`${complexity}/10 (${label})`);
}
/**
@@ -346,12 +323,8 @@ export function createTaskTable(
}
if (showComplexity) {
// Show complexity score from report if available
if (typeof task.complexity === 'number') {
row.push(getComplexityWithColor(task.complexity));
} else {
row.push(chalk.gray('N/A'));
}
// Show N/A if no complexity score
row.push(chalk.gray('N/A'));
}
table.push(row);

View File

@@ -1,12 +1,5 @@
# Change Log
## 0.25.5-rc.0
### Patch Changes
- Updated dependencies [[`aaacc3d`](https://github.com/eyaltoledano/claude-task-master/commit/aaacc3dae36247b4de72b2d2697f49e5df6d01e3), [`0079b7d`](https://github.com/eyaltoledano/claude-task-master/commit/0079b7defdad550811f704c470fdd01955d91d4d), [`0b2c696`](https://github.com/eyaltoledano/claude-task-master/commit/0b2c6967c4605c33a100cff16f6ce8ff09ad06f0), [`18aa416`](https://github.com/eyaltoledano/claude-task-master/commit/18aa416035f44345bde1c7321490345733a5d042), [`18aa416`](https://github.com/eyaltoledano/claude-task-master/commit/18aa416035f44345bde1c7321490345733a5d042), [`738ec51`](https://github.com/eyaltoledano/claude-task-master/commit/738ec51c049a295a12839b2dfddaf05e23b8fede), [`d67b81d`](https://github.com/eyaltoledano/claude-task-master/commit/d67b81d25ddd927fabb6f5deb368e8993519c541), [`b5fe723`](https://github.com/eyaltoledano/claude-task-master/commit/b5fe723f8ead928e9f2dbde13b833ee70ac3382d), [`2b69936`](https://github.com/eyaltoledano/claude-task-master/commit/2b69936ee7b34346d6de5175af20e077359e2e2a), [`986ac11`](https://github.com/eyaltoledano/claude-task-master/commit/986ac117aee00bcd3e6830a0f76e1ad6d10e0bca), [`20004a3`](https://github.com/eyaltoledano/claude-task-master/commit/20004a39ea848f747e1ff48981bfe176554e4055)]:
- task-master-ai@0.28.0-rc.0
## 0.25.4
### Patch Changes

View File

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

View File

@@ -1,6 +1,6 @@
{
"name": "task-master-ai",
"version": "0.28.0-rc.0",
"version": "0.27.3",
"description": "A task management system for ambitious AI-driven development that doesn't overwhelm and confuse Cursor.",
"main": "index.js",
"type": "module",

View File

@@ -33,9 +33,6 @@ export class TaskEntity implements Task {
tags?: string[];
assignee?: string;
complexity?: Task['complexity'];
recommendedSubtasks?: number;
expansionPrompt?: string;
complexityReasoning?: string;
constructor(data: Task | (Omit<Task, 'id'> & { id: number | string })) {
this.validate(data);
@@ -65,9 +62,6 @@ export class TaskEntity implements Task {
this.tags = data.tags;
this.assignee = data.assignee;
this.complexity = data.complexity;
this.recommendedSubtasks = data.recommendedSubtasks;
this.expansionPrompt = data.expansionPrompt;
this.complexityReasoning = data.complexityReasoning;
}
/**
@@ -252,10 +246,7 @@ export class TaskEntity implements Task {
actualEffort: this.actualEffort,
tags: this.tags,
assignee: this.assignee,
complexity: this.complexity,
recommendedSubtasks: this.recommendedSubtasks,
expansionPrompt: this.expansionPrompt,
complexityReasoning: this.complexityReasoning
complexity: this.complexity
};
}

View File

@@ -61,12 +61,3 @@ export { getLogger, createLogger, setGlobalLogger } from './logger/index.js';
// Re-export executors
export * from './executors/index.js';
// Re-export reports
export {
ComplexityReportManager,
type ComplexityReport,
type ComplexityReportMetadata,
type ComplexityAnalysis,
type TaskComplexityData
} from './reports/index.js';

View File

@@ -1,185 +0,0 @@
/**
* @fileoverview ComplexityReportManager - Handles loading and managing complexity analysis reports
* Follows the same pattern as ConfigManager and AuthManager
*/
import { promises as fs } from 'fs';
import path from 'path';
import type {
ComplexityReport,
ComplexityAnalysis,
TaskComplexityData
} from './types.js';
import { getLogger } from '../logger/index.js';
const logger = getLogger('ComplexityReportManager');
/**
* Manages complexity analysis reports
* Handles loading, caching, and providing complexity data for tasks
*/
export class ComplexityReportManager {
private projectRoot: string;
private reportCache: Map<string, ComplexityReport> = new Map();
constructor(projectRoot: string) {
this.projectRoot = projectRoot;
}
/**
* Get the path to the complexity report file for a given tag
*/
private getReportPath(tag?: string): string {
const reportsDir = path.join(this.projectRoot, '.taskmaster', 'reports');
const tagSuffix = tag && tag !== 'master' ? `_${tag}` : '';
return path.join(reportsDir, `task-complexity-report${tagSuffix}.json`);
}
/**
* Load complexity report for a given tag
* Results are cached to avoid repeated file reads
*/
async loadReport(tag?: string): Promise<ComplexityReport | null> {
const resolvedTag = tag || 'master';
const cacheKey = resolvedTag;
// Check cache first
if (this.reportCache.has(cacheKey)) {
return this.reportCache.get(cacheKey)!;
}
const reportPath = this.getReportPath(tag);
try {
// Check if file exists
await fs.access(reportPath);
// Read and parse the report
const content = await fs.readFile(reportPath, 'utf-8');
const report = JSON.parse(content) as ComplexityReport;
// Validate basic structure
if (!report.meta || !Array.isArray(report.complexityAnalysis)) {
logger.warn(
`Invalid complexity report structure at ${reportPath}, ignoring`
);
return null;
}
// Cache the report
this.reportCache.set(cacheKey, report);
logger.debug(
`Loaded complexity report for tag '${resolvedTag}' with ${report.complexityAnalysis.length} analyses`
);
return report;
} catch (error: any) {
if (error.code === 'ENOENT') {
// File doesn't exist - this is normal, not all projects have complexity reports
logger.debug(`No complexity report found for tag '${resolvedTag}'`);
return null;
}
// Other errors (parsing, permissions, etc.)
logger.warn(
`Failed to load complexity report for tag '${resolvedTag}': ${error.message}`
);
return null;
}
}
/**
* Get complexity data for a specific task ID
*/
async getComplexityForTask(
taskId: string | number,
tag?: string
): Promise<TaskComplexityData | null> {
const report = await this.loadReport(tag);
if (!report) {
return null;
}
// Find the analysis for this task
const analysis = report.complexityAnalysis.find(
(a) => String(a.taskId) === String(taskId)
);
if (!analysis) {
return null;
}
// Convert to TaskComplexityData format
return {
complexityScore: analysis.complexityScore,
recommendedSubtasks: analysis.recommendedSubtasks,
expansionPrompt: analysis.expansionPrompt,
complexityReasoning: analysis.complexityReasoning
};
}
/**
* Get complexity data for multiple tasks at once
* More efficient than calling getComplexityForTask multiple times
*/
async getComplexityForTasks(
taskIds: (string | number)[],
tag?: string
): Promise<Map<string, TaskComplexityData>> {
const result = new Map<string, TaskComplexityData>();
const report = await this.loadReport(tag);
if (!report) {
return result;
}
// Create a map for fast lookups
const analysisMap = new Map<string, ComplexityAnalysis>();
report.complexityAnalysis.forEach((analysis) => {
analysisMap.set(String(analysis.taskId), analysis);
});
// Map each task ID to its complexity data
taskIds.forEach((taskId) => {
const analysis = analysisMap.get(String(taskId));
if (analysis) {
result.set(String(taskId), {
complexityScore: analysis.complexityScore,
recommendedSubtasks: analysis.recommendedSubtasks,
expansionPrompt: analysis.expansionPrompt,
complexityReasoning: analysis.complexityReasoning
});
}
});
return result;
}
/**
* Clear the report cache
* @param tag - Specific tag to clear, or undefined to clear all cached reports
* Useful when reports are regenerated or modified externally
*/
clearCache(tag?: string): void {
if (tag) {
this.reportCache.delete(tag);
} else {
// Clear all cached reports
this.reportCache.clear();
}
}
/**
* Check if a complexity report exists for a tag
*/
async hasReport(tag?: string): Promise<boolean> {
const reportPath = this.getReportPath(tag);
try {
await fs.access(reportPath);
return true;
} catch {
return false;
}
}
}

View File

@@ -1,11 +0,0 @@
/**
* @fileoverview Reports module exports
*/
export { ComplexityReportManager } from './complexity-report-manager.js';
export type {
ComplexityReport,
ComplexityReportMetadata,
ComplexityAnalysis,
TaskComplexityData
} from './types.js';

View File

@@ -1,65 +0,0 @@
/**
* @fileoverview Type definitions for complexity analysis reports
*/
/**
* Analysis result for a single task
*/
export interface ComplexityAnalysis {
/** Task ID being analyzed */
taskId: string | number;
/** Task title */
taskTitle: string;
/** Complexity score (1-10 scale) */
complexityScore: number;
/** Recommended number of subtasks */
recommendedSubtasks: number;
/** AI-generated prompt for task expansion */
expansionPrompt: string;
/** Reasoning behind the complexity assessment */
complexityReasoning: string;
}
/**
* Metadata about the complexity report
*/
export interface ComplexityReportMetadata {
/** When the report was generated */
generatedAt: string;
/** Number of tasks analyzed in this run */
tasksAnalyzed: number;
/** Total number of tasks in the file */
totalTasks?: number;
/** Total analyses in the report (across all runs) */
analysisCount?: number;
/** Complexity threshold score used */
thresholdScore: number;
/** Project name */
projectName?: string;
/** Whether research mode was used */
usedResearch: boolean;
}
/**
* Complete complexity analysis report
*/
export interface ComplexityReport {
/** Report metadata */
meta: ComplexityReportMetadata;
/** Array of complexity analyses */
complexityAnalysis: ComplexityAnalysis[];
}
/**
* Complexity data to be attached to a Task
*/
export interface TaskComplexityData {
/** Complexity score (1-10 scale) */
complexityScore?: number;
/** Recommended number of subtasks */
recommendedSubtasks?: number;
/** AI-generated expansion prompt */
expansionPrompt?: string;
/** Reasoning behind the assessment */
complexityReasoning?: string;
}

View File

@@ -397,6 +397,16 @@ export class TaskService {
}
}
// Complexity filter
if (filter.complexity) {
const complexities = Array.isArray(filter.complexity)
? filter.complexity
: [filter.complexity];
if (!task.complexity || !complexities.includes(task.complexity)) {
return false;
}
}
// Search filter
if (filter.search) {
const searchLower = filter.search.toLowerCase();

View File

@@ -11,7 +11,6 @@ import type {
import { FormatHandler } from './format-handler.js';
import { FileOperations } from './file-operations.js';
import { PathResolver } from './path-resolver.js';
import { ComplexityReportManager } from '../../reports/complexity-report-manager.js';
/**
* File-based storage implementation using a single tasks.json file with separated concerns
@@ -20,13 +19,11 @@ export class FileStorage implements IStorage {
private formatHandler: FormatHandler;
private fileOps: FileOperations;
private pathResolver: PathResolver;
private complexityManager: ComplexityReportManager;
constructor(projectPath: string) {
this.formatHandler = new FormatHandler();
this.fileOps = new FileOperations();
this.pathResolver = new PathResolver(projectPath);
this.complexityManager = new ComplexityReportManager(projectPath);
}
/**
@@ -90,7 +87,6 @@ export class FileStorage implements IStorage {
/**
* Load tasks from the single tasks.json file for a specific tag
* Enriches tasks with complexity data from the complexity report
*/
async loadTasks(tag?: string): Promise<Task[]> {
const filePath = this.pathResolver.getTasksPath();
@@ -98,10 +94,7 @@ export class FileStorage implements IStorage {
try {
const rawData = await this.fileOps.readJson(filePath);
const tasks = this.formatHandler.extractTasks(rawData, resolvedTag);
// Enrich tasks with complexity data
return await this.enrichTasksWithComplexity(tasks, resolvedTag);
return this.formatHandler.extractTasks(rawData, resolvedTag);
} catch (error: any) {
if (error.code === 'ENOENT') {
return []; // File doesn't exist, return empty array
@@ -603,46 +596,6 @@ export class FileStorage implements IStorage {
await this.saveTasks(tasks, targetTag);
}
/**
* Enrich tasks with complexity data from the complexity report
* Private helper method called by loadTasks()
*/
private async enrichTasksWithComplexity(
tasks: Task[],
tag: string
): Promise<Task[]> {
// Get all task IDs for bulk lookup
const taskIds = tasks.map((t) => t.id);
// Load complexity data for all tasks at once (more efficient)
const complexityMap = await this.complexityManager.getComplexityForTasks(
taskIds,
tag
);
// If no complexity data found, return tasks as-is
if (complexityMap.size === 0) {
return tasks;
}
// Enrich each task with its complexity data
return tasks.map((task) => {
const complexityData = complexityMap.get(String(task.id));
if (!complexityData) {
return task;
}
// Merge complexity data into the task
return {
...task,
complexity: complexityData.complexityScore,
recommendedSubtasks: complexityData.recommendedSubtasks,
expansionPrompt: complexityData.expansionPrompt,
complexityReasoning: complexityData.complexityReasoning
};
});
}
}
// Export as default for convenience

View File

@@ -72,13 +72,7 @@ export interface Task {
actualEffort?: number;
tags?: string[];
assignee?: string;
// Complexity analysis (from complexity report)
// Can be either enum ('simple' | 'moderate' | 'complex' | 'very-complex') or numeric score (1-10)
complexity?: TaskComplexity | number;
recommendedSubtasks?: number;
expansionPrompt?: string;
complexityReasoning?: string;
complexity?: TaskComplexity;
}
/**
@@ -151,6 +145,7 @@ export interface TaskFilter {
hasSubtasks?: boolean;
search?: string;
assignee?: string;
complexity?: TaskComplexity | TaskComplexity[];
}
/**

View File

@@ -19,10 +19,10 @@ const getBuildTimeEnvs = () => {
for (const [key, value] of Object.entries(process.env)) {
if (key.startsWith('TM_PUBLIC_')) {
// Return the actual value, not JSON.stringify'd
envs[key] = value || '';
}
}
return envs;
};

View File

@@ -5,8 +5,7 @@
"build": {
"dependsOn": ["^build"],
"outputs": ["dist/**"],
"outputLogs": "new-only",
"env": ["NODE_ENV", "TM_PUBLIC_*"]
"outputLogs": "new-only"
},
"dev": {
"cache": false,