From 8ad9ccd6b731e7fa838f07bb0bb3b65e2743c335 Mon Sep 17 00:00:00 2001 From: Ralph Khreish <35776126+Crunchyman-ralph@users.noreply.github.com> Date: Tue, 29 Jul 2025 19:55:38 +0300 Subject: [PATCH] chore: refactor and cleanup - remove eslint - refactor code into common design patterns where needed - refactor taskMasterApi from 1.5k lines to smaller chunks and different files - removed taskFileReader (not used anywhere) - added support for tag selection (wip) - added configuration page where a user can see his config.json more visually --- apps/extension/eslint.config.mjs | 34 - apps/extension/package.json | 8 +- apps/extension/package.mjs | 2 +- apps/extension/src/components/ConfigView.tsx | 291 +++ .../TaskDetails/AIActionsSection.tsx | 201 ++ .../components/TaskDetails/DetailsSection.tsx | 178 ++ .../components/TaskDetails/PriorityBadge.tsx | 47 + .../TaskDetails/SubtasksSection.tsx | 233 +++ .../TaskDetails/TaskMetadataSidebar.tsx | 288 +++ .../components/TaskDetails/useTaskDetails.ts | 133 ++ .../components/TaskDetailsView.original.tsx | 1304 +++++++++++++ .../src/components/TaskDetailsView.tsx | 1340 +------------ .../src/components/ui/CollapsibleSection.tsx | 61 + apps/extension/src/components/ui/badge.tsx | 4 +- .../src/components/ui/breadcrumb.tsx | 2 +- apps/extension/src/components/ui/button.tsx | 4 +- apps/extension/src/components/ui/card.tsx | 2 +- .../src/components/ui/dropdown-menu.tsx | 2 +- apps/extension/src/components/ui/label.tsx | 2 +- .../src/components/ui/scroll-area.tsx | 6 +- .../extension/src/components/ui/separator.tsx | 2 +- .../components/ui/shadcn-io/kanban/index.tsx | 2 +- apps/extension/src/components/ui/textarea.tsx | 2 +- apps/extension/src/extension.ts | 1510 ++------------- apps/extension/src/services/config-service.ts | 141 ++ apps/extension/src/services/error-handler.ts | 167 ++ .../src/services/notification-preferences.ts | 129 ++ .../extension/src/services/polling-service.ts | 92 + .../src/services/polling-strategies.ts | 67 + .../extension/src/services/task-repository.ts | 138 ++ .../extension/src/services/webview-manager.ts | 356 ++++ apps/extension/src/utils/configManager.ts | 2 +- apps/extension/src/utils/connectionManager.ts | 10 +- apps/extension/src/utils/errorHandler.ts | 14 +- apps/extension/src/utils/event-emitter.ts | 34 + apps/extension/src/utils/logger.ts | 26 +- apps/extension/src/utils/mcpClient.ts | 2 +- .../task-master-api/cache/cache-manager.ts | 253 +++ .../src/utils/task-master-api/index.ts | 471 +++++ .../src/utils/task-master-api/mcp-client.ts | 98 + .../transformers/task-transformer.ts | 477 +++++ .../src/utils/task-master-api/types/index.ts | 156 ++ apps/extension/src/utils/taskFileReader.ts | 215 --- apps/extension/src/utils/taskMasterApi.ts | 1348 ------------- apps/extension/src/webview/App.tsx | 150 ++ .../src/webview/components/ErrorBoundary.tsx | 113 ++ .../src/webview/components/PollingStatus.tsx | 84 + .../src/webview/components/PriorityBadge.tsx | 30 + .../src/webview/components/TagDropdown.tsx | 141 ++ .../src/webview/components/TaskCard.tsx | 67 + .../src/webview/components/TaskEditModal.tsx | 242 +++ .../webview/components/TaskMasterKanban.tsx | 363 ++++ .../src/webview/components/ToastContainer.tsx | 31 + .../webview/components/ToastNotification.tsx | 167 ++ apps/extension/src/webview/constants/index.ts | 17 + .../src/webview/contexts/VSCodeContext.tsx | 32 + .../src/webview/hooks/useVSCodeMessages.ts | 259 +++ .../src/webview/hooks/useWebviewHeight.ts | 42 + apps/extension/src/webview/index.tsx | 1712 +---------------- .../src/webview/reducers/appReducer.ts | 187 ++ apps/extension/src/webview/types/index.ts | 120 ++ apps/extension/src/webview/utils/toast.ts | 56 + biome.json | 7 +- package-lock.json | 1522 +++------------ package.json | 4 +- 65 files changed, 7969 insertions(+), 7231 deletions(-) delete mode 100644 apps/extension/eslint.config.mjs create mode 100644 apps/extension/src/components/ConfigView.tsx create mode 100644 apps/extension/src/components/TaskDetails/AIActionsSection.tsx create mode 100644 apps/extension/src/components/TaskDetails/DetailsSection.tsx create mode 100644 apps/extension/src/components/TaskDetails/PriorityBadge.tsx create mode 100644 apps/extension/src/components/TaskDetails/SubtasksSection.tsx create mode 100644 apps/extension/src/components/TaskDetails/TaskMetadataSidebar.tsx create mode 100644 apps/extension/src/components/TaskDetails/useTaskDetails.ts create mode 100644 apps/extension/src/components/TaskDetailsView.original.tsx create mode 100644 apps/extension/src/components/ui/CollapsibleSection.tsx create mode 100644 apps/extension/src/services/config-service.ts create mode 100644 apps/extension/src/services/error-handler.ts create mode 100644 apps/extension/src/services/notification-preferences.ts create mode 100644 apps/extension/src/services/polling-service.ts create mode 100644 apps/extension/src/services/polling-strategies.ts create mode 100644 apps/extension/src/services/task-repository.ts create mode 100644 apps/extension/src/services/webview-manager.ts create mode 100644 apps/extension/src/utils/event-emitter.ts create mode 100644 apps/extension/src/utils/task-master-api/cache/cache-manager.ts create mode 100644 apps/extension/src/utils/task-master-api/index.ts create mode 100644 apps/extension/src/utils/task-master-api/mcp-client.ts create mode 100644 apps/extension/src/utils/task-master-api/transformers/task-transformer.ts create mode 100644 apps/extension/src/utils/task-master-api/types/index.ts delete mode 100644 apps/extension/src/utils/taskFileReader.ts delete mode 100644 apps/extension/src/utils/taskMasterApi.ts create mode 100644 apps/extension/src/webview/App.tsx create mode 100644 apps/extension/src/webview/components/ErrorBoundary.tsx create mode 100644 apps/extension/src/webview/components/PollingStatus.tsx create mode 100644 apps/extension/src/webview/components/PriorityBadge.tsx create mode 100644 apps/extension/src/webview/components/TagDropdown.tsx create mode 100644 apps/extension/src/webview/components/TaskCard.tsx create mode 100644 apps/extension/src/webview/components/TaskEditModal.tsx create mode 100644 apps/extension/src/webview/components/TaskMasterKanban.tsx create mode 100644 apps/extension/src/webview/components/ToastContainer.tsx create mode 100644 apps/extension/src/webview/components/ToastNotification.tsx create mode 100644 apps/extension/src/webview/constants/index.ts create mode 100644 apps/extension/src/webview/contexts/VSCodeContext.tsx create mode 100644 apps/extension/src/webview/hooks/useVSCodeMessages.ts create mode 100644 apps/extension/src/webview/hooks/useWebviewHeight.ts create mode 100644 apps/extension/src/webview/reducers/appReducer.ts create mode 100644 apps/extension/src/webview/types/index.ts create mode 100644 apps/extension/src/webview/utils/toast.ts diff --git a/apps/extension/eslint.config.mjs b/apps/extension/eslint.config.mjs deleted file mode 100644 index d4c8915c..00000000 --- a/apps/extension/eslint.config.mjs +++ /dev/null @@ -1,34 +0,0 @@ -import typescriptEslint from '@typescript-eslint/eslint-plugin'; -import tsParser from '@typescript-eslint/parser'; - -export default [ - { - files: ['**/*.ts'] - }, - { - plugins: { - '@typescript-eslint': typescriptEslint - }, - - languageOptions: { - parser: tsParser, - ecmaVersion: 2022, - sourceType: 'module' - }, - - rules: { - '@typescript-eslint/naming-convention': [ - 'warn', - { - selector: 'import', - format: ['camelCase', 'PascalCase'] - } - ], - - curly: 'warn', - eqeqeq: 'warn', - 'no-throw-literal': 'warn', - semi: 'warn' - } - } -]; diff --git a/apps/extension/package.json b/apps/extension/package.json index 14d6cf26..edfdc0ea 100644 --- a/apps/extension/package.json +++ b/apps/extension/package.json @@ -192,15 +192,14 @@ "vscode:prepublish": "npm run build", "build": "npm run build:js && npm run build:css", "build:js": "node ./esbuild.js --production", - "build:css": "npx @tailwindcss/cli -o ./dist/index.css --minify", + "build:css": "npx @tailwindcss/cli -i ./src/webview/index.css -o ./dist/index.css --minify", "package": "npm exec node ./package.mjs", "package:direct": "node ./package.mjs", "debug:env": "node ./debug-env.mjs", "compile": "node ./esbuild.js", "watch": "npm run watch:js & npm run watch:css", "watch:js": "node ./esbuild.js --watch", - "watch:css": "npx @tailwindcss/cli -o ./dist/index.css --watch", - "lint": "eslint src --ext ts,tsx", + "watch:css": "npx @tailwindcss/cli -i ./src/webview/index.css -o ./dist/index.css --watch", "test": "vscode-test", "check-types": "tsc --noEmit" }, @@ -221,8 +220,6 @@ "@types/react": "19.1.8", "@types/react-dom": "19.1.6", "@types/vscode": "^1.101.0", - "@typescript-eslint/eslint-plugin": "^8.31.1", - "@typescript-eslint/parser": "^8.31.1", "@vscode/test-cli": "^0.0.11", "@vscode/test-electron": "^2.5.2", "@vscode/vsce": "^2.32.0", @@ -231,7 +228,6 @@ "clsx": "^2.1.1", "esbuild": "^0.25.3", "esbuild-postcss": "^0.0.4", - "eslint": "^9.25.1", "fs-extra": "^11.3.0", "lucide-react": "^0.525.0", "npm-run-all": "^4.1.5", diff --git a/apps/extension/package.mjs b/apps/extension/package.mjs index b2882747..2ffeab9b 100644 --- a/apps/extension/package.mjs +++ b/apps/extension/package.mjs @@ -1,7 +1,7 @@ import { execSync } from 'child_process'; -import fs from 'fs-extra'; import path from 'path'; import { fileURLToPath } from 'url'; +import fs from 'fs-extra'; // --- Configuration --- const __filename = fileURLToPath(import.meta.url); diff --git a/apps/extension/src/components/ConfigView.tsx b/apps/extension/src/components/ConfigView.tsx new file mode 100644 index 00000000..1b04b602 --- /dev/null +++ b/apps/extension/src/components/ConfigView.tsx @@ -0,0 +1,291 @@ +import { ArrowLeft, RefreshCw, Settings } from 'lucide-react'; +import type React from 'react'; +import { useEffect, useState } from 'react'; +import { Badge } from './ui/badge'; +import { Button } from './ui/button'; +import { + Card, + CardContent, + CardDescription, + CardHeader, + CardTitle +} from './ui/card'; +import { ScrollArea } from './ui/scroll-area'; +import { Separator } from './ui/separator'; + +interface ModelConfig { + provider: string; + modelId: string; + maxTokens: number; + temperature: number; +} + +interface ConfigData { + models?: { + main?: ModelConfig; + research?: ModelConfig; + fallback?: ModelConfig; + }; + global?: { + defaultNumTasks?: number; + defaultSubtasks?: number; + defaultPriority?: string; + projectName?: string; + responseLanguage?: string; + }; +} + +interface ConfigViewProps { + sendMessage: (message: any) => Promise; + onNavigateBack: () => void; +} + +export const ConfigView: React.FC = ({ + sendMessage, + onNavigateBack +}) => { + const [config, setConfig] = useState(null); + const [loading, setLoading] = useState(true); + const [error, setError] = useState(null); + + const loadConfig = async () => { + setLoading(true); + setError(null); + try { + const response = await sendMessage({ type: 'getConfig' }); + setConfig(response); + } catch (err) { + setError('Failed to load configuration'); + console.error('Error loading config:', err); + } finally { + setLoading(false); + } + }; + + useEffect(() => { + loadConfig(); + }, []); + + const modelLabels = { + main: { + label: 'Main Model', + icon: '🤖', + description: 'Primary model for task generation' + }, + research: { + label: 'Research Model', + icon: '🔍', + description: 'Model for research-backed operations' + }, + fallback: { + label: 'Fallback Model', + icon: '🔄', + description: 'Backup model if primary fails' + } + }; + + return ( +
+ {/* Header */} +
+
+ +
+ +

Task Master Configuration

+
+
+ +
+ + {/* Content */} + +
+ {loading ? ( +
+ +
+ ) : error ? ( +
{error}
+ ) : config ? ( +
+ {/* Models Section */} + + + AI Models + + Models configured for different Task Master operations + + + + {config.models && + Object.entries(config.models).map(([key, modelConfig]) => { + const label = + modelLabels[key as keyof typeof modelLabels]; + if (!label || !modelConfig) return null; + + return ( +
+
+ {label.icon} +
+

{label.label}

+

+ {label.description} +

+
+
+
+
+ + Provider: + + + {modelConfig.provider} + +
+
+ + Model: + + + {modelConfig.modelId} + +
+
+ + Max Tokens: + + + {modelConfig.maxTokens.toLocaleString()} + +
+
+ + Temperature: + + + {modelConfig.temperature} + +
+
+
+ ); + })} +
+
+ + {/* Task Defaults Section */} + {config.global && ( + + + Task Defaults + + Default values for new tasks and subtasks + + + +
+
+ + Default Number of Tasks + + + {config.global.defaultNumTasks || 10} + +
+ +
+ + Default Number of Subtasks + + + {config.global.defaultSubtasks || 5} + +
+ +
+ + Default Priority + + + {config.global.defaultPriority || 'medium'} + +
+ {config.global.projectName && ( + <> + +
+ + Project Name + + + {config.global.projectName} + +
+ + )} + {config.global.responseLanguage && ( + <> + +
+ + Response Language + + + {config.global.responseLanguage} + +
+ + )} +
+
+
+ )} + + {/* Info Card */} + + +

+ To modify these settings, go to{' '} + + .taskmaster/config.json + {' '} + and modify them, or use the MCP. +

+
+
+
+ ) : ( +
+ No configuration found. Please run `task-master init` in your + project. +
+ )} +
+
+
+ ); +}; diff --git a/apps/extension/src/components/TaskDetails/AIActionsSection.tsx b/apps/extension/src/components/TaskDetails/AIActionsSection.tsx new file mode 100644 index 00000000..49bd03e5 --- /dev/null +++ b/apps/extension/src/components/TaskDetails/AIActionsSection.tsx @@ -0,0 +1,201 @@ +import type React from 'react'; +import { useState } from 'react'; +import { Button } from '@/components/ui/button'; +import { Label } from '@/components/ui/label'; +import { Textarea } from '@/components/ui/textarea'; +import { CollapsibleSection } from '@/components/ui/CollapsibleSection'; +import { Wand2, Loader2, PlusCircle } from 'lucide-react'; +import type { TaskMasterTask } from '../../webview/types'; + +interface AIActionsSectionProps { + currentTask: TaskMasterTask; + isSubtask: boolean; + parentTask?: TaskMasterTask | null; + sendMessage: (message: any) => Promise; + refreshComplexityAfterAI: () => void; + onRegeneratingChange?: (isRegenerating: boolean) => void; + onAppendingChange?: (isAppending: boolean) => void; +} + +export const AIActionsSection: React.FC = ({ + currentTask, + isSubtask, + parentTask, + sendMessage, + refreshComplexityAfterAI, + onRegeneratingChange, + onAppendingChange +}) => { + const [prompt, setPrompt] = useState(''); + const [isRegenerating, setIsRegenerating] = useState(false); + const [isAppending, setIsAppending] = useState(false); + + const handleRegenerate = async () => { + if (!currentTask || !prompt.trim()) { + return; + } + + setIsRegenerating(true); + try { + if (isSubtask && parentTask) { + await sendMessage({ + type: 'updateSubtask', + data: { + taskId: `${parentTask.id}.${currentTask.id}`, + prompt: prompt, + options: { research: false } + } + }); + } else { + await sendMessage({ + type: 'updateTask', + data: { + taskId: currentTask.id, + updates: { description: prompt }, + options: { append: false, research: false } + } + }); + } + + refreshComplexityAfterAI(); + } catch (error) { + console.error('❌ TaskDetailsView: Failed to regenerate task:', error); + } finally { + setIsRegenerating(false); + setPrompt(''); + } + }; + + const handleAppend = async () => { + if (!currentTask || !prompt.trim()) { + return; + } + + setIsAppending(true); + try { + if (isSubtask && parentTask) { + await sendMessage({ + type: 'updateSubtask', + data: { + taskId: `${parentTask.id}.${currentTask.id}`, + prompt: prompt, + options: { research: false } + } + }); + } else { + await sendMessage({ + type: 'updateTask', + data: { + taskId: currentTask.id, + updates: { description: prompt }, + options: { append: true, research: false } + } + }); + } + + refreshComplexityAfterAI(); + } catch (error) { + console.error('❌ TaskDetailsView: Failed to append to task:', error); + } finally { + setIsAppending(false); + setPrompt(''); + } + }; + + return ( + +
+
+ +