# Product Requirements Document: tm-core Package - Parse PRD Feature ## Project Overview Create a TypeScript package named `tm-core` at `packages/tm-core` that implements parse-prd functionality using class-based architecture similar to the existing AI providers pattern. ## Design Patterns & Architecture ### Patterns to Apply 1. **Factory Pattern**: Use for `ProviderFactory` to create AI provider instances 2. **Strategy Pattern**: Use for `IAIProvider` implementations and `IStorage` implementations 3. **Facade Pattern**: Use for `TaskMasterCore` as the main API entry point 4. **Template Method Pattern**: Use for `BaseProvider` abstract class 5. **Dependency Injection**: Use throughout for testability (pass dependencies via constructor) 6. **Repository Pattern**: Use for `FileStorage` to abstract data persistence ### Naming Conventions - **Files**: kebab-case (e.g., `task-parser.ts`, `file-storage.ts`) - **Classes**: PascalCase (e.g., `TaskParser`, `FileStorage`) - **Interfaces**: PascalCase with 'I' prefix (e.g., `IStorage`, `IAIProvider`) - **Methods**: camelCase (e.g., `parsePRD`, `loadTasks`) - **Constants**: UPPER_SNAKE_CASE (e.g., `DEFAULT_MODEL`) - **Type aliases**: PascalCase (e.g., `TaskStatus`, `ParseOptions`) ## Exact Folder Structure Required ``` packages/tm-core/ ├── src/ │ ├── index.ts │ ├── types/ │ │ └── index.ts │ ├── interfaces/ │ │ ├── index.ts # Barrel export │ │ ├── storage.interface.ts │ │ ├── ai-provider.interface.ts │ │ └── configuration.interface.ts │ ├── tasks/ │ │ ├── index.ts # Barrel export │ │ └── task-parser.ts │ ├── ai/ │ │ ├── index.ts # Barrel export │ │ ├── base-provider.ts │ │ ├── provider-factory.ts │ │ ├── prompt-builder.ts │ │ └── providers/ │ │ ├── index.ts # Barrel export │ │ ├── anthropic-provider.ts │ │ ├── openai-provider.ts │ │ └── google-provider.ts │ ├── storage/ │ │ ├── index.ts # Barrel export │ │ └── file-storage.ts │ ├── config/ │ │ ├── index.ts # Barrel export │ │ └── config-manager.ts │ ├── utils/ │ │ ├── index.ts # Barrel export │ │ └── id-generator.ts │ └── errors/ │ ├── index.ts # Barrel export │ └── task-master-error.ts ├── tests/ │ ├── task-parser.test.ts │ ├── integration/ │ │ └── parse-prd.test.ts │ └── mocks/ │ └── mock-provider.ts ├── package.json ├── tsconfig.json ├── tsup.config.js └── jest.config.js ``` ## Specific Implementation Requirements ### 1. Create types/index.ts Define these exact TypeScript interfaces: - `Task` interface with fields: id, title, description, status, priority, complexity, dependencies, subtasks, metadata, createdAt, updatedAt, source - `Subtask` interface with fields: id, title, description, completed - `TaskMetadata` interface with fields: parsedFrom, aiProvider, version, tags (optional) - Type literals: `TaskStatus` = 'pending' | 'in-progress' | 'completed' | 'blocked' - Type literals: `TaskPriority` = 'low' | 'medium' | 'high' | 'critical' - Type literals: `TaskComplexity` = 'simple' | 'moderate' | 'complex' - `ParseOptions` interface with fields: dryRun (optional), additionalContext (optional), tag (optional), maxTasks (optional) ### 2. Create interfaces/storage.interface.ts Define `IStorage` interface with these exact methods: - `loadTasks(tag?: string): Promise` - `saveTasks(tasks: Task[], tag?: string): Promise` - `appendTasks(tasks: Task[], tag?: string): Promise` - `updateTask(id: string, task: Partial, tag?: string): Promise` - `deleteTask(id: string, tag?: string): Promise` - `exists(tag?: string): Promise` ### 3. Create interfaces/ai-provider.interface.ts Define `IAIProvider` interface with these exact methods: - `generateCompletion(prompt: string, options?: AIOptions): Promise` - `calculateTokens(text: string): number` - `getName(): string` - `getModel(): string` Define `AIOptions` interface with fields: temperature (optional), maxTokens (optional), systemPrompt (optional) ### 4. Create interfaces/configuration.interface.ts Define `IConfiguration` interface with fields: - `projectPath: string` - `aiProvider: string` - `apiKey?: string` - `aiOptions?: AIOptions` - `mainModel?: string` - `researchModel?: string` - `fallbackModel?: string` - `tasksPath?: string` - `enableTags?: boolean` ### 5. Create tasks/task-parser.ts Create class `TaskParser` with: - Constructor accepting `aiProvider: IAIProvider` and `config: IConfiguration` - Private property `promptBuilder: PromptBuilder` - Public method `parsePRD(prdPath: string, options: ParseOptions = {}): Promise` - Private method `readPRD(prdPath: string): Promise` - Private method `extractTasks(aiResponse: string): Partial[]` - Private method `enrichTasks(rawTasks: Partial[], prdPath: string): Task[]` - Apply **Dependency Injection** pattern via constructor ### 6. Create ai/base-provider.ts Copy existing base-provider.js and convert to TypeScript abstract class: - Abstract class `BaseProvider` implementing `IAIProvider` - Protected properties: `apiKey: string`, `model: string` - Constructor accepting `apiKey: string` and `options: { model?: string }` - Abstract methods matching IAIProvider interface - Abstract method `getDefaultModel(): string` - Apply **Template Method** pattern for common provider logic ### 7. Create ai/provider-factory.ts Create class `ProviderFactory` with: - Static method `create(config: { provider: string; apiKey?: string; model?: string }): Promise` - Switch statement for providers: 'anthropic', 'openai', 'google' - Dynamic imports for each provider - Throw error for unknown providers - Apply **Factory** pattern for creating provider instances Example implementation structure: ```typescript switch (provider.toLowerCase()) { case 'anthropic': const { AnthropicProvider } = await import('./providers/anthropic-provider.js'); return new AnthropicProvider(apiKey, { model }); } ``` ### 8. Create ai/providers/anthropic-provider.ts Create class `AnthropicProvider` extending `BaseProvider`: - Import Anthropic SDK: `import { Anthropic } from '@anthropic-ai/sdk'` - Private property `client: Anthropic` - Implement all abstract methods from BaseProvider - Default model: 'claude-3-sonnet-20240229' - Handle API errors and wrap with meaningful messages ### 9. Create ai/providers/openai-provider.ts (placeholder) Create class `OpenAIProvider` extending `BaseProvider`: - Import OpenAI SDK when implemented - For now, throw error: "OpenAI provider not yet implemented" ### 10. Create ai/providers/google-provider.ts (placeholder) Create class `GoogleProvider` extending `BaseProvider`: - Import Google Generative AI SDK when implemented - For now, throw error: "Google provider not yet implemented" ### 11. Create ai/prompt-builder.ts Create class `PromptBuilder` with: - Method `buildParsePrompt(prdContent: string, options: ParseOptions = {}): string` - Method `buildExpandPrompt(task: string, context?: string): string` - Use template literals for prompt construction - Include specific JSON format instructions in prompts ### 9. Create storage/file-storage.ts Create class `FileStorage` implementing `IStorage`: - Private property `basePath: string` set to `{projectPath}/.taskmaster` - Constructor accepting `projectPath: string` - Private method `getTasksPath(tag?: string): string` returning correct path based on tag - Private method `ensureDirectory(dir: string): Promise` - Implement all IStorage methods - Handle ENOENT errors by returning empty arrays - Use JSON format with structure: `{ tasks: Task[], metadata: { version: string, lastModified: string } }` - Apply **Repository** pattern for data access abstraction ### 10. Create config/config-manager.ts Create class `ConfigManager`: - Private property `config: IConfiguration` - Constructor accepting `options: Partial` - Use Zod for validation with schema matching IConfiguration - Method `get(key: K): IConfiguration[K]` - Method `getAll(): IConfiguration` - Method `validate(): boolean` - Default values: projectPath = process.cwd(), aiProvider = 'anthropic', enableTags = true ### 11. Create utils/id-generator.ts Export functions: - `generateTaskId(index: number = 0): string` returning format `task_{timestamp}_{index}_{random}` - `generateSubtaskId(parentId: string, index: number = 0): string` returning format `{parentId}_sub_{index}_{random}` ### 16. Create src/index.ts Create main class `TaskMasterCore`: - Private properties: `config: ConfigManager`, `storage: IStorage`, `aiProvider?: IAIProvider`, `parser?: TaskParser` - Constructor accepting `options: Partial` - Method `initialize(): Promise` for lazy loading - Method `parsePRD(prdPath: string, options: ParseOptions = {}): Promise` - Method `getTasks(tag?: string): Promise` - Apply **Facade** pattern to provide simple API over complex subsystems Export: - Class `TaskMasterCore` - Function `createTaskMaster(options: Partial): TaskMasterCore` - All types from './types' - All interfaces from './interfaces/*' Import statements should use kebab-case: ```typescript import { TaskParser } from './tasks/task-parser'; import { FileStorage } from './storage/file-storage'; import { ConfigManager } from './config/config-manager'; import { ProviderFactory } from './ai/provider-factory'; ``` ### 17. Configure package.json Create package.json with: - name: "@task-master/core" - version: "0.1.0" - type: "module" - main: "./dist/index.js" - module: "./dist/index.mjs" - types: "./dist/index.d.ts" - exports map for proper ESM/CJS support - scripts: build (tsup), dev (tsup --watch), test (jest), typecheck (tsc --noEmit) - dependencies: zod@^3.23.8 - peerDependencies: @anthropic-ai/sdk, openai, @google/generative-ai - devDependencies: typescript, tsup, jest, ts-jest, @types/node, @types/jest ### 18. Configure TypeScript Create tsconfig.json with: - target: "ES2022" - module: "ESNext" - strict: true (with all strict flags enabled) - declaration: true - outDir: "./dist" - rootDir: "./src" ### 19. Configure tsup Create tsup.config.js with: - entry: ['src/index.ts'] - format: ['cjs', 'esm'] - dts: true - sourcemap: true - clean: true - external: AI provider SDKs ### 20. Configure Jest Create jest.config.js with: - preset: 'ts-jest' - testEnvironment: 'node' - Coverage threshold: 80% for all metrics ## Build Process 1. Use tsup to compile TypeScript to both CommonJS and ESM 2. Generate .d.ts files for TypeScript consumers 3. Output to dist/ directory 4. Ensure tree-shaking works properly ## Testing Requirements - Create unit tests for TaskParser in tests/task-parser.test.ts - Create MockProvider class in tests/mocks/mock-provider.ts for testing without API calls - Test error scenarios (file not found, invalid JSON, etc.) - Create integration test in tests/integration/parse-prd.test.ts - Follow kebab-case naming for all test files ## Success Criteria - TypeScript compilation with zero errors - No use of 'any' type - All interfaces properly exported - Compatible with existing tasks.json format - Feature flag support via USE_TM_CORE environment variable ## Import/Export Conventions - Use named exports for all classes and interfaces - Use barrel exports (index.ts) in each directory - Import types/interfaces with type-only imports: `import type { Task } from '../types'` - Group imports in order: Node built-ins, external packages, internal packages, relative imports - Use .js extension in import paths for ESM compatibility ## Error Handling Patterns - Create custom error classes in `src/errors/` directory - All public methods should catch and wrap errors with context - Use error codes for different error types (e.g., 'FILE_NOT_FOUND', 'PARSE_ERROR') - Never expose internal implementation details in error messages - Log errors to console.error only in development mode ## Barrel Exports Content ### interfaces/index.ts ```typescript export type { IStorage } from './storage.interface'; export type { IAIProvider, AIOptions } from './ai-provider.interface'; export type { IConfiguration } from './configuration.interface'; ``` ### tasks/index.ts ```typescript export { TaskParser } from './task-parser'; ``` ### ai/index.ts ```typescript export { BaseProvider } from './base-provider'; export { ProviderFactory } from './provider-factory'; export { PromptBuilder } from './prompt-builder'; ``` ### ai/providers/index.ts ```typescript export { AnthropicProvider } from './anthropic-provider'; export { OpenAIProvider } from './openai-provider'; export { GoogleProvider } from './google-provider'; ``` ### storage/index.ts ```typescript export { FileStorage } from './file-storage'; ``` ### config/index.ts ```typescript export { ConfigManager } from './config-manager'; ``` ### utils/index.ts ```typescript export { generateTaskId, generateSubtaskId } from './id-generator'; ``` ### errors/index.ts ```typescript export { TaskMasterError } from './task-master-error'; ```