feat: add universal logger instead of console.log.
- fixed esbuild issues - converted to npm instead of pnpm since root project is npm (might switch whole project to pnpm later)
This commit is contained in:
@@ -69,8 +69,8 @@ async function main() {
|
||||
bundle: true,
|
||||
format: 'cjs',
|
||||
minify: production,
|
||||
sourcemap: !production,
|
||||
sourcesContent: false,
|
||||
sourcemap: !production ? 'inline' : false,
|
||||
sourcesContent: !production,
|
||||
platform: 'node',
|
||||
outdir: 'dist',
|
||||
external: ['vscode'],
|
||||
@@ -90,8 +90,8 @@ async function main() {
|
||||
format: 'iife',
|
||||
globalName: 'App',
|
||||
minify: production,
|
||||
sourcemap: !production,
|
||||
sourcesContent: false,
|
||||
sourcemap: !production ? 'inline' : false,
|
||||
sourcesContent: !production,
|
||||
platform: 'browser',
|
||||
outdir: 'dist',
|
||||
logLevel: 'silent',
|
||||
@@ -99,6 +99,13 @@ async function main() {
|
||||
jsx: 'automatic',
|
||||
jsxImportSource: 'react',
|
||||
external: ['*.css'],
|
||||
// Bundle React with webview since it's not available in the runtime
|
||||
// This prevents the multiple React instances issue
|
||||
// Ensure React is resolved from the workspace root to avoid duplicates
|
||||
alias: {
|
||||
react: path.resolve(__dirname, '../../node_modules/react'),
|
||||
'react-dom': path.resolve(__dirname, '../../node_modules/react-dom')
|
||||
},
|
||||
define: {
|
||||
'process.env.NODE_ENV': production ? '"production"' : '"development"',
|
||||
global: 'globalThis'
|
||||
|
||||
@@ -9,12 +9,7 @@
|
||||
"engines": {
|
||||
"vscode": "^1.93.0"
|
||||
},
|
||||
"categories": [
|
||||
"AI",
|
||||
"Visualization",
|
||||
"Education",
|
||||
"Other"
|
||||
],
|
||||
"categories": ["AI", "Visualization", "Education", "Other"],
|
||||
"main": "./dist/extension.js",
|
||||
"contributes": {
|
||||
"commands": [
|
||||
@@ -48,11 +43,7 @@
|
||||
"items": {
|
||||
"type": "string"
|
||||
},
|
||||
"default": [
|
||||
"-y",
|
||||
"--package=task-master-ai",
|
||||
"task-master-ai"
|
||||
],
|
||||
"default": ["-y", "--package=task-master-ai", "task-master-ai"],
|
||||
"description": "An array of arguments to pass to the MCP server command."
|
||||
},
|
||||
"taskmaster.mcp.cwd": {
|
||||
@@ -112,11 +103,7 @@
|
||||
},
|
||||
"taskmaster.ui.theme": {
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"auto",
|
||||
"light",
|
||||
"dark"
|
||||
],
|
||||
"enum": ["auto", "light", "dark"],
|
||||
"default": "auto",
|
||||
"description": "UI theme preference"
|
||||
},
|
||||
@@ -177,12 +164,7 @@
|
||||
},
|
||||
"taskmaster.debug.logLevel": {
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"error",
|
||||
"warn",
|
||||
"info",
|
||||
"debug"
|
||||
],
|
||||
"enum": ["error", "warn", "info", "debug"],
|
||||
"default": "info",
|
||||
"description": "Logging level"
|
||||
},
|
||||
@@ -207,15 +189,15 @@
|
||||
}
|
||||
},
|
||||
"scripts": {
|
||||
"vscode:prepublish": false,
|
||||
"build": "pnpm run build:js && pnpm run build:css",
|
||||
"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",
|
||||
"package": "pnpm exec node ./package.mjs",
|
||||
"package": "npm exec node ./package.mjs",
|
||||
"package:direct": "node ./package.mjs",
|
||||
"debug:env": "node ./debug-env.mjs",
|
||||
"compile": "node ./esbuild.js",
|
||||
"watch": "pnpm run watch:js & pnpm run watch:css",
|
||||
"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",
|
||||
@@ -254,8 +236,6 @@
|
||||
"lucide-react": "^0.525.0",
|
||||
"npm-run-all": "^4.1.5",
|
||||
"postcss": "8.5.6",
|
||||
"react": "19.1.0",
|
||||
"react-dom": "19.1.0",
|
||||
"tailwind-merge": "^3.3.1",
|
||||
"tailwindcss": "4.1.11",
|
||||
"typescript": "^5.8.3"
|
||||
|
||||
@@ -54,26 +54,35 @@ try {
|
||||
|
||||
// 5. Sync versions and prepare the final package.json
|
||||
console.log('Syncing versions and preparing the final package.json...');
|
||||
|
||||
|
||||
// Read current versions
|
||||
const devPackagePath = path.resolve(__dirname, 'package.json');
|
||||
const publishPackagePath = path.resolve(__dirname, 'package.publish.json');
|
||||
|
||||
|
||||
const devPackage = JSON.parse(fs.readFileSync(devPackagePath, 'utf8'));
|
||||
const publishPackage = JSON.parse(fs.readFileSync(publishPackagePath, 'utf8'));
|
||||
|
||||
const publishPackage = JSON.parse(
|
||||
fs.readFileSync(publishPackagePath, 'utf8')
|
||||
);
|
||||
|
||||
// Check if versions are in sync
|
||||
if (devPackage.version !== publishPackage.version) {
|
||||
console.log(` - Version sync needed: ${publishPackage.version} → ${devPackage.version}`);
|
||||
console.log(
|
||||
` - Version sync needed: ${publishPackage.version} → ${devPackage.version}`
|
||||
);
|
||||
publishPackage.version = devPackage.version;
|
||||
|
||||
|
||||
// Update the source package.publish.json file
|
||||
fs.writeFileSync(publishPackagePath, JSON.stringify(publishPackage, null, '\t') + '\n');
|
||||
console.log(` - Updated package.publish.json version to ${devPackage.version}`);
|
||||
fs.writeFileSync(
|
||||
publishPackagePath,
|
||||
JSON.stringify(publishPackage, null, '\t') + '\n'
|
||||
);
|
||||
console.log(
|
||||
` - Updated package.publish.json version to ${devPackage.version}`
|
||||
);
|
||||
} else {
|
||||
console.log(` - Versions already in sync: ${devPackage.version}`);
|
||||
}
|
||||
|
||||
|
||||
// Copy the (now synced) package.publish.json as package.json
|
||||
fs.copySync(publishPackagePath, path.resolve(packageDir, 'package.json'));
|
||||
console.log(' - Copied package.publish.json as package.json');
|
||||
|
||||
@@ -8,12 +8,7 @@
|
||||
"engines": {
|
||||
"vscode": "^1.93.0"
|
||||
},
|
||||
"categories": [
|
||||
"AI",
|
||||
"Visualization",
|
||||
"Education",
|
||||
"Other"
|
||||
],
|
||||
"categories": ["AI", "Visualization", "Education", "Other"],
|
||||
"keywords": [
|
||||
"kanban",
|
||||
"kanban board",
|
||||
@@ -87,11 +82,7 @@
|
||||
"items": {
|
||||
"type": "string"
|
||||
},
|
||||
"default": [
|
||||
"-y",
|
||||
"--package=task-master-ai",
|
||||
"task-master-ai"
|
||||
],
|
||||
"default": ["-y", "--package=task-master-ai", "task-master-ai"],
|
||||
"description": "An array of arguments to pass to the MCP server command."
|
||||
},
|
||||
"taskmaster.mcp.cwd": {
|
||||
@@ -151,11 +142,7 @@
|
||||
},
|
||||
"taskmaster.ui.theme": {
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"auto",
|
||||
"light",
|
||||
"dark"
|
||||
],
|
||||
"enum": ["auto", "light", "dark"],
|
||||
"default": "auto",
|
||||
"description": "UI theme preference"
|
||||
},
|
||||
@@ -216,12 +203,7 @@
|
||||
},
|
||||
"taskmaster.debug.logLevel": {
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"error",
|
||||
"warn",
|
||||
"info",
|
||||
"debug"
|
||||
],
|
||||
"enum": ["error", "warn", "info", "debug"],
|
||||
"default": "info",
|
||||
"description": "Logging level"
|
||||
},
|
||||
|
||||
6366
apps/extension/pnpm-lock.yaml
generated
6366
apps/extension/pnpm-lock.yaml
generated
File diff suppressed because it is too large
Load Diff
@@ -261,8 +261,9 @@ export const TaskDetailsView: React.FC<TaskDetailsViewProps> = ({
|
||||
onNavigateToTask
|
||||
}) => {
|
||||
const context = useContext(VSCodeContext);
|
||||
if (!context)
|
||||
{throw new Error('TaskDetailsView must be used within VSCodeContext');}
|
||||
if (!context) {
|
||||
throw new Error('TaskDetailsView must be used within VSCodeContext');
|
||||
}
|
||||
|
||||
const { state, sendMessage } = context;
|
||||
const { tasks } = state;
|
||||
@@ -372,7 +373,9 @@ 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 +419,9 @@ 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 +548,9 @@ 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 +591,9 @@ export const TaskDetailsView: React.FC<TaskDetailsViewProps> = ({
|
||||
};
|
||||
|
||||
const handleAppend = async () => {
|
||||
if (!currentTask || !prompt.trim()) {return;}
|
||||
if (!currentTask || !prompt.trim()) {
|
||||
return;
|
||||
}
|
||||
|
||||
setIsAppending(true);
|
||||
try {
|
||||
@@ -626,7 +635,9 @@ 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 +683,9 @@ export const TaskDetailsView: React.FC<TaskDetailsViewProps> = ({
|
||||
|
||||
// Handle status change
|
||||
const handleStatusChange = async (newStatus: TaskMasterTask['status']) => {
|
||||
if (!currentTask) {return;}
|
||||
if (!currentTask) {
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
await sendMessage({
|
||||
|
||||
@@ -25,6 +25,7 @@ import {
|
||||
import { getToastDuration } from './utils/notificationPreferences';
|
||||
import { parseTaskFileData } from './utils/taskFileReader';
|
||||
import { TaskMasterTask } from './utils/taskMasterApi';
|
||||
import { logger } from './utils/logger';
|
||||
|
||||
// Global MCP client manager instance
|
||||
let mcpClient: MCPClientManager | null = null;
|
||||
@@ -82,8 +83,8 @@ let pollingState: PollingState = {
|
||||
// Initialize MCP components
|
||||
async function initializeMCPComponents(context: vscode.ExtensionContext) {
|
||||
try {
|
||||
console.log('🔄 Initializing MCP components...');
|
||||
console.log(
|
||||
logger.log('🔄 Initializing MCP components...');
|
||||
logger.log(
|
||||
'🔍 DEBUGGING: initializeMCPComponents started at',
|
||||
new Date().toISOString()
|
||||
);
|
||||
@@ -95,7 +96,7 @@ async function initializeMCPComponents(context: vscode.ExtensionContext) {
|
||||
const mcpConfig = createMCPConfigFromSettings();
|
||||
|
||||
// Initialize MCP client
|
||||
console.log(
|
||||
logger.log(
|
||||
'🔍 DEBUGGING: About to create MCPClientManager with config:',
|
||||
mcpConfig
|
||||
);
|
||||
@@ -110,14 +111,14 @@ async function initializeMCPComponents(context: vscode.ExtensionContext) {
|
||||
});
|
||||
|
||||
// Try to connect to MCP server
|
||||
console.log('🔗 Connecting to Task Master MCP server...');
|
||||
logger.log('🔗 Connecting to Task Master MCP server...');
|
||||
try {
|
||||
await mcpClient.connect();
|
||||
|
||||
// Test connection
|
||||
const connectionTest = await taskMasterApi.testConnection();
|
||||
if (connectionTest.success && connectionTest.data) {
|
||||
console.log('✅ Task Master MCP connection established');
|
||||
logger.log('✅ Task Master MCP connection established');
|
||||
vscode.window.showInformationMessage(
|
||||
'Task Master connected successfully!'
|
||||
);
|
||||
@@ -125,8 +126,8 @@ async function initializeMCPComponents(context: vscode.ExtensionContext) {
|
||||
throw new Error(connectionTest.error || 'Connection test failed');
|
||||
}
|
||||
} catch (connectionError) {
|
||||
console.error('❌ Task Master MCP connection failed:', connectionError);
|
||||
console.error('Connection error details:', {
|
||||
logger.error('❌ Task Master MCP connection failed:', connectionError);
|
||||
logger.error('Connection error details:', {
|
||||
message:
|
||||
connectionError instanceof Error
|
||||
? connectionError.message
|
||||
@@ -165,7 +166,7 @@ async function initializeMCPComponents(context: vscode.ExtensionContext) {
|
||||
|
||||
// Initialize in offline mode
|
||||
pollingState.isOfflineMode = true;
|
||||
console.log(
|
||||
logger.log(
|
||||
'📴 Starting in offline mode - some features will be unavailable'
|
||||
);
|
||||
}
|
||||
@@ -181,7 +182,7 @@ async function startPolling(): Promise<void> {
|
||||
return;
|
||||
}
|
||||
|
||||
console.log('🔄 Starting task polling with interval:', pollingState.interval);
|
||||
logger.log('🔄 Starting task polling with interval:', pollingState.interval);
|
||||
pollingState.isPolling = true;
|
||||
pollingState.errorCount = 0;
|
||||
|
||||
@@ -197,7 +198,7 @@ function stopPolling(): void {
|
||||
return;
|
||||
}
|
||||
|
||||
console.log('⏹️ Stopping task polling');
|
||||
logger.log('⏹️ Stopping task polling');
|
||||
pollingState.isPolling = false;
|
||||
|
||||
if (pollingState.timer) {
|
||||
@@ -212,7 +213,7 @@ async function pollForUpdates(): Promise<void> {
|
||||
}
|
||||
|
||||
try {
|
||||
console.log('📡 Polling for task updates...');
|
||||
logger.log('📡 Polling for task updates...');
|
||||
|
||||
const tasksResult = await taskMasterApi.getTasks({
|
||||
withSubtasks: true,
|
||||
@@ -223,7 +224,7 @@ async function pollForUpdates(): Promise<void> {
|
||||
const hasChanges = detectTaskChanges(tasksResult.data);
|
||||
|
||||
if (hasChanges) {
|
||||
console.log('📋 Task changes detected, notifying webviews');
|
||||
logger.log('📋 Task changes detected, notifying webviews');
|
||||
|
||||
// Track change for adaptive frequency
|
||||
pollingState.changeDetectionWindow.push(Date.now());
|
||||
@@ -242,7 +243,7 @@ async function pollForUpdates(): Promise<void> {
|
||||
});
|
||||
});
|
||||
} else {
|
||||
console.log('📋 No task changes detected');
|
||||
logger.log('📋 No task changes detected');
|
||||
pollingState.consecutiveNoChanges++;
|
||||
}
|
||||
|
||||
@@ -260,7 +261,7 @@ async function pollForUpdates(): Promise<void> {
|
||||
if (pollingState.isOfflineMode) {
|
||||
pollingState.isOfflineMode = false;
|
||||
notifyConnectionStatus('online', 'Connected');
|
||||
console.log('✅ Reconnected successfully from offline mode');
|
||||
logger.log('✅ Reconnected successfully from offline mode');
|
||||
}
|
||||
} else {
|
||||
throw new Error(tasksResult.error || 'Failed to fetch tasks');
|
||||
@@ -291,7 +292,7 @@ function detectTaskChanges(newTasks: any[]): boolean {
|
||||
);
|
||||
return newTasksStr !== oldTasksStr;
|
||||
} catch (error) {
|
||||
console.warn('⚠️ Error comparing tasks, assuming changed:', error);
|
||||
logger.warn('⚠️ Error comparing tasks, assuming changed:', error);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -343,11 +344,11 @@ function adjustPollingFrequency(): void {
|
||||
pollingState.minInterval,
|
||||
pollingState.baseInterval * 0.5
|
||||
);
|
||||
console.log('📈 High activity detected, increasing polling frequency');
|
||||
logger.log('📈 High activity detected, increasing polling frequency');
|
||||
} else if (changesPerMinute > 0.5) {
|
||||
// Moderate activity: use base interval
|
||||
newInterval = pollingState.baseInterval;
|
||||
console.log('📊 Moderate activity, using base polling interval');
|
||||
logger.log('📊 Moderate activity, using base polling interval');
|
||||
} else if (pollingState.consecutiveNoChanges > 3) {
|
||||
// Low activity: reduce polling frequency with exponential backoff
|
||||
const backoffMultiplier = Math.min(
|
||||
@@ -358,7 +359,7 @@ function adjustPollingFrequency(): void {
|
||||
pollingState.maxInterval,
|
||||
pollingState.baseInterval * backoffMultiplier
|
||||
);
|
||||
console.log(
|
||||
logger.log(
|
||||
`📉 Low activity detected (${pollingState.consecutiveNoChanges} no-change cycles), reducing polling frequency`
|
||||
);
|
||||
}
|
||||
@@ -368,7 +369,7 @@ function adjustPollingFrequency(): void {
|
||||
Math.abs(newInterval - pollingState.interval) > 500 &&
|
||||
pollingState.isPolling
|
||||
) {
|
||||
console.log(
|
||||
logger.log(
|
||||
`🔄 Adjusting polling interval from ${pollingState.interval}ms to ${newInterval}ms`
|
||||
);
|
||||
pollingState.interval = newInterval;
|
||||
@@ -388,7 +389,7 @@ function handleNetworkError(error: any): void {
|
||||
pollingState.errorCount++;
|
||||
pollingState.reconnectAttempts++;
|
||||
|
||||
console.error(
|
||||
logger.error(
|
||||
`❌ Network error (attempt ${pollingState.reconnectAttempts}/${pollingState.maxReconnectAttempts}):`,
|
||||
error
|
||||
);
|
||||
@@ -410,7 +411,7 @@ function handleNetworkError(error: any): void {
|
||||
const maxBackoffDelay = pollingState.maxInterval;
|
||||
const finalDelay = Math.min(backoffDelay, maxBackoffDelay);
|
||||
|
||||
console.log(
|
||||
logger.log(
|
||||
`🔄 Retrying connection in ${finalDelay}ms (attempt ${pollingState.reconnectAttempts})`
|
||||
);
|
||||
|
||||
@@ -432,7 +433,7 @@ function handleNetworkError(error: any): void {
|
||||
}
|
||||
|
||||
function enterOfflineMode(): void {
|
||||
console.warn('⚠️ Entering offline mode due to persistent connection failures');
|
||||
logger.warn('⚠️ Entering offline mode due to persistent connection failures');
|
||||
|
||||
pollingState.isOfflineMode = true;
|
||||
stopPolling();
|
||||
@@ -462,7 +463,7 @@ function attemptReconnection(): void {
|
||||
return;
|
||||
}
|
||||
|
||||
console.log('🔄 Attempting to reconnect from offline mode...');
|
||||
logger.log('🔄 Attempting to reconnect from offline mode...');
|
||||
|
||||
// Reset connection state
|
||||
pollingState.isOfflineMode = false;
|
||||
@@ -474,7 +475,7 @@ function attemptReconnection(): void {
|
||||
|
||||
// Try to restart polling
|
||||
startPolling().catch((error) => {
|
||||
console.error('Failed to reconnect:', error);
|
||||
logger.error('Failed to reconnect:', error);
|
||||
enterOfflineMode();
|
||||
});
|
||||
}
|
||||
@@ -509,7 +510,7 @@ async function handleExtensionError(
|
||||
...context
|
||||
});
|
||||
|
||||
console.error(`Extension Error [${operation}]:`, error);
|
||||
logger.error(`Extension Error [${operation}]:`, error);
|
||||
await errorHandler.handleError(
|
||||
error instanceof Error ? error : new Error(String(error)),
|
||||
context
|
||||
@@ -527,7 +528,7 @@ async function handleMCPError(
|
||||
context
|
||||
);
|
||||
|
||||
console.error(`MCP Error [${operation}]:`, error);
|
||||
logger.error(`MCP Error [${operation}]:`, error);
|
||||
await errorHandler.handleError(mcpError, context);
|
||||
}
|
||||
|
||||
@@ -542,7 +543,7 @@ async function handleTaskLoadingError(
|
||||
context
|
||||
);
|
||||
|
||||
console.error(`Task Loading Error [${operation}]:`, error);
|
||||
logger.error(`Task Loading Error [${operation}]:`, error);
|
||||
await errorHandler.handleError(taskError, context);
|
||||
}
|
||||
|
||||
@@ -557,7 +558,7 @@ async function handleNetworkConnectionError(
|
||||
context
|
||||
);
|
||||
|
||||
console.error(`Network Error [${operation}]:`, error);
|
||||
logger.error(`Network Error [${operation}]:`, error);
|
||||
await errorHandler.handleError(networkError, context);
|
||||
}
|
||||
|
||||
@@ -572,16 +573,16 @@ async function handleUIError(
|
||||
context
|
||||
);
|
||||
|
||||
console.error(`UI Error [${operation}]:`, error);
|
||||
logger.error(`UI Error [${operation}]:`, error);
|
||||
await errorHandler.handleError(uiError, context);
|
||||
}
|
||||
|
||||
// This method is called when your extension is activated
|
||||
// Your extension is activated the very first time the command is executed
|
||||
export function activate(context: vscode.ExtensionContext) {
|
||||
console.log('🎉 Task Master Kanban extension is now active!');
|
||||
console.log('🎉 Extension context:', context);
|
||||
console.log(
|
||||
logger.log('🎉 Task Master Kanban extension is now active!');
|
||||
logger.log('🎉 Extension context:', context);
|
||||
logger.log(
|
||||
'🔍 DEBUGGING: Extension activation started at',
|
||||
new Date().toISOString()
|
||||
);
|
||||
@@ -614,7 +615,7 @@ export function activate(context: vscode.ExtensionContext) {
|
||||
const showKanbanCommand = vscode.commands.registerCommand(
|
||||
'taskr.showKanbanBoard',
|
||||
async () => {
|
||||
console.log('🎯 Show Kanban command executed!');
|
||||
logger.log('🎯 Show Kanban command executed!');
|
||||
|
||||
// Check if panel already exists
|
||||
const existingPanel = activeWebviewPanels.find(
|
||||
@@ -668,11 +669,11 @@ export function activate(context: vscode.ExtensionContext) {
|
||||
|
||||
// Handle messages from webview
|
||||
panel.webview.onDidReceiveMessage(async (message) => {
|
||||
console.log('📨 Received message from webview:', message);
|
||||
logger.log('📨 Received message from webview:', message);
|
||||
|
||||
switch (message.type) {
|
||||
case 'ready':
|
||||
console.log('🚀 Webview is ready!');
|
||||
logger.log('🚀 Webview is ready!');
|
||||
// Send initial configuration or data
|
||||
panel.webview.postMessage({
|
||||
type: 'init',
|
||||
@@ -681,7 +682,7 @@ export function activate(context: vscode.ExtensionContext) {
|
||||
break;
|
||||
|
||||
case 'getTasks':
|
||||
console.log('📋 Getting tasks...');
|
||||
logger.log('📋 Getting tasks...');
|
||||
try {
|
||||
if (!taskMasterApi) {
|
||||
throw new Error(
|
||||
@@ -707,14 +708,14 @@ export function activate(context: vscode.ExtensionContext) {
|
||||
requestId: message.requestId,
|
||||
data: tasksResult.data
|
||||
});
|
||||
console.log(
|
||||
logger.log(
|
||||
`✅ Retrieved ${tasksResult.data?.length || 0} tasks from Task Master`
|
||||
);
|
||||
} else {
|
||||
throw new Error(tasksResult.error || 'Failed to get tasks');
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('❌ Error getting tasks:', error);
|
||||
logger.error('❌ Error getting tasks:', error);
|
||||
|
||||
// Send error to webview instead of falling back to sample data
|
||||
panel.webview.postMessage({
|
||||
@@ -735,7 +736,7 @@ export function activate(context: vscode.ExtensionContext) {
|
||||
break;
|
||||
|
||||
case 'updateTaskStatus':
|
||||
console.log('🔄 Updating task status:', message.data);
|
||||
logger.log('🔄 Updating task status:', message.data);
|
||||
try {
|
||||
if (
|
||||
taskMasterApi &&
|
||||
@@ -761,7 +762,7 @@ export function activate(context: vscode.ExtensionContext) {
|
||||
newStatus: message.data.newStatus
|
||||
}
|
||||
});
|
||||
console.log(
|
||||
logger.log(
|
||||
`✅ Updated task ${message.data.taskId} status to ${message.data.newStatus}`
|
||||
);
|
||||
} else {
|
||||
@@ -775,7 +776,7 @@ export function activate(context: vscode.ExtensionContext) {
|
||||
);
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('❌ Error updating task status:', error);
|
||||
logger.error('❌ Error updating task status:', error);
|
||||
panel.webview.postMessage({
|
||||
type: 'error',
|
||||
requestId: message.requestId,
|
||||
@@ -788,7 +789,7 @@ export function activate(context: vscode.ExtensionContext) {
|
||||
break;
|
||||
|
||||
case 'updateTask':
|
||||
console.log('📝 Updating task content:', message.data);
|
||||
logger.log('📝 Updating task content:', message.data);
|
||||
try {
|
||||
if (
|
||||
taskMasterApi &&
|
||||
@@ -816,7 +817,7 @@ export function activate(context: vscode.ExtensionContext) {
|
||||
updates: message.data.updates
|
||||
}
|
||||
});
|
||||
console.log(`✅ Updated task ${message.data.taskId} content`);
|
||||
logger.log(`✅ Updated task ${message.data.taskId} content`);
|
||||
} else {
|
||||
throw new Error(
|
||||
updateResult.error || 'Failed to update task'
|
||||
@@ -828,7 +829,7 @@ export function activate(context: vscode.ExtensionContext) {
|
||||
);
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('❌ Error updating task:', error);
|
||||
logger.error('❌ Error updating task:', error);
|
||||
panel.webview.postMessage({
|
||||
type: 'error',
|
||||
requestId: message.requestId,
|
||||
@@ -841,7 +842,7 @@ export function activate(context: vscode.ExtensionContext) {
|
||||
break;
|
||||
|
||||
case 'updateSubtask':
|
||||
console.log('📝 Updating subtask content:', message.data);
|
||||
logger.log('📝 Updating subtask content:', message.data);
|
||||
try {
|
||||
if (
|
||||
taskMasterApi &&
|
||||
@@ -868,7 +869,7 @@ export function activate(context: vscode.ExtensionContext) {
|
||||
prompt: message.data.prompt
|
||||
}
|
||||
});
|
||||
console.log(
|
||||
logger.log(
|
||||
`✅ Updated subtask ${message.data.taskId} content`
|
||||
);
|
||||
} else {
|
||||
@@ -882,7 +883,7 @@ export function activate(context: vscode.ExtensionContext) {
|
||||
);
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('❌ Error updating subtask:', error);
|
||||
logger.error('❌ Error updating subtask:', error);
|
||||
panel.webview.postMessage({
|
||||
type: 'error',
|
||||
requestId: message.requestId,
|
||||
@@ -895,7 +896,7 @@ export function activate(context: vscode.ExtensionContext) {
|
||||
break;
|
||||
|
||||
case 'addSubtask':
|
||||
console.log('➕ Adding new subtask:', message.data);
|
||||
logger.log('➕ Adding new subtask:', message.data);
|
||||
try {
|
||||
if (
|
||||
taskMasterApi &&
|
||||
@@ -921,7 +922,7 @@ export function activate(context: vscode.ExtensionContext) {
|
||||
subtaskData: message.data.subtaskData
|
||||
}
|
||||
});
|
||||
console.log(
|
||||
logger.log(
|
||||
`✅ Added subtask to task ${message.data.parentTaskId}`
|
||||
);
|
||||
} else {
|
||||
@@ -933,7 +934,7 @@ export function activate(context: vscode.ExtensionContext) {
|
||||
);
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('❌ Error adding subtask:', error);
|
||||
logger.error('❌ Error adding subtask:', error);
|
||||
panel.webview.postMessage({
|
||||
type: 'error',
|
||||
requestId: message.requestId,
|
||||
@@ -946,7 +947,7 @@ export function activate(context: vscode.ExtensionContext) {
|
||||
break;
|
||||
|
||||
case 'startPolling':
|
||||
console.log('🔄 Manual start polling requested');
|
||||
logger.log('🔄 Manual start polling requested');
|
||||
await startPolling();
|
||||
panel.webview.postMessage({
|
||||
type: 'pollingStarted',
|
||||
@@ -956,7 +957,7 @@ export function activate(context: vscode.ExtensionContext) {
|
||||
break;
|
||||
|
||||
case 'stopPolling':
|
||||
console.log('⏹️ Manual stop polling requested');
|
||||
logger.log('⏹️ Manual stop polling requested');
|
||||
stopPolling();
|
||||
panel.webview.postMessage({
|
||||
type: 'pollingStopped',
|
||||
@@ -966,7 +967,7 @@ export function activate(context: vscode.ExtensionContext) {
|
||||
break;
|
||||
|
||||
case 'getPollingStatus':
|
||||
console.log('📊 Polling status requested');
|
||||
logger.log('📊 Polling status requested');
|
||||
panel.webview.postMessage({
|
||||
type: 'pollingStatus',
|
||||
requestId: message.requestId,
|
||||
@@ -980,7 +981,7 @@ export function activate(context: vscode.ExtensionContext) {
|
||||
break;
|
||||
|
||||
case 'attemptReconnection':
|
||||
console.log('🔄 Manual reconnection requested');
|
||||
logger.log('🔄 Manual reconnection requested');
|
||||
if (pollingState.isOfflineMode) {
|
||||
attemptReconnection();
|
||||
panel.webview.postMessage({
|
||||
@@ -999,7 +1000,7 @@ export function activate(context: vscode.ExtensionContext) {
|
||||
break;
|
||||
|
||||
case 'getNetworkStatus':
|
||||
console.log('📊 Network status requested');
|
||||
logger.log('📊 Network status requested');
|
||||
panel.webview.postMessage({
|
||||
type: 'networkStatus',
|
||||
requestId: message.requestId,
|
||||
@@ -1014,7 +1015,7 @@ export function activate(context: vscode.ExtensionContext) {
|
||||
break;
|
||||
|
||||
case 'reactError':
|
||||
console.log('🔥 React error reported from webview:', message.data);
|
||||
logger.log('🔥 React error reported from webview:', message.data);
|
||||
try {
|
||||
await handleUIError(
|
||||
new Error(message.data.message),
|
||||
@@ -1026,12 +1027,12 @@ export function activate(context: vscode.ExtensionContext) {
|
||||
}
|
||||
);
|
||||
} catch (error) {
|
||||
console.error('Failed to handle React error:', error);
|
||||
logger.error('Failed to handle React error:', error);
|
||||
}
|
||||
break;
|
||||
|
||||
case 'readTaskFileData':
|
||||
console.log('📄 Reading task file data:', message.data);
|
||||
logger.log('📄 Reading task file data:', message.data);
|
||||
{
|
||||
const { requestId } = message;
|
||||
try {
|
||||
@@ -1050,7 +1051,7 @@ export function activate(context: vscode.ExtensionContext) {
|
||||
'tasks',
|
||||
'tasks.json'
|
||||
);
|
||||
console.log('🔍 Looking for tasks.json at:', tasksJsonPath);
|
||||
logger.log('🔍 Looking for tasks.json at:', tasksJsonPath);
|
||||
|
||||
// Check if file exists
|
||||
if (!fs.existsSync(tasksJsonPath)) {
|
||||
@@ -1060,7 +1061,7 @@ export function activate(context: vscode.ExtensionContext) {
|
||||
'tasks',
|
||||
'tasks.json'
|
||||
);
|
||||
console.log('🔍 Trying legacy path:', legacyPath);
|
||||
logger.log('🔍 Trying legacy path:', legacyPath);
|
||||
if (!fs.existsSync(legacyPath)) {
|
||||
throw new Error(
|
||||
'tasks.json not found in .taskmaster/tasks/ or tasks/ directory'
|
||||
@@ -1068,7 +1069,7 @@ export function activate(context: vscode.ExtensionContext) {
|
||||
}
|
||||
// Use legacy path
|
||||
const content = fs.readFileSync(legacyPath, 'utf8');
|
||||
console.log(
|
||||
logger.log(
|
||||
'📖 Read legacy tasks.json, content length:',
|
||||
content.length
|
||||
);
|
||||
@@ -1078,7 +1079,7 @@ export function activate(context: vscode.ExtensionContext) {
|
||||
tagName,
|
||||
workspaceFolder.uri.fsPath
|
||||
);
|
||||
console.log('✅ Parsed task data for legacy path:', taskData);
|
||||
logger.log('✅ Parsed task data for legacy path:', taskData);
|
||||
panel.webview.postMessage({
|
||||
type: 'response',
|
||||
requestId,
|
||||
@@ -1089,7 +1090,7 @@ export function activate(context: vscode.ExtensionContext) {
|
||||
|
||||
// Read and parse tasks.json
|
||||
const content = fs.readFileSync(tasksJsonPath, 'utf8');
|
||||
console.log(
|
||||
logger.log(
|
||||
'📖 Read tasks.json, content length:',
|
||||
content.length
|
||||
);
|
||||
@@ -1099,7 +1100,7 @@ export function activate(context: vscode.ExtensionContext) {
|
||||
tagName,
|
||||
workspaceFolder.uri.fsPath
|
||||
);
|
||||
console.log('✅ Parsed task data:', taskData);
|
||||
logger.log('✅ Parsed task data:', taskData);
|
||||
|
||||
panel.webview.postMessage({
|
||||
type: 'response',
|
||||
@@ -1107,9 +1108,9 @@ export function activate(context: vscode.ExtensionContext) {
|
||||
data: taskData
|
||||
});
|
||||
|
||||
console.log(`✅ Retrieved task file data for task ${taskId}`);
|
||||
logger.log(`✅ Retrieved task file data for task ${taskId}`);
|
||||
} catch (error) {
|
||||
console.error('❌ Error reading task file data:', error);
|
||||
logger.error('❌ Error reading task file data:', error);
|
||||
panel.webview.postMessage({
|
||||
type: 'error',
|
||||
requestId,
|
||||
@@ -1123,7 +1124,7 @@ export function activate(context: vscode.ExtensionContext) {
|
||||
break;
|
||||
|
||||
case 'mcpRequest':
|
||||
console.log('📊 MCP Request:', message);
|
||||
logger.log('📊 MCP Request:', message);
|
||||
const { requestId: mcpRequestId, tool, parameters } = message;
|
||||
try {
|
||||
if (!taskMasterApi) {
|
||||
@@ -1140,7 +1141,7 @@ export function activate(context: vscode.ExtensionContext) {
|
||||
|
||||
switch (tool) {
|
||||
case 'complexity_report':
|
||||
console.log('📊 Calling complexity_report MCP tool');
|
||||
logger.log('📊 Calling complexity_report MCP tool');
|
||||
try {
|
||||
// Use the private callMCPTool method via type assertion to access it
|
||||
const mcpResult = await (taskMasterApi as any).callMCPTool(
|
||||
@@ -1164,7 +1165,7 @@ export function activate(context: vscode.ExtensionContext) {
|
||||
break;
|
||||
|
||||
case 'analyze_project_complexity':
|
||||
console.log('🧮 Calling analyze_project_complexity MCP tool');
|
||||
logger.log('🧮 Calling analyze_project_complexity MCP tool');
|
||||
try {
|
||||
// Use the private callMCPTool method via type assertion to access it
|
||||
const mcpResult = await (taskMasterApi as any).callMCPTool(
|
||||
@@ -1197,14 +1198,14 @@ export function activate(context: vscode.ExtensionContext) {
|
||||
requestId: mcpRequestId,
|
||||
data: result.data
|
||||
});
|
||||
console.log(`✅ MCP tool ${tool} executed successfully`);
|
||||
logger.log(`✅ MCP tool ${tool} executed successfully`);
|
||||
} else {
|
||||
throw new Error(
|
||||
result.error || `Failed to execute MCP tool: ${tool}`
|
||||
);
|
||||
}
|
||||
} catch (error) {
|
||||
console.error(`❌ Error executing MCP tool ${tool}:`, error);
|
||||
logger.error(`❌ Error executing MCP tool ${tool}:`, error);
|
||||
panel.webview.postMessage({
|
||||
type: 'error',
|
||||
requestId: mcpRequestId,
|
||||
@@ -1217,7 +1218,7 @@ export function activate(context: vscode.ExtensionContext) {
|
||||
break;
|
||||
|
||||
default:
|
||||
console.log('❓ Unknown message type:', message.type);
|
||||
logger.log('❓ Unknown message type:', message.type);
|
||||
}
|
||||
});
|
||||
|
||||
@@ -1228,7 +1229,7 @@ export function activate(context: vscode.ExtensionContext) {
|
||||
const checkConnectionCommand = vscode.commands.registerCommand(
|
||||
'taskr.checkConnection',
|
||||
async () => {
|
||||
console.log('🔗 Check connection command executed!');
|
||||
logger.log('🔗 Check connection command executed!');
|
||||
vscode.window.showInformationMessage('Check connection command works!');
|
||||
}
|
||||
);
|
||||
@@ -1236,7 +1237,7 @@ export function activate(context: vscode.ExtensionContext) {
|
||||
const reconnectCommand = vscode.commands.registerCommand(
|
||||
'taskr.reconnect',
|
||||
async () => {
|
||||
console.log('🔄 Reconnect command executed!');
|
||||
logger.log('🔄 Reconnect command executed!');
|
||||
vscode.window.showInformationMessage('Reconnect command works!');
|
||||
}
|
||||
);
|
||||
@@ -1244,7 +1245,7 @@ export function activate(context: vscode.ExtensionContext) {
|
||||
const openSettingsCommand = vscode.commands.registerCommand(
|
||||
'taskr.openSettings',
|
||||
() => {
|
||||
console.log('⚙️ Open settings command executed!');
|
||||
logger.log('⚙️ Open settings command executed!');
|
||||
vscode.commands.executeCommand(
|
||||
'workbench.action.openSettings',
|
||||
'@ext:taskr taskmaster'
|
||||
@@ -1259,7 +1260,7 @@ export function activate(context: vscode.ExtensionContext) {
|
||||
openSettingsCommand
|
||||
);
|
||||
|
||||
console.log('✅ All commands registered successfully!');
|
||||
logger.log('✅ All commands registered successfully!');
|
||||
}
|
||||
|
||||
// Generate webview HTML content
|
||||
@@ -1393,7 +1394,7 @@ function getSampleTasks() {
|
||||
|
||||
// This method is called when your extension is deactivated
|
||||
export function deactivate() {
|
||||
console.log('👋 Task Master Kanban extension deactivated');
|
||||
logger.log('👋 Task Master Kanban extension deactivated');
|
||||
|
||||
// Stop polling
|
||||
stopPolling();
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import * as vscode from 'vscode';
|
||||
import { MCPConfig } from './mcpClient';
|
||||
import { logger } from './logger';
|
||||
|
||||
export interface TaskMasterConfig {
|
||||
mcp: MCPServerConfig;
|
||||
@@ -469,7 +470,7 @@ export class ConfigManager {
|
||||
private setupConfigWatcher(): void {
|
||||
vscode.workspace.onDidChangeConfiguration((event) => {
|
||||
if (event.affectsConfiguration('taskmaster')) {
|
||||
console.log('Task Master configuration changed, reloading...');
|
||||
logger.log('Task Master configuration changed, reloading...');
|
||||
this.config = this.loadConfig();
|
||||
this.notifyConfigChange();
|
||||
}
|
||||
@@ -499,7 +500,7 @@ export class ConfigManager {
|
||||
try {
|
||||
listener(this.config);
|
||||
} catch (error) {
|
||||
console.error('Error in configuration change listener:', error);
|
||||
logger.error('Error in configuration change listener:', error);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import * as vscode from 'vscode';
|
||||
import { MCPClientManager, MCPConfig, MCPServerStatus } from './mcpClient';
|
||||
import { logger } from './logger';
|
||||
|
||||
export interface ConnectionEvent {
|
||||
type: 'connected' | 'disconnected' | 'error' | 'reconnecting';
|
||||
@@ -82,7 +83,7 @@ export class ConnectionManager {
|
||||
|
||||
this.logEvent({ type: 'connected', timestamp: new Date() });
|
||||
|
||||
console.log('Connection manager: Successfully connected');
|
||||
logger.log('Connection manager: Successfully connected');
|
||||
} catch (error) {
|
||||
this.logEvent({
|
||||
type: 'error',
|
||||
@@ -216,11 +217,11 @@ export class ConnectionManager {
|
||||
|
||||
// Attempt reconnection if connection seems lost
|
||||
if (this.health.consecutiveFailures >= 3 && !this.isReconnecting) {
|
||||
console.log(
|
||||
logger.log(
|
||||
'Multiple consecutive failures detected, attempting reconnection...'
|
||||
);
|
||||
this.reconnectWithBackoff().catch((err) => {
|
||||
console.error('Reconnection failed:', err);
|
||||
logger.error('Reconnection failed:', err);
|
||||
});
|
||||
}
|
||||
|
||||
@@ -242,7 +243,7 @@ export class ConnectionManager {
|
||||
try {
|
||||
await this.connect();
|
||||
} catch (error) {
|
||||
console.error('Failed to connect with new configuration:', error);
|
||||
logger.error('Failed to connect with new configuration:', error);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -256,7 +257,7 @@ export class ConnectionManager {
|
||||
try {
|
||||
await this.testConnection();
|
||||
} catch (error) {
|
||||
console.error('Health check failed:', error);
|
||||
logger.error('Health check failed:', error);
|
||||
}
|
||||
}, 15000); // Check every 15 seconds
|
||||
}
|
||||
@@ -303,7 +304,7 @@ export class ConnectionManager {
|
||||
this.maxBackoffMs
|
||||
);
|
||||
|
||||
console.log(
|
||||
logger.log(
|
||||
`Attempting reconnection ${this.reconnectAttempts}/${this.maxReconnectAttempts} in ${backoffMs}ms...`
|
||||
);
|
||||
|
||||
@@ -312,7 +313,7 @@ export class ConnectionManager {
|
||||
try {
|
||||
await this.connect();
|
||||
} catch (error) {
|
||||
console.error(
|
||||
logger.error(
|
||||
`Reconnection attempt ${this.reconnectAttempts} failed:`,
|
||||
error
|
||||
);
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import * as vscode from 'vscode';
|
||||
import { logger } from './logger';
|
||||
import {
|
||||
shouldShowNotification,
|
||||
getNotificationType,
|
||||
@@ -322,7 +323,7 @@ export class ErrorHandler {
|
||||
await errorDetails.recovery.action();
|
||||
this.markErrorResolved(logEntry.id);
|
||||
} catch (recoveryError) {
|
||||
console.error('Error recovery failed:', recoveryError);
|
||||
logger.error('Error recovery failed:', recoveryError);
|
||||
logEntry.attempts++;
|
||||
logEntry.lastAttempt = new Date();
|
||||
}
|
||||
@@ -548,10 +549,10 @@ export class ErrorHandler {
|
||||
switch (errorDetails.severity) {
|
||||
case ErrorSeverity.CRITICAL:
|
||||
case ErrorSeverity.HIGH:
|
||||
console.error(logMessage, errorDetails);
|
||||
logger.error(logMessage, errorDetails);
|
||||
break;
|
||||
case ErrorSeverity.MEDIUM:
|
||||
console.warn(logMessage, errorDetails);
|
||||
logger.warn(logMessage, errorDetails);
|
||||
break;
|
||||
case ErrorSeverity.LOW:
|
||||
console.info(logMessage, errorDetails);
|
||||
@@ -634,7 +635,7 @@ ${errorDetails.context ? JSON.stringify(errorDetails.context, null, 2) : 'None'}
|
||||
try {
|
||||
listener(errorDetails);
|
||||
} catch (error) {
|
||||
console.error('Error in error listener:', error);
|
||||
logger.error('Error in error listener:', error);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
86
apps/extension/src/utils/logger.ts
Normal file
86
apps/extension/src/utils/logger.ts
Normal file
@@ -0,0 +1,86 @@
|
||||
import * as vscode from 'vscode';
|
||||
|
||||
/**
|
||||
* Logger that outputs to VS Code's output channel instead of console
|
||||
* This prevents interference with MCP stdio communication
|
||||
*/
|
||||
export class ExtensionLogger {
|
||||
private static instance: ExtensionLogger;
|
||||
private outputChannel: vscode.OutputChannel;
|
||||
private debugMode: boolean;
|
||||
|
||||
private constructor() {
|
||||
this.outputChannel = vscode.window.createOutputChannel('Task Master');
|
||||
const config = vscode.workspace.getConfiguration('taskmaster');
|
||||
this.debugMode = config.get<boolean>('debug.enableLogging', true);
|
||||
}
|
||||
|
||||
static getInstance(): ExtensionLogger {
|
||||
if (!ExtensionLogger.instance) {
|
||||
ExtensionLogger.instance = new ExtensionLogger();
|
||||
}
|
||||
return ExtensionLogger.instance;
|
||||
}
|
||||
|
||||
log(message: string, ...args: any[]): void {
|
||||
if (!this.debugMode) return;
|
||||
const timestamp = new Date().toISOString();
|
||||
const formattedMessage = this.formatMessage(message, args);
|
||||
this.outputChannel.appendLine(`[${timestamp}] ${formattedMessage}`);
|
||||
}
|
||||
|
||||
error(message: string, ...args: any[]): void {
|
||||
const timestamp = new Date().toISOString();
|
||||
const formattedMessage = this.formatMessage(message, args);
|
||||
this.outputChannel.appendLine(`[${timestamp}] ERROR: ${formattedMessage}`);
|
||||
}
|
||||
|
||||
warn(message: string, ...args: any[]): void {
|
||||
if (!this.debugMode) return;
|
||||
const timestamp = new Date().toISOString();
|
||||
const formattedMessage = this.formatMessage(message, args);
|
||||
this.outputChannel.appendLine(`[${timestamp}] WARN: ${formattedMessage}`);
|
||||
}
|
||||
|
||||
debug(message: string, ...args: any[]): void {
|
||||
if (!this.debugMode) return;
|
||||
const timestamp = new Date().toISOString();
|
||||
const formattedMessage = this.formatMessage(message, args);
|
||||
this.outputChannel.appendLine(`[${timestamp}] DEBUG: ${formattedMessage}`);
|
||||
}
|
||||
|
||||
private formatMessage(message: string, args: any[]): string {
|
||||
if (args.length === 0) {
|
||||
return message;
|
||||
}
|
||||
|
||||
// Convert objects to JSON for better readability
|
||||
const formattedArgs = args.map((arg) => {
|
||||
if (typeof arg === 'object' && arg !== null) {
|
||||
try {
|
||||
return JSON.stringify(arg, null, 2);
|
||||
} catch {
|
||||
return String(arg);
|
||||
}
|
||||
}
|
||||
return String(arg);
|
||||
});
|
||||
|
||||
return `${message} ${formattedArgs.join(' ')}`;
|
||||
}
|
||||
|
||||
show(): void {
|
||||
this.outputChannel.show();
|
||||
}
|
||||
|
||||
dispose(): void {
|
||||
this.outputChannel.dispose();
|
||||
}
|
||||
|
||||
setDebugMode(enabled: boolean): void {
|
||||
this.debugMode = enabled;
|
||||
}
|
||||
}
|
||||
|
||||
// Export a singleton instance for convenience
|
||||
export const logger = ExtensionLogger.getInstance();
|
||||
@@ -1,6 +1,7 @@
|
||||
import { StdioClientTransport } from '@modelcontextprotocol/sdk/client/stdio.js';
|
||||
import { Client } from '@modelcontextprotocol/sdk/client/index.js';
|
||||
import * as vscode from 'vscode';
|
||||
import { logger } from './logger';
|
||||
|
||||
export interface MCPConfig {
|
||||
command: string;
|
||||
@@ -23,7 +24,7 @@ export class MCPClientManager {
|
||||
private connectionPromise: Promise<void> | null = null;
|
||||
|
||||
constructor(config: MCPConfig) {
|
||||
console.log(
|
||||
logger.log(
|
||||
'🔍 DEBUGGING: MCPClientManager constructor called with config:',
|
||||
config
|
||||
);
|
||||
@@ -55,11 +56,11 @@ export class MCPClientManager {
|
||||
await this.disconnect();
|
||||
|
||||
// Create the transport - it will handle spawning the server process internally
|
||||
console.log(
|
||||
logger.log(
|
||||
`Starting MCP server: ${this.config.command} ${this.config.args?.join(' ') || ''}`
|
||||
);
|
||||
console.log('🔍 DEBUGGING: Transport config cwd:', this.config.cwd);
|
||||
console.log('🔍 DEBUGGING: Process cwd before spawn:', process.cwd());
|
||||
logger.log('🔍 DEBUGGING: Transport config cwd:', this.config.cwd);
|
||||
logger.log('🔍 DEBUGGING: Process cwd before spawn:', process.cwd());
|
||||
|
||||
// Test if the target directory and .taskmaster exist
|
||||
const fs = require('fs');
|
||||
@@ -69,19 +70,19 @@ export class MCPClientManager {
|
||||
const taskmasterDir = path.join(targetDir, '.taskmaster');
|
||||
const tasksFile = path.join(taskmasterDir, 'tasks', 'tasks.json');
|
||||
|
||||
console.log(
|
||||
logger.log(
|
||||
'🔍 DEBUGGING: Checking target directory:',
|
||||
targetDir,
|
||||
'exists:',
|
||||
fs.existsSync(targetDir)
|
||||
);
|
||||
console.log(
|
||||
logger.log(
|
||||
'🔍 DEBUGGING: Checking .taskmaster dir:',
|
||||
taskmasterDir,
|
||||
'exists:',
|
||||
fs.existsSync(taskmasterDir)
|
||||
);
|
||||
console.log(
|
||||
logger.log(
|
||||
'🔍 DEBUGGING: Checking tasks.json:',
|
||||
tasksFile,
|
||||
'exists:',
|
||||
@@ -90,10 +91,10 @@ export class MCPClientManager {
|
||||
|
||||
if (fs.existsSync(tasksFile)) {
|
||||
const stats = fs.statSync(tasksFile);
|
||||
console.log('🔍 DEBUGGING: tasks.json size:', stats.size, 'bytes');
|
||||
logger.log('🔍 DEBUGGING: tasks.json size:', stats.size, 'bytes');
|
||||
}
|
||||
} catch (error) {
|
||||
console.log('🔍 DEBUGGING: Error checking filesystem:', error);
|
||||
logger.log('🔍 DEBUGGING: Error checking filesystem:', error);
|
||||
}
|
||||
|
||||
this.transport = new StdioClientTransport({
|
||||
@@ -108,12 +109,12 @@ export class MCPClientManager {
|
||||
}
|
||||
});
|
||||
|
||||
console.log('🔍 DEBUGGING: Transport created, checking process...');
|
||||
logger.log('🔍 DEBUGGING: Transport created, checking process...');
|
||||
|
||||
// Set up transport event handlers
|
||||
this.transport.onerror = (error: Error) => {
|
||||
console.error('❌ MCP transport error:', error);
|
||||
console.error('Transport error details:', {
|
||||
logger.error('❌ MCP transport error:', error);
|
||||
logger.error('Transport error details:', {
|
||||
message: error.message,
|
||||
stack: error.stack,
|
||||
code: (error as any).code,
|
||||
@@ -127,7 +128,7 @@ export class MCPClientManager {
|
||||
};
|
||||
|
||||
this.transport.onclose = () => {
|
||||
console.log('🔌 MCP transport closed');
|
||||
logger.log('🔌 MCP transport closed');
|
||||
this.status = { isRunning: false };
|
||||
this.client = null;
|
||||
this.transport = null;
|
||||
@@ -135,7 +136,7 @@ export class MCPClientManager {
|
||||
|
||||
// Add message handler like the working debug script
|
||||
this.transport.onmessage = (message: any) => {
|
||||
console.log('📤 MCP server message:', message);
|
||||
logger.log('📤 MCP server message:', message);
|
||||
};
|
||||
|
||||
// Create the client
|
||||
@@ -152,14 +153,14 @@ export class MCPClientManager {
|
||||
);
|
||||
|
||||
// Connect the client to the transport (this automatically starts the transport)
|
||||
console.log('🔄 Attempting MCP client connection...');
|
||||
console.log('MCP config:', {
|
||||
logger.log('🔄 Attempting MCP client connection...');
|
||||
logger.log('MCP config:', {
|
||||
command: this.config.command,
|
||||
args: this.config.args,
|
||||
cwd: this.config.cwd
|
||||
});
|
||||
console.log('Current working directory:', process.cwd());
|
||||
console.log(
|
||||
logger.log('Current working directory:', process.cwd());
|
||||
logger.log(
|
||||
'VS Code workspace folders:',
|
||||
vscode.workspace.workspaceFolders?.map((f) => f.uri.fsPath)
|
||||
);
|
||||
@@ -167,37 +168,37 @@ export class MCPClientManager {
|
||||
// Check if process was created before connecting
|
||||
if (this.transport && (this.transport as any).process) {
|
||||
const proc = (this.transport as any).process;
|
||||
console.log('📝 MCP server process PID:', proc.pid);
|
||||
console.log('📝 Process working directory will be:', this.config.cwd);
|
||||
logger.log('📝 MCP server process PID:', proc.pid);
|
||||
logger.log('📝 Process working directory will be:', this.config.cwd);
|
||||
|
||||
proc.on('exit', (code: number, signal: string) => {
|
||||
console.log(
|
||||
logger.log(
|
||||
`🔚 MCP server process exited with code ${code}, signal ${signal}`
|
||||
);
|
||||
if (code !== 0) {
|
||||
console.log('❌ Non-zero exit code indicates server failure');
|
||||
logger.log('❌ Non-zero exit code indicates server failure');
|
||||
}
|
||||
});
|
||||
|
||||
proc.on('error', (error: Error) => {
|
||||
console.log('❌ MCP server process error:', error);
|
||||
logger.log('❌ MCP server process error:', error);
|
||||
});
|
||||
|
||||
// Listen to stderr to see server-side errors
|
||||
if (proc.stderr) {
|
||||
proc.stderr.on('data', (data: Buffer) => {
|
||||
console.log('📥 MCP server stderr:', data.toString());
|
||||
logger.log('📥 MCP server stderr:', data.toString());
|
||||
});
|
||||
}
|
||||
|
||||
// Listen to stdout for server messages
|
||||
if (proc.stdout) {
|
||||
proc.stdout.on('data', (data: Buffer) => {
|
||||
console.log('📤 MCP server stdout:', data.toString());
|
||||
logger.log('📤 MCP server stdout:', data.toString());
|
||||
});
|
||||
}
|
||||
} else {
|
||||
console.log('⚠️ No process found in transport before connection');
|
||||
logger.log('⚠️ No process found in transport before connection');
|
||||
}
|
||||
|
||||
await this.client.connect(this.transport);
|
||||
@@ -208,12 +209,12 @@ export class MCPClientManager {
|
||||
pid: this.transport.pid || undefined
|
||||
};
|
||||
|
||||
console.log('MCP client connected successfully');
|
||||
logger.log('MCP client connected successfully');
|
||||
vscode.window.showInformationMessage(
|
||||
'Task Master connected successfully'
|
||||
);
|
||||
} catch (error) {
|
||||
console.error('Failed to connect to MCP server:', error);
|
||||
logger.error('Failed to connect to MCP server:', error);
|
||||
this.status = {
|
||||
isRunning: false,
|
||||
error: error instanceof Error ? error.message : 'Unknown error'
|
||||
@@ -232,13 +233,13 @@ export class MCPClientManager {
|
||||
* Disconnect from the MCP server and clean up resources
|
||||
*/
|
||||
async disconnect(): Promise<void> {
|
||||
console.log('Disconnecting from MCP server');
|
||||
logger.log('Disconnecting from MCP server');
|
||||
|
||||
if (this.client) {
|
||||
try {
|
||||
await this.client.close();
|
||||
} catch (error) {
|
||||
console.error('Error closing MCP client:', error);
|
||||
logger.error('Error closing MCP client:', error);
|
||||
}
|
||||
this.client = null;
|
||||
}
|
||||
@@ -247,7 +248,7 @@ export class MCPClientManager {
|
||||
try {
|
||||
await this.transport.close();
|
||||
} catch (error) {
|
||||
console.error('Error closing MCP transport:', error);
|
||||
logger.error('Error closing MCP transport:', error);
|
||||
}
|
||||
this.transport = null;
|
||||
}
|
||||
@@ -281,7 +282,7 @@ export class MCPClientManager {
|
||||
|
||||
return result;
|
||||
} catch (error) {
|
||||
console.error(`Error calling MCP tool "${toolName}":`, error);
|
||||
logger.error(`Error calling MCP tool "${toolName}":`, error);
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
@@ -297,13 +298,13 @@ export class MCPClientManager {
|
||||
}
|
||||
|
||||
const result = await this.client.listTools();
|
||||
console.log(
|
||||
logger.log(
|
||||
'Available MCP tools:',
|
||||
result.tools?.map((t) => t.name) || []
|
||||
);
|
||||
return true;
|
||||
} catch (error) {
|
||||
console.error('Connection test failed:', error);
|
||||
logger.error('Connection test failed:', error);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -328,7 +329,7 @@ export class MCPClientManager {
|
||||
* Create MCP configuration from VS Code settings
|
||||
*/
|
||||
export function createMCPConfigFromSettings(): MCPConfig {
|
||||
console.log(
|
||||
logger.log(
|
||||
'🔍 DEBUGGING: createMCPConfigFromSettings called at',
|
||||
new Date().toISOString()
|
||||
);
|
||||
@@ -347,7 +348,7 @@ export function createMCPConfigFromSettings(): MCPConfig {
|
||||
const cwd = config.get<string>('mcp.cwd', defaultCwd);
|
||||
const env = config.get<Record<string, string>>('mcp.env');
|
||||
|
||||
console.log('✅ Using workspace directory:', defaultCwd);
|
||||
logger.log('✅ Using workspace directory:', defaultCwd);
|
||||
|
||||
// If using default 'npx', try to find the full path on macOS/Linux
|
||||
if (command === 'npx') {
|
||||
@@ -363,7 +364,7 @@ export function createMCPConfigFromSettings(): MCPConfig {
|
||||
try {
|
||||
if (path === 'npx' || fs.existsSync(path)) {
|
||||
command = path;
|
||||
console.log(`✅ Using npx at: ${path}`);
|
||||
logger.log(`✅ Using npx at: ${path}`);
|
||||
break;
|
||||
}
|
||||
} catch (error) {
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import * as vscode from 'vscode';
|
||||
import { ErrorCategory, ErrorSeverity, NotificationType } from './errorHandler';
|
||||
import { logger } from './logger';
|
||||
|
||||
export interface NotificationPreferences {
|
||||
// Global notification toggles
|
||||
@@ -240,9 +241,7 @@ export class NotificationPreferencesManager {
|
||||
vscode.ConfigurationTarget.Global
|
||||
);
|
||||
|
||||
console.log(
|
||||
'Task Master Kanban notification preferences reset to defaults'
|
||||
);
|
||||
logger.log('Task Master Kanban notification preferences reset to defaults');
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import * as fs from 'fs';
|
||||
import * as path from 'path';
|
||||
import { logger } from './logger';
|
||||
|
||||
export interface TaskFileData {
|
||||
details?: string;
|
||||
@@ -85,7 +86,7 @@ export async function readTaskFileData(
|
||||
return { details: undefined, testStrategy: undefined };
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('Error reading task file data:', error);
|
||||
logger.error('Error reading task file data:', error);
|
||||
return { details: undefined, testStrategy: undefined };
|
||||
}
|
||||
}
|
||||
@@ -103,21 +104,21 @@ export function findTaskById(
|
||||
// Check if this is a subtask ID with dotted notation (e.g., "1.2")
|
||||
if (taskId.includes('.')) {
|
||||
const [parentId, subtaskId] = taskId.split('.');
|
||||
console.log('🔍 Looking for subtask:', { parentId, subtaskId, taskId });
|
||||
logger.log('🔍 Looking for subtask:', { parentId, subtaskId, taskId });
|
||||
|
||||
// Find the parent task first
|
||||
const parentTask = tasks.find((task) => String(task.id) === parentId);
|
||||
if (!parentTask || !parentTask.subtasks) {
|
||||
console.log('❌ Parent task not found or has no subtasks:', parentId);
|
||||
logger.log('❌ Parent task not found or has no subtasks:', parentId);
|
||||
return undefined;
|
||||
}
|
||||
|
||||
console.log(
|
||||
logger.log(
|
||||
'📋 Parent task found with',
|
||||
parentTask.subtasks.length,
|
||||
'subtasks'
|
||||
);
|
||||
console.log(
|
||||
logger.log(
|
||||
'🔍 Subtask IDs in parent:',
|
||||
parentTask.subtasks.map((st) => st.id)
|
||||
);
|
||||
@@ -127,9 +128,9 @@ export function findTaskById(
|
||||
(st) => String(st.id) === subtaskId
|
||||
);
|
||||
if (subtask) {
|
||||
console.log('✅ Subtask found:', subtask.id);
|
||||
logger.log('✅ Subtask found:', subtask.id);
|
||||
} else {
|
||||
console.log('❌ Subtask not found:', subtaskId);
|
||||
logger.log('❌ Subtask not found:', subtaskId);
|
||||
}
|
||||
return subtask;
|
||||
}
|
||||
@@ -159,7 +160,7 @@ export function parseTaskFileData(
|
||||
tagName: string,
|
||||
workspacePath?: string
|
||||
): TaskFileData {
|
||||
console.log('🔍 parseTaskFileData called with:', {
|
||||
logger.log('🔍 parseTaskFileData called with:', {
|
||||
taskId,
|
||||
tagName,
|
||||
contentLength: content.length
|
||||
@@ -167,17 +168,17 @@ export function parseTaskFileData(
|
||||
|
||||
try {
|
||||
const tasksJson: TasksJsonStructure = JSON.parse(content);
|
||||
console.log('📊 Available tags:', Object.keys(tasksJson));
|
||||
logger.log('📊 Available tags:', Object.keys(tasksJson));
|
||||
|
||||
// Get the tag data
|
||||
const tagData = tasksJson[tagName];
|
||||
if (!tagData || !tagData.tasks) {
|
||||
console.log('❌ Tag not found or no tasks in tag:', tagName);
|
||||
logger.log('❌ Tag not found or no tasks in tag:', tagName);
|
||||
return { details: undefined, testStrategy: undefined };
|
||||
}
|
||||
|
||||
console.log('📋 Tag found with', tagData.tasks.length, 'tasks');
|
||||
console.log(
|
||||
logger.log('📋 Tag found with', tagData.tasks.length, 'tasks');
|
||||
logger.log(
|
||||
'🔍 Available task IDs:',
|
||||
tagData.tasks.map((t) => t.id)
|
||||
);
|
||||
@@ -185,18 +186,18 @@ export function parseTaskFileData(
|
||||
// Find the task
|
||||
const task = findTaskById(tagData.tasks, taskId);
|
||||
if (!task) {
|
||||
console.log('❌ Task not found:', taskId);
|
||||
logger.log('❌ Task not found:', taskId);
|
||||
return { details: undefined, testStrategy: undefined };
|
||||
}
|
||||
|
||||
console.log('✅ Task found:', task.id);
|
||||
console.log(
|
||||
logger.log('✅ Task found:', task.id);
|
||||
logger.log(
|
||||
'📝 Task has details:',
|
||||
!!task.details,
|
||||
'length:',
|
||||
task.details?.length
|
||||
);
|
||||
console.log(
|
||||
logger.log(
|
||||
'🧪 Task has testStrategy:',
|
||||
!!task.testStrategy,
|
||||
'length:',
|
||||
@@ -208,7 +209,7 @@ export function parseTaskFileData(
|
||||
testStrategy: task.testStrategy
|
||||
};
|
||||
} catch (error) {
|
||||
console.error('❌ Error parsing tasks.json:', error);
|
||||
logger.error('❌ Error parsing tasks.json:', error);
|
||||
return { details: undefined, testStrategy: undefined };
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import * as vscode from 'vscode';
|
||||
import { MCPClientManager } from './mcpClient';
|
||||
import { logger } from './logger';
|
||||
|
||||
// Task Master MCP API response types
|
||||
export interface MCPTaskResponse {
|
||||
@@ -155,7 +156,7 @@ export class TaskMasterApi {
|
||||
this.initializeBackgroundRefresh();
|
||||
}
|
||||
|
||||
console.log('TaskMasterApi: Initialized with enhanced caching:', {
|
||||
logger.log('TaskMasterApi: Initialized with enhanced caching:', {
|
||||
cacheDuration: this.config.cacheDuration,
|
||||
maxSize: this.config.cache?.maxSize,
|
||||
backgroundRefresh: this.config.cache?.enableBackgroundRefresh,
|
||||
@@ -200,7 +201,7 @@ export class TaskMasterApi {
|
||||
mcpArgs.tag = options.tag;
|
||||
}
|
||||
|
||||
console.log('TaskMasterApi: Calling get_tasks with args:', mcpArgs);
|
||||
logger.log('TaskMasterApi: Calling get_tasks with args:', mcpArgs);
|
||||
|
||||
// Call the MCP tool
|
||||
const mcpResponse = await this.callMCPTool('get_tasks', mcpArgs);
|
||||
@@ -217,7 +218,7 @@ export class TaskMasterApi {
|
||||
requestDuration: Date.now() - startTime
|
||||
};
|
||||
} catch (error) {
|
||||
console.error('TaskMasterApi: Error getting tasks:', error);
|
||||
logger.error('TaskMasterApi: Error getting tasks:', error);
|
||||
|
||||
return {
|
||||
success: false,
|
||||
@@ -247,7 +248,7 @@ export class TaskMasterApi {
|
||||
projectRoot: options?.projectRoot || this.getWorkspaceRoot()
|
||||
};
|
||||
|
||||
console.log('TaskMasterApi: Calling set_task_status with args:', mcpArgs);
|
||||
logger.log('TaskMasterApi: Calling set_task_status with args:', mcpArgs);
|
||||
|
||||
await this.callMCPTool('set_task_status', mcpArgs);
|
||||
|
||||
@@ -260,7 +261,7 @@ export class TaskMasterApi {
|
||||
requestDuration: Date.now() - startTime
|
||||
};
|
||||
} catch (error) {
|
||||
console.error('TaskMasterApi: Error updating task status:', error);
|
||||
logger.error('TaskMasterApi: Error updating task status:', error);
|
||||
|
||||
return {
|
||||
success: false,
|
||||
@@ -331,7 +332,7 @@ export class TaskMasterApi {
|
||||
mcpArgs.research = options.research;
|
||||
}
|
||||
|
||||
console.log('TaskMasterApi: Calling update_task with args:', mcpArgs);
|
||||
logger.log('TaskMasterApi: Calling update_task with args:', mcpArgs);
|
||||
|
||||
await this.callMCPTool('update_task', mcpArgs);
|
||||
|
||||
@@ -344,7 +345,7 @@ export class TaskMasterApi {
|
||||
requestDuration: Date.now() - startTime
|
||||
};
|
||||
} catch (error) {
|
||||
console.error('TaskMasterApi: Error updating task:', error);
|
||||
logger.error('TaskMasterApi: Error updating task:', error);
|
||||
|
||||
return {
|
||||
success: false,
|
||||
@@ -380,7 +381,7 @@ export class TaskMasterApi {
|
||||
mcpArgs.research = options.research;
|
||||
}
|
||||
|
||||
console.log('TaskMasterApi: Calling update_subtask with args:', mcpArgs);
|
||||
logger.log('TaskMasterApi: Calling update_subtask with args:', mcpArgs);
|
||||
|
||||
await this.callMCPTool('update_subtask', mcpArgs);
|
||||
|
||||
@@ -393,7 +394,7 @@ export class TaskMasterApi {
|
||||
requestDuration: Date.now() - startTime
|
||||
};
|
||||
} catch (error) {
|
||||
console.error('TaskMasterApi: Error updating subtask:', error);
|
||||
logger.error('TaskMasterApi: Error updating subtask:', error);
|
||||
|
||||
return {
|
||||
success: false,
|
||||
@@ -439,7 +440,7 @@ export class TaskMasterApi {
|
||||
mcpArgs.status = subtaskData.status;
|
||||
}
|
||||
|
||||
console.log('TaskMasterApi: Calling add_subtask with args:', mcpArgs);
|
||||
logger.log('TaskMasterApi: Calling add_subtask with args:', mcpArgs);
|
||||
|
||||
await this.callMCPTool('add_subtask', mcpArgs);
|
||||
|
||||
@@ -452,7 +453,7 @@ export class TaskMasterApi {
|
||||
requestDuration: Date.now() - startTime
|
||||
};
|
||||
} catch (error) {
|
||||
console.error('TaskMasterApi: Error adding subtask:', error);
|
||||
logger.error('TaskMasterApi: Error adding subtask:', error);
|
||||
|
||||
return {
|
||||
success: false,
|
||||
@@ -489,7 +490,7 @@ export class TaskMasterApi {
|
||||
requestDuration: Date.now() - startTime
|
||||
};
|
||||
} catch (error) {
|
||||
console.error('TaskMasterApi: Connection test failed:', error);
|
||||
logger.error('TaskMasterApi: Connection test failed:', error);
|
||||
|
||||
return {
|
||||
success: false,
|
||||
@@ -529,7 +530,7 @@ export class TaskMasterApi {
|
||||
this.performBackgroundRefresh();
|
||||
}, interval);
|
||||
|
||||
console.log(
|
||||
logger.log(
|
||||
`TaskMasterApi: Background refresh initialized with ${interval}ms interval`
|
||||
);
|
||||
}
|
||||
@@ -542,7 +543,7 @@ export class TaskMasterApi {
|
||||
return;
|
||||
}
|
||||
|
||||
console.log('TaskMasterApi: Starting background cache refresh');
|
||||
logger.log('TaskMasterApi: Starting background cache refresh');
|
||||
const startTime = Date.now();
|
||||
|
||||
// Find frequently accessed entries that are close to expiration
|
||||
@@ -565,7 +566,7 @@ export class TaskMasterApi {
|
||||
const optionsMatch = key.match(/get_tasks_(.+)/);
|
||||
if (optionsMatch) {
|
||||
const options = JSON.parse(optionsMatch[1]);
|
||||
console.log(`TaskMasterApi: Background refreshing cache key: ${key}`);
|
||||
logger.log(`TaskMasterApi: Background refreshing cache key: ${key}`);
|
||||
|
||||
// Perform the refresh (this will update the cache)
|
||||
await this.getTasks(options);
|
||||
@@ -573,7 +574,7 @@ export class TaskMasterApi {
|
||||
this.cacheAnalytics.refreshes++;
|
||||
}
|
||||
} catch (error) {
|
||||
console.warn(
|
||||
logger.warn(
|
||||
`TaskMasterApi: Background refresh failed for key ${key}:`,
|
||||
error
|
||||
);
|
||||
@@ -581,7 +582,7 @@ export class TaskMasterApi {
|
||||
}
|
||||
|
||||
const duration = Date.now() - startTime;
|
||||
console.log(
|
||||
logger.log(
|
||||
`TaskMasterApi: Background refresh completed in ${duration}ms, refreshed ${refreshedCount} entries`
|
||||
);
|
||||
}
|
||||
@@ -633,7 +634,7 @@ export class TaskMasterApi {
|
||||
|
||||
if (evictedCount > 0) {
|
||||
this.cacheAnalytics.evictions += evictedCount;
|
||||
console.log(
|
||||
logger.log(
|
||||
`TaskMasterApi: Evicted ${evictedCount} cache entries matching pattern: ${pattern}`
|
||||
);
|
||||
}
|
||||
@@ -661,14 +662,14 @@ export class TaskMasterApi {
|
||||
}
|
||||
|
||||
const accessTime = Date.now() - startTime;
|
||||
console.log(
|
||||
logger.log(
|
||||
`TaskMasterApi: Cache hit for ${key} (${accessTime}ms, ${cached.accessCount} accesses)`
|
||||
);
|
||||
return cached.data;
|
||||
} else {
|
||||
// Remove expired entry
|
||||
this.cache.delete(key);
|
||||
console.log(`TaskMasterApi: Cache entry expired and removed: ${key}`);
|
||||
logger.log(`TaskMasterApi: Cache entry expired and removed: ${key}`);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -676,7 +677,7 @@ export class TaskMasterApi {
|
||||
this.cacheAnalytics.misses++;
|
||||
}
|
||||
|
||||
console.log(`TaskMasterApi: Cache miss for ${key}`);
|
||||
logger.log(`TaskMasterApi: Cache miss for ${key}`);
|
||||
return null;
|
||||
}
|
||||
|
||||
@@ -709,7 +710,7 @@ export class TaskMasterApi {
|
||||
}
|
||||
|
||||
this.cache.set(key, entry);
|
||||
console.log(
|
||||
logger.log(
|
||||
`TaskMasterApi: Cached data for ${key} (size: ${dataSize} bytes, TTL: ${entry.ttl || this.config.cacheDuration}ms)`
|
||||
);
|
||||
|
||||
@@ -733,7 +734,7 @@ export class TaskMasterApi {
|
||||
}
|
||||
|
||||
if (entries.length > 0) {
|
||||
console.log(`TaskMasterApi: Evicted ${entries.length} LRU cache entries`);
|
||||
logger.log(`TaskMasterApi: Evicted ${entries.length} LRU cache entries`);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -755,7 +756,7 @@ export class TaskMasterApi {
|
||||
// This is a simple implementation - in a more sophisticated system,
|
||||
// we might prefetch related tasks, subtasks, or dependency data
|
||||
if (key.includes('get_tasks') && Array.isArray(data)) {
|
||||
console.log(
|
||||
logger.log(
|
||||
`TaskMasterApi: Scheduled prefetch for ${data.length} tasks related to ${key}`
|
||||
);
|
||||
// Future enhancement: prefetch individual task details, related dependencies, etc.
|
||||
@@ -771,7 +772,7 @@ export class TaskMasterApi {
|
||||
this.backgroundRefreshTimer = undefined;
|
||||
}
|
||||
this.clearCache();
|
||||
console.log('TaskMasterApi: Destroyed and cleaned up resources');
|
||||
logger.log('TaskMasterApi: Destroyed and cleaned up resources');
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -786,7 +787,7 @@ export class TaskMasterApi {
|
||||
for (let attempt = 1; attempt <= this.config.retryAttempts; attempt++) {
|
||||
try {
|
||||
const rawResponse = await this.mcpClient.callTool(toolName, args);
|
||||
console.log(
|
||||
logger.log(
|
||||
`🔍 DEBUGGING: Raw MCP response for ${toolName}:`,
|
||||
JSON.stringify(rawResponse, null, 2)
|
||||
);
|
||||
@@ -802,30 +803,30 @@ export class TaskMasterApi {
|
||||
if (contentItem.type === 'text' && contentItem.text) {
|
||||
try {
|
||||
const parsedData = JSON.parse(contentItem.text);
|
||||
console.log(
|
||||
logger.log(
|
||||
`🔍 DEBUGGING: Parsed MCP data for ${toolName}:`,
|
||||
parsedData
|
||||
);
|
||||
return parsedData;
|
||||
} catch (parseError) {
|
||||
console.error(
|
||||
logger.error(
|
||||
`TaskMasterApi: Failed to parse MCP response text for ${toolName}:`,
|
||||
parseError
|
||||
);
|
||||
console.error(`TaskMasterApi: Raw text was:`, contentItem.text);
|
||||
logger.error(`TaskMasterApi: Raw text was:`, contentItem.text);
|
||||
return rawResponse; // Fall back to original response
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// If not in expected format, return as-is
|
||||
console.warn(
|
||||
logger.warn(
|
||||
`TaskMasterApi: Unexpected MCP response format for ${toolName}, returning raw response`
|
||||
);
|
||||
return rawResponse;
|
||||
} catch (error) {
|
||||
lastError = error instanceof Error ? error : new Error('Unknown error');
|
||||
console.warn(
|
||||
logger.warn(
|
||||
`TaskMasterApi: Attempt ${attempt}/${this.config.retryAttempts} failed for ${toolName}:`,
|
||||
lastError.message
|
||||
);
|
||||
@@ -856,7 +857,7 @@ export class TaskMasterApi {
|
||||
// Validate response structure
|
||||
const validationResult = this.validateMCPResponse(mcpResponse);
|
||||
if (!validationResult.isValid) {
|
||||
console.warn(
|
||||
logger.warn(
|
||||
'TaskMasterApi: MCP response validation failed:',
|
||||
validationResult.errors
|
||||
);
|
||||
@@ -864,7 +865,7 @@ export class TaskMasterApi {
|
||||
}
|
||||
|
||||
const tasks = mcpResponse.data.tasks || [];
|
||||
console.log(
|
||||
logger.log(
|
||||
`TaskMasterApi: Transforming ${tasks.length} tasks from MCP response`
|
||||
);
|
||||
|
||||
@@ -892,7 +893,7 @@ export class TaskMasterApi {
|
||||
error: errorMsg,
|
||||
task: tasks[i]
|
||||
});
|
||||
console.error(
|
||||
logger.error(
|
||||
`TaskMasterApi: Failed to transform task at index ${i}:`,
|
||||
errorMsg,
|
||||
tasks[i]
|
||||
@@ -902,7 +903,7 @@ export class TaskMasterApi {
|
||||
|
||||
// Log transformation summary
|
||||
const transformDuration = Date.now() - transformStartTime;
|
||||
console.log(
|
||||
logger.log(
|
||||
`TaskMasterApi: Transformation completed in ${transformDuration}ms`,
|
||||
{
|
||||
totalTasks: tasks.length,
|
||||
@@ -917,7 +918,7 @@ export class TaskMasterApi {
|
||||
|
||||
return transformedTasks;
|
||||
} catch (error) {
|
||||
console.error(
|
||||
logger.error(
|
||||
'TaskMasterApi: Critical error during response transformation:',
|
||||
error
|
||||
);
|
||||
@@ -972,7 +973,7 @@ export class TaskMasterApi {
|
||||
*/
|
||||
private transformSingleTask(task: any, index: number): TaskMasterTask | null {
|
||||
if (!task || typeof task !== 'object') {
|
||||
console.warn(
|
||||
logger.warn(
|
||||
`TaskMasterApi: Task at index ${index} is not a valid object:`,
|
||||
task
|
||||
);
|
||||
@@ -1045,7 +1046,7 @@ export class TaskMasterApi {
|
||||
dependencies.length > 0 ||
|
||||
complexityScore !== undefined
|
||||
) {
|
||||
console.log(
|
||||
logger.log(
|
||||
`TaskMasterApi: Successfully transformed complex task ${taskId}:`,
|
||||
{
|
||||
subtaskCount: subtasks.length,
|
||||
@@ -1059,7 +1060,7 @@ export class TaskMasterApi {
|
||||
|
||||
return transformedTask;
|
||||
} catch (error) {
|
||||
console.error(
|
||||
logger.error(
|
||||
`TaskMasterApi: Error transforming task at index ${index}:`,
|
||||
error,
|
||||
task
|
||||
@@ -1074,14 +1075,14 @@ export class TaskMasterApi {
|
||||
private validateAndNormalizeId(id: any, fallbackIndex: number): string {
|
||||
if (id === null || id === undefined) {
|
||||
const generatedId = `generated_${fallbackIndex}_${Date.now()}`;
|
||||
console.warn(`TaskMasterApi: Task missing ID, generated: ${generatedId}`);
|
||||
logger.warn(`TaskMasterApi: Task missing ID, generated: ${generatedId}`);
|
||||
return generatedId;
|
||||
}
|
||||
|
||||
const stringId = String(id).trim();
|
||||
if (stringId === '') {
|
||||
const generatedId = `empty_${fallbackIndex}_${Date.now()}`;
|
||||
console.warn(
|
||||
logger.warn(
|
||||
`TaskMasterApi: Task has empty ID, generated: ${generatedId}`
|
||||
);
|
||||
return generatedId;
|
||||
@@ -1103,7 +1104,7 @@ export class TaskMasterApi {
|
||||
}
|
||||
|
||||
if (typeof value !== 'string') {
|
||||
console.warn(
|
||||
logger.warn(
|
||||
`TaskMasterApi: ${fieldName} is not a string, converting:`,
|
||||
value
|
||||
);
|
||||
@@ -1127,7 +1128,7 @@ export class TaskMasterApi {
|
||||
}
|
||||
|
||||
if (!Array.isArray(dependencies)) {
|
||||
console.warn(
|
||||
logger.warn(
|
||||
`TaskMasterApi: Dependencies for task ${taskId} is not an array:`,
|
||||
dependencies
|
||||
);
|
||||
@@ -1138,7 +1139,7 @@ export class TaskMasterApi {
|
||||
for (let i = 0; i < dependencies.length; i++) {
|
||||
const dep = dependencies[i];
|
||||
if (dep === null || dep === undefined) {
|
||||
console.warn(
|
||||
logger.warn(
|
||||
`TaskMasterApi: Null dependency at index ${i} for task ${taskId}`
|
||||
);
|
||||
continue;
|
||||
@@ -1146,7 +1147,7 @@ export class TaskMasterApi {
|
||||
|
||||
const stringDep = String(dep).trim();
|
||||
if (stringDep === '') {
|
||||
console.warn(
|
||||
logger.warn(
|
||||
`TaskMasterApi: Empty dependency at index ${i} for task ${taskId}`
|
||||
);
|
||||
continue;
|
||||
@@ -1154,7 +1155,7 @@ export class TaskMasterApi {
|
||||
|
||||
// Check for self-dependency
|
||||
if (stringDep === taskId) {
|
||||
console.warn(
|
||||
logger.warn(
|
||||
`TaskMasterApi: Self-dependency detected for task ${taskId}, skipping`
|
||||
);
|
||||
continue;
|
||||
@@ -1185,7 +1186,7 @@ export class TaskMasterApi {
|
||||
}
|
||||
|
||||
if (!Array.isArray(subtasks)) {
|
||||
console.warn(
|
||||
logger.warn(
|
||||
`TaskMasterApi: Subtasks for task ${parentTaskId} is not an array:`,
|
||||
subtasks
|
||||
);
|
||||
@@ -1197,7 +1198,7 @@ export class TaskMasterApi {
|
||||
try {
|
||||
const subtask = subtasks[i];
|
||||
if (!subtask || typeof subtask !== 'object') {
|
||||
console.warn(
|
||||
logger.warn(
|
||||
`TaskMasterApi: Invalid subtask at index ${i} for task ${parentTaskId}:`,
|
||||
subtask
|
||||
);
|
||||
@@ -1233,7 +1234,7 @@ export class TaskMasterApi {
|
||||
|
||||
validSubtasks.push(transformedSubtask);
|
||||
} catch (error) {
|
||||
console.error(
|
||||
logger.error(
|
||||
`TaskMasterApi: Error transforming subtask at index ${i} for task ${parentTaskId}:`,
|
||||
error
|
||||
);
|
||||
@@ -1285,7 +1286,7 @@ export class TaskMasterApi {
|
||||
const result = statusMap[normalized] || 'pending';
|
||||
|
||||
if (original && original !== result) {
|
||||
console.log(
|
||||
logger.log(
|
||||
`TaskMasterApi: Normalized status '${original}' -> '${result}'`
|
||||
);
|
||||
}
|
||||
@@ -1330,7 +1331,7 @@ export class TaskMasterApi {
|
||||
}
|
||||
|
||||
if (original && original !== result) {
|
||||
console.log(
|
||||
logger.log(
|
||||
`TaskMasterApi: Normalized priority '${original}' -> '${result}'`
|
||||
);
|
||||
}
|
||||
|
||||
@@ -648,14 +648,21 @@ const TaskEditModal: React.FC<{
|
||||
|
||||
// Only include changed fields
|
||||
const updates: TaskUpdates = {};
|
||||
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;}
|
||||
if (formData.priority !== task.priority)
|
||||
{updates.priority = formData.priority;}
|
||||
if (formData.testStrategy !== task.testStrategy)
|
||||
{updates.testStrategy = formData.testStrategy;}
|
||||
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;
|
||||
}
|
||||
if (formData.priority !== task.priority) {
|
||||
updates.priority = formData.priority;
|
||||
}
|
||||
if (formData.testStrategy !== task.testStrategy) {
|
||||
updates.testStrategy = formData.testStrategy;
|
||||
}
|
||||
if (
|
||||
JSON.stringify(formData.dependencies) !==
|
||||
JSON.stringify(task.dependencies)
|
||||
@@ -874,8 +881,9 @@ const TaskCard: React.FC<{
|
||||
// Main Kanban Board Component
|
||||
const TaskMasterKanban: React.FC = () => {
|
||||
const context = useContext(VSCodeContext);
|
||||
if (!context)
|
||||
{throw new Error('TaskMasterKanban must be used within VSCodeContext');}
|
||||
if (!context) {
|
||||
throw new Error('TaskMasterKanban must be used within VSCodeContext');
|
||||
}
|
||||
|
||||
const { state, dispatch, sendMessage, availableHeight } = context;
|
||||
const {
|
||||
@@ -984,14 +992,18 @@ 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 +1394,9 @@ 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 +1540,16 @@ 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';}
|
||||
else if (
|
||||
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 =
|
||||
|
||||
7885
package-lock.json
generated
7885
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
@@ -9,10 +9,7 @@
|
||||
"task-master-mcp": "mcp-server/server.js",
|
||||
"task-master-ai": "mcp-server/server.js"
|
||||
},
|
||||
"workspaces": [
|
||||
"apps/*",
|
||||
"."
|
||||
],
|
||||
"workspaces": ["apps/*", "."],
|
||||
"scripts": {
|
||||
"test": "node --experimental-vm-modules node_modules/.bin/jest",
|
||||
"test:fails": "node --experimental-vm-modules node_modules/.bin/jest --onlyFailures",
|
||||
@@ -126,7 +123,8 @@
|
||||
"jest-environment-node": "^29.7.0",
|
||||
"mock-fs": "^5.5.0",
|
||||
"prettier": "^3.5.3",
|
||||
"react": "^18.3.1",
|
||||
"react": "^19.1.0",
|
||||
"react-dom": "^19.1.0",
|
||||
"supertest": "^7.1.0",
|
||||
"tsx": "^4.16.2"
|
||||
}
|
||||
|
||||
@@ -332,9 +332,9 @@
|
||||
"input": 1.0,
|
||||
"output": 3.0
|
||||
},
|
||||
"allowed_roles": ["main", "fallback"],
|
||||
"max_tokens": 16384,
|
||||
"supported": true
|
||||
"allowed_roles": ["main", "fallback"],
|
||||
"max_tokens": 16384,
|
||||
"supported": true
|
||||
},
|
||||
{
|
||||
"id": "llama-3.3-70b-versatile",
|
||||
|
||||
@@ -1,52 +1,47 @@
|
||||
#!/usr/bin/env node
|
||||
import assert from 'node:assert/strict'
|
||||
import { spawnSync } from 'node:child_process'
|
||||
import { readFileSync } from 'node:fs'
|
||||
import { join, dirname } from 'node:path'
|
||||
import { fileURLToPath } from 'node:url'
|
||||
import assert from 'node:assert/strict';
|
||||
import { spawnSync } from 'node:child_process';
|
||||
import { readFileSync } from 'node:fs';
|
||||
import { join, dirname } from 'node:path';
|
||||
import { fileURLToPath } from 'node:url';
|
||||
|
||||
const __filename = fileURLToPath(import.meta.url)
|
||||
const __dirname = dirname(__filename)
|
||||
const __filename = fileURLToPath(import.meta.url);
|
||||
const __dirname = dirname(__filename);
|
||||
|
||||
// Read the extension's publishing package.json for accurate version/name
|
||||
const extensionDir = join(__dirname, '..', 'apps', 'extension')
|
||||
const publishPkgPath = join(extensionDir, 'package.publish.json')
|
||||
const extensionDir = join(__dirname, '..', 'apps', 'extension');
|
||||
const publishPkgPath = join(extensionDir, 'package.publish.json');
|
||||
|
||||
let pkg
|
||||
let pkg;
|
||||
try {
|
||||
const pkgContent = readFileSync(publishPkgPath, 'utf8')
|
||||
pkg = JSON.parse(pkgContent)
|
||||
const pkgContent = readFileSync(publishPkgPath, 'utf8');
|
||||
pkg = JSON.parse(pkgContent);
|
||||
} catch (error) {
|
||||
console.error('Failed to read package.publish.json:', error.message)
|
||||
process.exit(1)
|
||||
console.error('Failed to read package.publish.json:', error.message);
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
// Ensure we have required fields
|
||||
assert(pkg.name, 'package.publish.json must have a name field')
|
||||
assert(pkg.version, 'package.publish.json must have a version field')
|
||||
assert(pkg.repository, 'package.publish.json must have a repository field')
|
||||
assert(pkg.name, 'package.publish.json must have a name field');
|
||||
assert(pkg.version, 'package.publish.json must have a version field');
|
||||
assert(pkg.repository, 'package.publish.json must have a repository field');
|
||||
|
||||
const tag = `${pkg.name}@${pkg.version}`
|
||||
const tag = `${pkg.name}@${pkg.version}`;
|
||||
|
||||
// Get repository URL - handle both string and object format
|
||||
const repoUrl = typeof pkg.repository === 'string'
|
||||
? pkg.repository
|
||||
: pkg.repository.url
|
||||
const repoUrl =
|
||||
typeof pkg.repository === 'string' ? pkg.repository : pkg.repository.url;
|
||||
|
||||
assert(repoUrl, 'Repository URL not found in package.publish.json')
|
||||
assert(repoUrl, 'Repository URL not found in package.publish.json');
|
||||
|
||||
const { status, stdout, error } = spawnSync('git', [
|
||||
'ls-remote',
|
||||
repoUrl,
|
||||
tag
|
||||
])
|
||||
const { status, stdout, error } = spawnSync('git', ['ls-remote', repoUrl, tag]);
|
||||
|
||||
assert.equal(status, 0, error)
|
||||
assert.equal(status, 0, error);
|
||||
|
||||
const exists = String(stdout).trim() !== ''
|
||||
const exists = String(stdout).trim() !== '';
|
||||
|
||||
if (!exists) {
|
||||
console.log(`\nNew extension tag: ${tag}`)
|
||||
console.log(`\nNew extension tag: ${tag}`);
|
||||
} else {
|
||||
console.log(`\nExtension tag already exists: ${tag}`)
|
||||
}
|
||||
console.log(`\nExtension tag already exists: ${tag}`);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user