update-task-migration-plan.md
Migrate and unify update-tasks.js and update-subtask-by-id.js into a single update-task command that handles both task and subtask updates. This migration will move from the legacy scripts/modules/task-manager/ structure to the new apps/cli and packages/tm-core architecture.
update-tasks.js - Bulk Task UpdatesPurpose: Update multiple tasks from a specified ID onwards
Input Format: --from=<id> --prompt="context"
AI Service: generateObjectService with structured schema
update-subtask-by-id.js - Single Subtask UpdatesPurpose: Append timestamped information to a specific subtask
Input Format: --id=<parentId.subtaskId> --prompt="notes"
AI Service: generateTextService for freeform content
update-task# Update single task (replaces update-task)
task-master update-task --id=3 --prompt="changes"
# Update single subtask (replaces update-subtask)
task-master update-task --id=3.2 --prompt="implementation notes"
# Update multiple tasks from ID onwards (replaces update --from)
task-master update-task --from=3 --prompt="changes"
The command should automatically determine behavior based on:
. → subtask modetasksPath existsid parameter (task: integer, subtask: "parent.child" format)fromId parameter (integer, positive)prompt parameter (non-empty string)findProjectRoot())mcpLog presence)outputFormat ('text' or 'json', auto-detect for MCP)tasks.json using readJSON(tasksPath, projectRoot, tag)id >= fromId AND status !== 'done'ContextGatherer with projectRoot and tagflattenTasksWithSubtasks()FuzzyTaskSearch with appropriate command type:
'update' for bulk/single task mode'update-subtask' for subtask mode${parentTask.title} ${subtask.title} ${prompt}PromptManager via getPromptManager()tasks (array of tasks to update)updatePromptuseResearchprojectContext (gathered context)hasCodebaseAnalysis (from config)projectRootparentTask (id, title)prevSubtask (id, title, status) - if existsnextSubtask (id, title, status) - if existscurrentDetails (existing subtask details or fallback)updatePromptuseResearchgatheredContexthasCodebaseAnalysisprojectRootsystemPrompt and userPrompt from prompt manageruseResearch ? 'research' : 'main'generateObjectService with:
role, session, projectRootsystemPrompt, prompt (userPrompt)schema: COMMAND_SCHEMAS['update-tasks']objectName: 'tasks'commandName: 'update-tasks'outputType: isMCP ? 'mcp' : 'cli'generateTextService with:
prompt (userPrompt), systemPromptrole, session, projectRootmaxRetries: 2commandName: 'update-subtask'outputType: isMCP ? 'mcp' : 'cli'telemetryData and tagInfo from responseaiServiceResponse.mainResult.tasks arrayaiServiceResponse.mainResult<info added on ${timestamp}>\n${content}\n</info added on ${timestamp}>subtask.details (create if doesn't exist)[Updated: ${date}] to subtask.descriptionwriteJSON(tasksPath, data, projectRoot, tag)generateTaskFiles() (currently commented out in both)getStatusWithColor()displayAiUsageSummary(telemetryData, 'cli')mcpLog (MCP) or consoleLog (CLI)getDebugFlag(session) true):
Success returns (both modes):
{
success: true, // bulk/single task only
updatedTasks: [...], // bulk/single task only
updatedSubtask: {...}, // subtask only
telemetryData: {...},
tagInfo: {...}
}
Failure returns:
null on errorThis migration will follow the established patterns in tm-core and apps/cli:
packages/tm-core/
src/
commands/
update-task/
# Core Interfaces & Types
types.ts # Shared types, enums, interfaces
interfaces/
update-strategy.interface.ts # IUpdateStrategy contract
update-context.interface.ts # IUpdateContext contract
display.interface.ts # IDisplayManager contract
# Services (Business Logic)
update-task.service.ts # Main orchestrator service
context-builder.service.ts # Builds AI context (uses ContextGatherer, FuzzySearch)
prompt-builder.service.ts # Builds prompts (uses PromptManager)
data-merger.service.ts # Merges AI results with existing data
# Strategies (Update Mode Logic)
strategies/
base-update.strategy.ts # Abstract base class for all strategies
bulk-update.strategy.ts # Bulk task update implementation
single-task-update.strategy.ts # Single task update implementation
subtask-update.strategy.ts # Subtask update implementation
# Utilities & Helpers
validators/
update-input.validator.ts # Validates all input parameters
task-id.validator.ts # Parses and validates task/subtask IDs
display/
cli-display.manager.ts # CLI output formatting
json-display.manager.ts # JSON output formatting
update-display.factory.ts # Creates appropriate display manager
factories/
update-strategy.factory.ts # Creates appropriate strategy based on mode
# Main Entry Point
index.ts # Public API export
apps/cli/
src/
commands/
update-task.command.ts # CLI command definition (uses UpdateTaskService)
/**
* Main service that coordinates the entire update process
* Handles initialization, strategy selection, and result aggregation
*/
export class UpdateTaskService {
constructor(
private readonly configManager: ConfigManager,
private readonly storage: IStorage,
private readonly logger: Logger,
private readonly strategyFactory: UpdateStrategyFactory,
private readonly contextBuilder: ContextBuilderService,
private readonly displayFactory: UpdateDisplayFactory
) {}
async updateTask(options: UpdateTaskOptions): Promise<UpdateTaskResult> {
// 1. Validate inputs
// 2. Detect mode and create strategy
// 3. Build context
// 4. Execute strategy
// 5. Display results
// 6. Return result
}
}
Uses (existing classes):
ConfigManager - Project configurationIStorage - Task persistenceLogger - LoggingContextGatherer - Gather related contextFuzzyTaskSearch - Find relevant tasksPromptManager - Load prompt templatesUses (new classes):
UpdateStrategyFactory - Create update strategyContextBuilderService - Build AI contextUpdateDisplayFactory - Create display manager/**
* Contract for all update strategies
* Defines the common interface for bulk, single, and subtask updates
*/
export interface IUpdateStrategy {
/**
* Validate that the strategy can handle the given context
*/
validate(context: IUpdateContext): Promise<void>;
/**
* Load and filter tasks that need updating
*/
loadTasks(context: IUpdateContext): Promise<TaskLoadResult>;
/**
* Build prompts for AI service
*/
buildPrompts(
context: IUpdateContext,
tasks: TaskLoadResult
): Promise<PromptResult>;
/**
* Call appropriate AI service
*/
callAIService(
context: IUpdateContext,
prompts: PromptResult
): Promise<AIServiceResult>;
/**
* Merge AI results with existing data
*/
mergeResults(
context: IUpdateContext,
aiResult: AIServiceResult,
originalTasks: TaskLoadResult
): Promise<MergeResult>;
/**
* Get the mode this strategy handles
*/
getMode(): UpdateMode;
}
/**
* Provides common functionality for all update strategies
* Implements template method pattern for the update workflow
*/
export abstract class BaseUpdateStrategy implements IUpdateStrategy {
protected readonly logger: Logger;
constructor(
protected readonly contextBuilder: ContextBuilderService,
protected readonly promptBuilder: PromptBuilderService,
protected readonly dataMerger: DataMergerService,
protected readonly aiService: AIService // wrapper around generate[Object|Text]Service
) {
this.logger = getLogger(`UpdateStrategy:${this.getMode()}`);
}
// Template method - defines the workflow
async execute(context: IUpdateContext): Promise<UpdateStrategyResult> {
await this.validate(context);
const tasks = await this.loadTasks(context);
const prompts = await this.buildPrompts(context, tasks);
const aiResult = await this.callAIService(context, prompts);
const merged = await this.mergeResults(context, aiResult, tasks);
return merged;
}
// Subclasses must implement these
abstract validate(context: IUpdateContext): Promise<void>;
abstract loadTasks(context: IUpdateContext): Promise<TaskLoadResult>;
abstract getMode(): UpdateMode;
// Shared implementations with extensibility
async buildPrompts(
context: IUpdateContext,
tasks: TaskLoadResult
): Promise<PromptResult> {
// Delegates to PromptBuilderService with mode-specific params
}
protected abstract getPromptParams(
context: IUpdateContext,
tasks: TaskLoadResult
): PromptParams;
}
/**
* Handles bulk task updates (--from flag)
* Uses generateObjectService for structured updates
*/
export class BulkUpdateStrategy extends BaseUpdateStrategy {
getMode(): UpdateMode {
return UpdateMode.BULK;
}
async validate(context: IUpdateContext): Promise<void> {
if (!context.options.from) {
throw new TaskMasterError('Bulk mode requires --from parameter');
}
// Additional validations...
}
async loadTasks(context: IUpdateContext): Promise<TaskLoadResult> {
// Filter tasks where id >= fromId AND status !== 'done'
}
async callAIService(
context: IUpdateContext,
prompts: PromptResult
): Promise<AIServiceResult> {
// Call generateObjectService with update-tasks schema
}
protected getPromptParams(
context: IUpdateContext,
tasks: TaskLoadResult
): PromptParams {
return {
tasks: tasks.tasks,
updatePrompt: context.options.prompt,
useResearch: context.options.useResearch,
projectContext: tasks.gatheredContext,
// ...
};
}
}
/**
* Handles single subtask updates (--id with dot notation)
* Uses generateTextService for timestamped appends
*/
export class SubtaskUpdateStrategy extends BaseUpdateStrategy {
getMode(): UpdateMode {
return UpdateMode.SUBTASK;
}
async validate(context: IUpdateContext): Promise<void> {
const parsed = TaskIdValidator.parseSubtaskId(context.options.id);
if (!parsed) {
throw new TaskMasterError('Invalid subtask ID format');
}
}
async loadTasks(context: IUpdateContext): Promise<TaskLoadResult> {
// Find parent task, locate specific subtask
// Build context with prev/next subtask info
}
async callAIService(
context: IUpdateContext,
prompts: PromptResult
): Promise<AIServiceResult> {
// Call generateTextService for freeform content
}
async mergeResults(
context: IUpdateContext,
aiResult: AIServiceResult,
originalTasks: TaskLoadResult
): Promise<MergeResult> {
// Append timestamped content to subtask.details
const timestamp = new Date().toISOString();
const formatted = `<info added on ${timestamp}>\n${aiResult.text}\n</info>`;
// ...
}
}
/**
* Handles single task updates (--id without dot)
* Uses generateObjectService for structured updates
*/
export class SingleTaskUpdateStrategy extends BaseUpdateStrategy {
getMode(): UpdateMode {
return UpdateMode.SINGLE;
}
async validate(context: IUpdateContext): Promise<void> {
TaskIdValidator.validateTaskId(context.options.id);
}
async loadTasks(context: IUpdateContext): Promise<TaskLoadResult> {
// Find single task by ID
}
// Similar to BulkUpdateStrategy but operates on single task
}
/**
* Builds context for AI prompts
* Coordinates ContextGatherer and FuzzyTaskSearch
*/
export class ContextBuilderService {
constructor(
private readonly logger: Logger
) {}
async buildContext(
options: ContextBuildOptions
): Promise<BuiltContext> {
try {
const gatherer = new ContextGatherer(
options.projectRoot,
options.tag
);
const allTasksFlat = flattenTasksWithSubtasks(options.allTasks);
const fuzzySearch = new FuzzyTaskSearch(
allTasksFlat,
options.searchMode // 'update' or 'update-subtask'
);
const searchResults = fuzzySearch.findRelevantTasks(
options.searchQuery,
{ maxResults: 5, includeSelf: true }
);
const relevantTaskIds = fuzzySearch.getTaskIds(searchResults);
const finalTaskIds = [
...new Set([...options.targetTaskIds, ...relevantTaskIds])
];
const contextResult = await gatherer.gather({
tasks: finalTaskIds,
format: 'research'
});
return {
context: contextResult.context || '',
taskIds: finalTaskIds
};
} catch (error) {
this.logger.warn(`Context gathering failed: ${error.message}`);
return { context: '', taskIds: options.targetTaskIds };
}
}
}
Uses (existing):
ContextGathererFuzzyTaskSearch/**
* Builds system and user prompts for AI services
* Wraps PromptManager with strategy-specific logic
*/
export class PromptBuilderService {
constructor(
private readonly promptManager: PromptManager,
private readonly logger: Logger
) {}
async buildPrompt(
templateName: string,
params: PromptParams,
variant?: string
): Promise<PromptResult> {
const { systemPrompt, userPrompt } = await this.promptManager.loadPrompt(
templateName,
params,
variant
);
return {
systemPrompt,
userPrompt,
templateName,
params
};
}
}
Uses (existing):
PromptManager/**
* Merges AI service results with existing task data
* Handles different merge strategies for different modes
*/
export class DataMergerService {
constructor(private readonly logger: Logger) {}
/**
* Merge for bulk/single task mode (structured updates)
*/
mergeTasks(
existingTasks: Task[],
updatedTasks: Task[],
options: MergeOptions
): MergeResult {
const updatedTasksMap = new Map(
updatedTasks.map(t => [t.id, t])
);
let updateCount = 0;
const merged = existingTasks.map(task => {
if (updatedTasksMap.has(task.id)) {
const updated = updatedTasksMap.get(task.id)!;
updateCount++;
return {
...task,
...updated,
// Preserve subtasks if not provided by AI
subtasks: updated.subtasks !== undefined
? updated.subtasks
: task.subtasks
};
}
return task;
});
return {
tasks: merged,
updateCount,
mode: 'structured'
};
}
/**
* Merge for subtask mode (timestamped append)
*/
mergeSubtask(
parentTask: Task,
subtaskIndex: number,
newContent: string,
options: SubtaskMergeOptions
): SubtaskMergeResult {
const subtask = parentTask.subtasks![subtaskIndex];
const timestamp = new Date().toISOString();
const formatted = `<info added on ${timestamp}>\n${newContent.trim()}\n</info added on ${timestamp}>`;
subtask.details = (subtask.details ? subtask.details + '\n' : '') + formatted;
// Short prompts get description timestamp
if (options.prompt.length < 100 && subtask.description) {
subtask.description += ` [Updated: ${new Date().toLocaleDateString()}]`;
}
return {
updatedSubtask: subtask,
newlyAddedSnippet: formatted,
parentTask
};
}
}
/**
* Contract for display managers
* Allows different output formats (CLI, JSON, etc.)
*/
export interface IDisplayManager {
/**
* Show tasks before update
*/
showPreUpdate(tasks: Task[], mode: UpdateMode): void;
/**
* Show loading indicator
*/
startLoading(message: string): void;
stopLoading(success?: boolean): void;
/**
* Show post-update results
*/
showPostUpdate(result: UpdateStrategyResult, mode: UpdateMode): void;
/**
* Show telemetry/usage data
*/
showTelemetry(telemetry: TelemetryData): void;
/**
* Show errors
*/
showError(error: Error): void;
}
/**
* Formats output for CLI with colors, tables, and boxes
*/
export class CLIDisplayManager implements IDisplayManager {
constructor(
private readonly logger: Logger,
private readonly isSilent: boolean
) {}
showPreUpdate(tasks: Task[], mode: UpdateMode): void {
// Create table with ID, Title, Status columns
// Show boxed header
// For bulk mode: show completed subtasks info box
}
startLoading(message: string): void {
// startLoadingIndicator(message)
}
// ... implement other methods with chalk, boxen, cli-table3
}
/**
* Creates the appropriate update strategy based on mode
*/
export class UpdateStrategyFactory {
constructor(
private readonly contextBuilder: ContextBuilderService,
private readonly promptBuilder: PromptBuilderService,
private readonly dataMerger: DataMergerService,
private readonly aiService: AIService
) {}
createStrategy(mode: UpdateMode): IUpdateStrategy {
switch (mode) {
case UpdateMode.BULK:
return new BulkUpdateStrategy(
this.contextBuilder,
this.promptBuilder,
this.dataMerger,
this.aiService
);
case UpdateMode.SINGLE:
return new SingleTaskUpdateStrategy(
this.contextBuilder,
this.promptBuilder,
this.dataMerger,
this.aiService
);
case UpdateMode.SUBTASK:
return new SubtaskUpdateStrategy(
this.contextBuilder,
this.promptBuilder,
this.dataMerger,
this.aiService
);
default:
throw new TaskMasterError(`Unknown update mode: ${mode}`);
}
}
detectMode(options: UpdateTaskOptions): UpdateMode {
if (options.from !== undefined) {
return UpdateMode.BULK;
}
if (options.id && typeof options.id === 'string' && options.id.includes('.')) {
return UpdateMode.SUBTASK;
}
if (options.id !== undefined) {
return UpdateMode.SINGLE;
}
throw new TaskMasterError('Must provide either --id or --from parameter');
}
}
/**
* Validates all update task inputs
*/
export class UpdateInputValidator {
static validate(options: UpdateTaskOptions): void {
// Validate tasksPath, prompt, etc.
}
}
/**
* Parses and validates task/subtask IDs
*/
export class TaskIdValidator {
static validateTaskId(id: any): number {
// Parse and validate task ID
}
static parseSubtaskId(id: string): SubtaskIdParts | null {
// Parse "parentId.subtaskId" format
}
}
┌─────────────────────────┐
│ UpdateTaskService │ ◄─── Main Orchestrator
│ (Coordinates) │
└───────┬─────────────────┘
│ uses
├──► UpdateStrategyFactory ──creates──► IUpdateStrategy
│ │
├──► ContextBuilderService │ implements
│ ▼
├──► IDisplayManager ◄──creates── UpdateDisplayFactory
│ │
│ ├── CLIDisplayManager
│ └── JSONDisplayManager
│
└──► ConfigManager (existing)
IStorage (existing)
Logger (existing)
┌────────────────────────────────────────────────────┐
│ IUpdateStrategy │
└────────────────────────────────────────────────────┘
△
│ extends
┌───────────┴────────────┐
│ │
┌───────────────────────┐ ┌──────────────────────┐
│ BaseUpdateStrategy │ │ Abstract base with │
│ (Template Method) │ │ common workflow │
└───────────┬───────────┘ └──────────────────────┘
│ extends
┌───────┼──────────┬─────────────┐
│ │ │ │
┌───▼───┐ ┌─▼────┐ ┌─▼──────────┐ │
│ Bulk │ │Single│ │ Subtask │ │
│Update │ │Task │ │ Update │ │
│ │ │Update│ │ │ │
└───────┘ └──────┘ └────────────┘ │
│
├──► ContextBuilderService
│ ├─uses─► ContextGatherer (existing)
│ └─uses─► FuzzyTaskSearch (existing)
│
├──► PromptBuilderService
│ └─uses─► PromptManager (existing)
│
└──► DataMergerService
// In packages/tm-core/src/commands/update-task/index.ts
/**
* Factory function to create a fully initialized UpdateTaskService
*/
export async function createUpdateTaskService(
configManager: ConfigManager,
storage: IStorage
): Promise<UpdateTaskService> {
const logger = getLogger('UpdateTaskService');
// Create helper services
const contextBuilder = new ContextBuilderService(logger);
const promptManager = getPromptManager(); // existing
const promptBuilder = new PromptBuilderService(promptManager, logger);
const dataMerger = new DataMergerService(logger);
const aiService = new AIService(); // wrapper around generateObjectService/generateTextService
// Create factory
const strategyFactory = new UpdateStrategyFactory(
contextBuilder,
promptBuilder,
dataMerger,
aiService
);
// Create display factory
const displayFactory = new UpdateDisplayFactory();
// Create service
return new UpdateTaskService(
configManager,
storage,
logger,
strategyFactory,
contextBuilder,
displayFactory
);
}
// packages/tm-core/src/commands/update-task/types.ts
export enum UpdateMode {
BULK = 'bulk',
SINGLE = 'single',
SUBTASK = 'subtask'
}
export interface UpdateTaskOptions {
tasksPath: string;
id?: number | string;
from?: number;
prompt: string;
useResearch?: boolean;
context?: UpdateContext;
outputFormat?: 'text' | 'json';
}
export interface UpdateContext {
session?: any;
mcpLog?: any;
projectRoot?: string;
tag?: string;
}
export interface UpdateTaskResult {
success: boolean;
mode: UpdateMode;
updatedTasks?: Task[];
updatedSubtask?: Subtask;
updateCount?: number;
telemetryData?: TelemetryData;
tagInfo?: TagInfo;
}
export interface IUpdateContext {
options: UpdateTaskOptions;
projectRoot: string;
tag?: string;
mode: UpdateMode;
isMCP: boolean;
logger: Logger;
}
export interface TaskLoadResult {
tasks: Task[];
gatheredContext: string;
originalData: TasksData;
}
export interface PromptResult {
systemPrompt: string;
userPrompt: string;
templateName: string;
params: PromptParams;
}
export interface AIServiceResult {
mainResult: any; // structured object or text string
telemetryData?: TelemetryData;
tagInfo?: TagInfo;
}
export interface MergeResult {
tasks?: Task[];
updatedSubtask?: Subtask;
newlyAddedSnippet?: string;
updateCount: number;
mode: 'structured' | 'timestamped';
}
Goal: Establish the type system and interfaces
New Files to Create:
packages/tm-core/src/commands/update-task/types.ts
UpdateMode enumUpdateTaskOptions, UpdateTaskResult, etc.)packages/tm-core/src/commands/update-task/interfaces/update-strategy.interface.ts
IUpdateStrategy interfacepackages/tm-core/src/commands/update-task/interfaces/update-context.interface.ts
IUpdateContext interfacepackages/tm-core/src/commands/update-task/interfaces/display.interface.ts
IDisplayManager interfaceExisting Classes to Study:
BaseExecutor - For abstract class patternsTaskService - For service patternsIStorage - For interface patternsGoal: Build validation and utility classes
New Files to Create:
packages/tm-core/src/commands/update-task/validators/update-input.validator.ts
UpdateInputValidator classpackages/tm-core/src/commands/update-task/validators/task-id.validator.ts
TaskIdValidator classvalidateTaskId() and parseSubtaskId() methodsTests to Create:
update-input.validator.spec.tstask-id.validator.spec.tsGoal: Build the helper services that strategies will use
New Files to Create:
packages/tm-core/src/commands/update-task/context-builder.service.ts
ContextBuilderService classContextGatherer, FuzzyTaskSearchpackages/tm-core/src/commands/update-task/prompt-builder.service.ts
PromptBuilderService classPromptManager (via getPromptManager())packages/tm-core/src/commands/update-task/data-merger.service.ts
DataMergerService classmergeTasks() method (from update-tasks.js lines 250-273)mergeSubtask() method (from update-subtask-by-id.js lines 291-332)Tests to Create:
context-builder.service.spec.tsprompt-builder.service.spec.tsdata-merger.service.spec.tsExisting Classes Used:
ContextGatherer (from scripts/modules/utils/contextGatherer.js)FuzzyTaskSearch (from scripts/modules/utils/fuzzyTaskSearch.js)PromptManager (from scripts/modules/prompt-manager.js)Goal: Implement the update strategies
New Files to Create:
packages/tm-core/src/commands/update-task/strategies/base-update.strategy.ts
BaseUpdateStrategy abstract class implementing IUpdateStrategypackages/tm-core/src/commands/update-task/strategies/bulk-update.strategy.ts
BulkUpdateStrategy class extending BaseUpdateStrategyupdate-tasks.js lines 79-293generateObjectService with COMMAND_SCHEMAS['update-tasks']packages/tm-core/src/commands/update-task/strategies/single-task-update.strategy.ts
SingleTaskUpdateStrategy class extending BaseUpdateStrategygenerateObjectService with COMMAND_SCHEMAS['update-tasks']packages/tm-core/src/commands/update-task/strategies/subtask-update.strategy.ts
SubtaskUpdateStrategy class extending BaseUpdateStrategyupdate-subtask-by-id.js lines 67-378generateTextService for freeform contentTests to Create:
bulk-update.strategy.spec.tssingle-task-update.strategy.spec.tssubtask-update.strategy.spec.tsExisting Classes/Functions Used:
generateObjectService (from scripts/modules/ai-services-unified.js)generateTextService (from scripts/modules/ai-services-unified.js)COMMAND_SCHEMAS (from src/schemas/registry.js)readJSON, writeJSON, flattenTasksWithSubtasks (from scripts/modules/utils.js)Goal: Implement display managers for different output formats
New Files to Create:
packages/tm-core/src/commands/update-task/display/cli-display.manager.ts
CLIDisplayManager class implementing IDisplayManagerchalk, boxen, cli-table3, getStatusWithColor, truncatepackages/tm-core/src/commands/update-task/display/json-display.manager.ts
JSONDisplayManager class implementing IDisplayManagerpackages/tm-core/src/commands/update-task/display/update-display.factory.ts
UpdateDisplayFactory classTests to Create:
cli-display.manager.spec.tsjson-display.manager.spec.tsExisting Functions Used:
getStatusWithColor, startLoadingIndicator, stopLoadingIndicator, displayAiUsageSummary (from scripts/modules/ui.js)truncate, isSilentMode (from scripts/modules/utils.js)Goal: Implement factory for creating strategies
New Files to Create:
packages/tm-core/src/commands/update-task/factories/update-strategy.factory.ts
UpdateStrategyFactory classcreateStrategy(mode) methoddetectMode(options) methodTests to Create:
update-strategy.factory.spec.ts (test mode detection and strategy creation)Goal: Create the main service that ties everything together
New Files to Create:
packages/tm-core/src/commands/update-task/update-task.service.ts
UpdateTaskService classpackages/tm-core/src/commands/update-task/index.ts
createUpdateTaskService() factory functionUpdateTaskService classTests to Create:
update-task.service.spec.ts (integration tests)Existing Classes Used:
ConfigManager (from packages/tm-core/src/config/config-manager.ts)IStorage (from packages/tm-core/src/interfaces/storage.interface.ts)Logger, getLogger (from packages/tm-core/src/logger/)Goal: Wire up the new service to the CLI
New Files to Create:
apps/cli/src/commands/update-task.command.ts
commandercreateUpdateTaskService() and executesFiles to Modify:
apps/cli/src/index.ts (or main CLI entry point)
update-task commandExisting Patterns to Follow:
apps/cli/src/commands/Goal: Ensure everything works together
Tasks:
Run full integration tests
Verify against original functionality
Performance testing
Tests to Create:
update-task.integration.spec.ts - Full workflow testsGoal: Document the new system and deprecate old code
Tasks:
Update documentation
apps/docs/command-reference.mdxAdd deprecation warnings
update and update-subtask commands as deprecatedCreate changeset
Files to Modify:
apps/docs/command-reference.mdx - Update command documentationscripts/modules/task-manager/update-tasks.jsscripts/modules/task-manager/update-subtask-by-id.jsGoal: Remove deprecated code (future version)
Tasks:
Remove old files:
scripts/modules/task-manager/update-tasks.jsscripts/modules/task-manager/update-subtask-by-id.jsClean up any temporary compatibility shims
Update all references in codebase to use new command
# Could maintain old command names as aliases
task-master update --from=3 --prompt="..." # Still works, calls update-task
task-master update-subtask --id=3.2 --prompt="..." # Still works, calls update-task