feat(extension): complete VS Code extension with kanban board interface (#997)

---------
Co-authored-by: DavidMaliglowka <13022280+DavidMaliglowka@users.noreply.github.com>
Co-authored-by: Ralph Khreish <35776126+Crunchyman-ralph@users.noreply.github.com>
Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
This commit is contained in:
DavidMaliglowka
2025-08-01 07:04:22 -05:00
committed by GitHub
parent 60c03c548d
commit 64302dc191
101 changed files with 20608 additions and 181 deletions

View File

@@ -0,0 +1,104 @@
import * as vscode from 'vscode';
/**
* Logger interface for dependency injection
*/
export interface ILogger {
log(message: string, ...args: any[]): void;
error(message: string, ...args: any[]): void;
warn(message: string, ...args: any[]): void;
debug(message: string, ...args: any[]): void;
show(): void;
dispose(): void;
}
/**
* Logger that outputs to VS Code's output channel instead of console
* This prevents interference with MCP stdio communication
*/
export class ExtensionLogger implements ILogger {
private static instance: ExtensionLogger;
private outputChannel: vscode.OutputChannel;
private debugMode: boolean;
private constructor() {
this.outputChannel = vscode.window.createOutputChannel('TaskMaster');
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();