fix(extension): address PR review comments and improve implementation

- Fixed InternalError class definition in errorHandler.ts
- Updated extension configuration and CI workflows
- Improved error handling and type safety
- Enhanced build and release automation
- Updated documentation and changelogs

Addresses review feedback on PR #997
This commit is contained in:
DavidMaliglowka
2025-07-23 12:27:54 -05:00
parent 14bd559bd6
commit a79fd29036
18 changed files with 610 additions and 200 deletions

View File

@@ -262,7 +262,7 @@ export const TaskDetailsView: React.FC<TaskDetailsViewProps> = ({
}) => {
const context = useContext(VSCodeContext);
if (!context)
throw new Error('TaskDetailsView must be used within VSCodeContext');
{throw new Error('TaskDetailsView must be used within VSCodeContext');}
const { state, sendMessage } = context;
const { tasks } = state;
@@ -372,7 +372,7 @@ export const TaskDetailsView: React.FC<TaskDetailsViewProps> = ({
// Handle running complexity analysis for a task
const handleRunComplexityAnalysis = useCallback(async () => {
if (!currentTask) return;
if (!currentTask) {return;}
setIsLoadingComplexity(true);
try {
@@ -416,7 +416,7 @@ export const TaskDetailsView: React.FC<TaskDetailsViewProps> = ({
// Function to fetch task file data (implementation details and test strategy only)
const fetchTaskFileData = async () => {
if (!currentTask?.id) return;
if (!currentTask?.id) {return;}
setIsLoadingTaskFileData(true);
setTaskFileDataError(null);
@@ -543,7 +543,7 @@ export const TaskDetailsView: React.FC<TaskDetailsViewProps> = ({
// Handle AI Actions
const handleRegenerate = async () => {
if (!currentTask || !prompt.trim()) return;
if (!currentTask || !prompt.trim()) {return;}
setIsRegenerating(true);
try {
@@ -584,7 +584,7 @@ export const TaskDetailsView: React.FC<TaskDetailsViewProps> = ({
};
const handleAppend = async () => {
if (!currentTask || !prompt.trim()) return;
if (!currentTask || !prompt.trim()) {return;}
setIsAppending(true);
try {
@@ -626,7 +626,7 @@ export const TaskDetailsView: React.FC<TaskDetailsViewProps> = ({
// Handle adding a new subtask
const handleAddSubtask = async () => {
if (!currentTask || !newSubtaskTitle.trim() || isSubtask) return;
if (!currentTask || !newSubtaskTitle.trim() || isSubtask) {return;}
setIsSubmittingSubtask(true);
try {
@@ -672,7 +672,7 @@ export const TaskDetailsView: React.FC<TaskDetailsViewProps> = ({
// Handle status change
const handleStatusChange = async (newStatus: TaskMasterTask['status']) => {
if (!currentTask) return;
if (!currentTask) {return;}
try {
await sendMessage({

View File

@@ -24,6 +24,7 @@ import {
} from './utils/errorHandler';
import { getToastDuration } from './utils/notificationPreferences';
import { parseTaskFileData } from './utils/taskFileReader';
import { TaskMasterTask } from './utils/taskMasterApi';
// Global MCP client manager instance
let mcpClient: MCPClientManager | null = null;
@@ -39,7 +40,7 @@ interface PollingState {
timer?: NodeJS.Timeout;
isPolling: boolean;
interval: number;
lastTaskData?: any[];
lastTaskData?: TaskMasterTask[];
errorCount: number;
maxErrors: number;
// Adaptive frequency properties
@@ -55,7 +56,7 @@ interface PollingState {
reconnectBackoffMultiplier: number;
lastSuccessfulConnection?: number;
isOfflineMode: boolean;
cachedTaskData?: any[];
cachedTaskData?: TaskMasterTask[];
}
let pollingState: PollingState = {
@@ -351,7 +352,7 @@ function adjustPollingFrequency(): void {
// Low activity: reduce polling frequency with exponential backoff
const backoffMultiplier = Math.min(
4,
Math.pow(1.5, pollingState.consecutiveNoChanges - 3)
1.5 ** (pollingState.consecutiveNoChanges - 3)
);
newInterval = Math.min(
pollingState.maxInterval,
@@ -1031,43 +1032,65 @@ export function activate(context: vscode.ExtensionContext) {
case 'readTaskFileData':
console.log('📄 Reading task file data:', message.data);
const { requestId } = message;
try {
const { taskId, tag: tagName = 'master' } = message.data;
{
const { requestId } = message;
try {
const { taskId, tag: tagName = 'master' } = message.data;
// Get workspace folder
const workspaceFolder = vscode.workspace.workspaceFolders?.[0];
if (!workspaceFolder) {
throw new Error('No workspace folder found');
}
// Get workspace folder
const workspaceFolder = vscode.workspace.workspaceFolders?.[0];
if (!workspaceFolder) {
throw new Error('No workspace folder found');
}
// Build path to tasks.json
const tasksJsonPath = path.join(
workspaceFolder.uri.fsPath,
'.taskmaster',
'tasks',
'tasks.json'
);
console.log('🔍 Looking for tasks.json at:', tasksJsonPath);
// Check if file exists
if (!fs.existsSync(tasksJsonPath)) {
// Try legacy location
const legacyPath = path.join(
// Build path to tasks.json
const tasksJsonPath = path.join(
workspaceFolder.uri.fsPath,
'.taskmaster',
'tasks',
'tasks.json'
);
console.log('🔍 Trying legacy path:', legacyPath);
if (!fs.existsSync(legacyPath)) {
throw new Error(
'tasks.json not found in .taskmaster/tasks/ or tasks/ directory'
console.log('🔍 Looking for tasks.json at:', tasksJsonPath);
// Check if file exists
if (!fs.existsSync(tasksJsonPath)) {
// Try legacy location
const legacyPath = path.join(
workspaceFolder.uri.fsPath,
'tasks',
'tasks.json'
);
console.log('🔍 Trying legacy path:', legacyPath);
if (!fs.existsSync(legacyPath)) {
throw new Error(
'tasks.json not found in .taskmaster/tasks/ or tasks/ directory'
);
}
// Use legacy path
const content = fs.readFileSync(legacyPath, 'utf8');
console.log(
'📖 Read legacy tasks.json, content length:',
content.length
);
const taskData = parseTaskFileData(
content,
taskId,
tagName,
workspaceFolder.uri.fsPath
);
console.log('✅ Parsed task data for legacy path:', taskData);
panel.webview.postMessage({
type: 'response',
requestId,
data: taskData
});
return;
}
// Use legacy path
const content = fs.readFileSync(legacyPath, 'utf8');
// Read and parse tasks.json
const content = fs.readFileSync(tasksJsonPath, 'utf8');
console.log(
'📖 Read legacy tasks.json, content length:',
'📖 Read tasks.json, content length:',
content.length
);
const taskData = parseTaskFileData(
@@ -1076,46 +1099,26 @@ export function activate(context: vscode.ExtensionContext) {
tagName,
workspaceFolder.uri.fsPath
);
console.log('✅ Parsed task data for legacy path:', taskData);
console.log('✅ Parsed task data:', taskData);
panel.webview.postMessage({
type: 'response',
requestId,
data: taskData
});
return;
console.log(`✅ Retrieved task file data for task ${taskId}`);
} catch (error) {
console.error('❌ Error reading task file data:', error);
panel.webview.postMessage({
type: 'error',
requestId,
error:
error instanceof Error
? error.message
: 'Failed to read task file data'
});
}
// Read and parse tasks.json
const content = fs.readFileSync(tasksJsonPath, 'utf8');
console.log(
'📖 Read tasks.json, content length:',
content.length
);
const taskData = parseTaskFileData(
content,
taskId,
tagName,
workspaceFolder.uri.fsPath
);
console.log('✅ Parsed task data:', taskData);
panel.webview.postMessage({
type: 'response',
requestId,
data: taskData
});
console.log(`✅ Retrieved task file data for task ${taskId}`);
} catch (error) {
console.error('❌ Error reading task file data:', error);
panel.webview.postMessage({
type: 'error',
requestId,
error:
error instanceof Error
? error.message
: 'Failed to read task file data'
});
}
break;

View File

@@ -648,14 +648,14 @@ const TaskEditModal: React.FC<{
// Only include changed fields
const updates: TaskUpdates = {};
if (formData.title !== task.title) updates.title = formData.title;
if (formData.title !== task.title) {updates.title = formData.title;}
if (formData.description !== task.description)
updates.description = formData.description;
if (formData.details !== task.details) updates.details = formData.details;
{updates.description = formData.description;}
if (formData.details !== task.details) {updates.details = formData.details;}
if (formData.priority !== task.priority)
updates.priority = formData.priority;
{updates.priority = formData.priority;}
if (formData.testStrategy !== task.testStrategy)
updates.testStrategy = formData.testStrategy;
{updates.testStrategy = formData.testStrategy;}
if (
JSON.stringify(formData.dependencies) !==
JSON.stringify(task.dependencies)
@@ -875,7 +875,7 @@ const TaskCard: React.FC<{
const TaskMasterKanban: React.FC = () => {
const context = useContext(VSCodeContext);
if (!context)
throw new Error('TaskMasterKanban must be used within VSCodeContext');
{throw new Error('TaskMasterKanban must be used within VSCodeContext');}
const { state, dispatch, sendMessage, availableHeight } = context;
const {
@@ -984,14 +984,14 @@ const TaskMasterKanban: React.FC = () => {
dispatch({ type: 'SET_USER_INTERACTING', payload: false });
}, 1000); // 1 second delay to ensure smooth completion
if (!over) return;
if (!over) {return;}
const taskId = active.id as string;
const newStatus = over.id as TaskMasterTask['status'];
// Find the task that was moved
const task = tasks.find((t) => t.id === taskId);
if (!task || task.status === newStatus) return;
if (!task || task.status === newStatus) {return;}
console.log(`🔄 Moving task ${taskId} from ${task.status} to ${newStatus}`);
@@ -1382,7 +1382,7 @@ const App: React.FC = () => {
// Handle messages from extension
useEffect(() => {
if (!vscode) return;
if (!vscode) {return;}
const handleMessage = (event: MessageEvent) => {
const message: WebviewMessage = event.data;
@@ -1526,13 +1526,13 @@ const App: React.FC = () => {
// Map error severity to toast type
let toastType: ToastNotification['type'] = 'error';
if (errorData.severity === 'low') toastType = 'info';
else if (errorData.severity === 'medium') toastType = 'warning';
if (errorData.severity === 'low') {toastType = 'info';}
else if (errorData.severity === 'medium') {toastType = 'warning';}
else if (
errorData.severity === 'high' ||
errorData.severity === 'critical'
)
toastType = 'error';
{toastType = 'error';}
// Create appropriate toast based on error category
const title =