5.7 KiB
5.7 KiB
Task Master Migration Roadmap
Overview
Gradual migration from scripts-based architecture to a clean monorepo with separated concerns.
Architecture Vision
┌─────────────────────────────────────────────────┐
│ User Interfaces │
├──────────┬──────────┬──────────┬────────────────┤
│ @tm/cli │ @tm/mcp │ @tm/ext │ @tm/web │
│ (CLI) │ (MCP) │ (VSCode)│ (Future) │
└──────────┴──────────┴──────────┴────────────────┘
│
▼
┌──────────────────────┐
│ @tm/core │
│ (Business Logic) │
└──────────────────────┘
Migration Phases
Phase 1: Core Extraction ✅ (In Progress)
Goal: Move all business logic to @tm/core
- Create @tm/core package structure
- Move types and interfaces
- Implement TaskMasterCore facade
- Move storage adapters
- Move task services
- Move AI providers
- Move parser logic
- Complete test coverage
Phase 2: CLI Package Creation 🚧 (Started)
Goal: Create @tm/cli as a thin presentation layer
- Create @tm/cli package structure
- Implement Command interface pattern
- Create CommandRegistry
- Build legacy bridge/adapter
- Migrate list-tasks command
- Migrate remaining commands one by one
- Remove UI logic from core
Phase 3: Transitional Integration
Goal: Use new packages in existing scripts without breaking changes
// scripts/modules/commands.js gradually adopts new commands
import { ListTasksCommand } from '@tm/cli';
const listCommand = new ListTasksCommand();
// Old interface remains the same
programInstance
.command('list')
.action(async (options) => {
// Use new command internally
const result = await listCommand.execute(convertOptions(options));
});
Phase 4: MCP Package
Goal: Separate MCP server as its own package
- Create @tm/mcp package
- Move MCP server code
- Use @tm/core for all logic
- MCP becomes a thin RPC layer
Phase 5: Complete Migration
Goal: Remove old scripts, pure monorepo
- All commands migrated to @tm/cli
- Remove scripts/modules/task-manager/*
- Remove scripts/modules/commands.js
- Update bin/task-master.js to use @tm/cli
- Clean up dependencies
Current Transitional Strategy
1. Adapter Pattern (commands-adapter.js)
// Checks if new CLI is available and uses it
// Falls back to legacy implementation if not
export async function listTasksAdapter(...args) {
if (cliAvailable) {
return useNewImplementation(...args);
}
return useLegacyImplementation(...args);
}
2. Command Bridge Pattern
// Allows new commands to work in old code
const bridge = new CommandBridge(new ListTasksCommand());
const data = await bridge.run(legacyOptions); // Legacy style
const result = await bridge.execute(newOptions); // New style
3. Gradual File Migration
Instead of big-bang refactoring:
- Create new implementation in @tm/cli
- Add adapter in commands-adapter.js
- Update commands.js to use adapter
- Test both paths work
- Eventually remove adapter when all migrated
Benefits of This Approach
- No Breaking Changes: Existing CLI continues to work
- Incremental PRs: Each command can be migrated separately
- Parallel Development: New features can use new architecture
- Easy Rollback: Can disable new implementation if issues
- Clear Separation: Business logic (core) vs presentation (cli/mcp/etc)
Example PR Sequence
PR 1: Core Package Setup ✅
- Create @tm/core
- Move types and interfaces
- Basic TaskMasterCore implementation
PR 2: CLI Package Foundation ✅
- Create @tm/cli
- Command interface and registry
- Legacy bridge utilities
PR 3: First Command Migration
- Migrate list-tasks to new system
- Add adapter in scripts
- Test both implementations
PR 4-N: Migrate Commands One by One
- Each PR migrates 1-2 related commands
- Small, reviewable changes
- Continuous delivery
Final PR: Cleanup
- Remove legacy implementations
- Remove adapters
- Update documentation
Testing Strategy
Dual Testing During Migration
describe('List Tasks', () => {
it('works with legacy implementation', async () => {
// Force legacy
const result = await legacyListTasks(...);
expect(result).toBeDefined();
});
it('works with new implementation', async () => {
// Force new
const command = new ListTasksCommand();
const result = await command.execute(...);
expect(result.success).toBe(true);
});
it('adapter chooses correctly', async () => {
// Let adapter decide
const result = await listTasksAdapter(...);
expect(result).toBeDefined();
});
});
Success Metrics
- All commands migrated without breaking changes
- Test coverage maintained or improved
- Performance maintained or improved
- Cleaner, more maintainable codebase
- Easy to add new interfaces (web, desktop, etc.)
Notes for Contributors
- Keep PRs Small: Migrate one command at a time
- Test Both Paths: Ensure legacy and new both work
- Document Changes: Update this roadmap as you go
- Communicate: Discuss in PRs if architecture needs adjustment
This is a living document - update as the migration progresses!