Skip to main content
Glama

Spec Workflow MCP

vscode-api.ts9.14 kB
// VSCode API types and utilities for webview communication declare global { interface Window { acquireVsCodeApi?: () => VsCodeApi; } } interface VsCodeApi { postMessage(message: any): void; setState(state: any): void; getState(): any; } // Message types for communication between extension and webview export type ExtensionMessage = | { type: 'specs-updated'; data: SpecData[] } | { type: 'tasks-updated'; data: TaskProgressData } | { type: 'approvals-updated'; data: ApprovalData[] } | { type: 'steering-updated'; data: SteeringStatus } | { type: 'spec-documents-updated'; data: DocumentInfo[] } | { type: 'steering-documents-updated'; data: DocumentInfo[] } | { type: 'selected-spec-updated'; data: string } | { type: 'config-updated'; data: SoundNotificationConfig } | { type: 'sound-uris-updated'; data: { [key: string]: string } } | { type: 'navigate-to-approvals'; data: { specName: string; approvalId: string } } | { type: 'archived-specs-updated'; data: SpecData[] } | { type: 'approval-categories-updated'; data: { value: string; label: string; count: number }[] } | { type: 'language-preference-updated'; data: string } | { type: 'error'; message: string } | { type: 'notification'; message: string; level: 'info' | 'warning' | 'error' | 'success' }; export type WebviewMessage = | { type: 'get-specs' } | { type: 'get-tasks'; specName: string } | { type: 'get-approvals' } | { type: 'get-steering' } | { type: 'get-spec-documents'; specName: string } | { type: 'get-steering-documents' } | { type: 'open-document'; specName: string; docType: string } | { type: 'open-steering-document'; docType: string } | { type: 'update-task-status'; specName: string; taskId: string; status: TaskStatus } | { type: 'save-document'; specName: string; docType: string; content: string } | { type: 'approve-request'; id: string; response: string } | { type: 'reject-request'; id: string; response: string } | { type: 'request-revision-request'; id: string; response: string; annotations?: string; comments?: any[] } | { type: 'get-approval-content'; id: string } | { type: 'get-selected-spec' } | { type: 'set-selected-spec'; specName: string } | { type: 'get-config' } | { type: 'refresh-all' } | { type: 'get-archived-specs' } | { type: 'archive-spec'; specName: string } | { type: 'unarchive-spec'; specName: string } | { type: 'get-approval-categories' } | { type: 'get-language-preference' } | { type: 'set-language-preference'; language: string } | { type: 'open-external-url'; url: string }; export type TaskStatus = 'pending' | 'in-progress' | 'completed'; export interface SpecData { name: string; displayName: string; description?: string; createdAt: string; lastModified: string; isArchived?: boolean; phases: { requirements: PhaseStatus; design: PhaseStatus; tasks: PhaseStatus; implementation: PhaseStatus; }; taskProgress?: { total: number; completed: number; pending: number; }; } export interface PhaseStatus { exists: boolean; approved?: boolean; lastModified?: string; content?: string; } export interface TaskProgressData { specName: string; total: number; completed: number; progress: number; taskList: TaskInfo[]; inProgress?: string; } export interface PromptSection { key: string; value: string; } export interface TaskInfo { id: string; description: string; status: TaskStatus; completed: boolean; isHeader?: boolean; files?: string[]; implementationDetails?: string[]; requirements?: string[]; leverage?: string; purposes?: string[]; prompt?: string; promptStructured?: PromptSection[]; inProgress?: boolean; // For backward compatibility } export interface ApprovalComment { id: string; text: string; lineNumber?: number; timestamp: string; resolved?: boolean; } export interface ApprovalData { id: string; title: string; description?: string; filePath: string; // Path to the file to be reviewed type: 'document' | 'action'; status: 'pending' | 'approved' | 'rejected' | 'needs-revision'; createdAt: string; respondedAt?: string; response?: string; annotations?: string; comments?: ApprovalComment[]; revisionHistory?: { version: number; content: string; timestamp: string; reason?: string; }[]; metadata?: Record<string, any>; category: 'spec'; categoryName: string; // spec name } export interface SteeringStatus { exists: boolean; documents: { product: boolean; tech: boolean; structure: boolean; }; lastModified?: string; } export interface DocumentInfo { name: string; exists: boolean; path: string; lastModified?: string; } export interface SoundNotificationConfig { enabled: boolean; volume: number; approvalSound: boolean; taskCompletionSound: boolean; } class VsCodeApiService { private api: VsCodeApi | null = null; private messageListeners: Map<string, Set<(data: any) => void>> = new Map(); constructor() { // Get the VSCode API if (window.acquireVsCodeApi) { this.api = window.acquireVsCodeApi(); } // Listen for messages from the extension window.addEventListener('message', (event) => { const message = event.data as ExtensionMessage; this.notifyListeners(message.type, message); }); } // Send message to extension postMessage(message: WebviewMessage) { if (this.api) { this.api.postMessage(message); } else { console.warn('VSCode API not available, message not sent:', message); } } // Subscribe to messages from extension onMessage(type: string, callback: (data: any) => void) { if (!this.messageListeners.has(type)) { this.messageListeners.set(type, new Set()); } this.messageListeners.get(type)!.add(callback); // Return unsubscribe function return () => { this.messageListeners.get(type)?.delete(callback); }; } private notifyListeners(type: string, message: ExtensionMessage) { const listeners = this.messageListeners.get(type); if (listeners) { listeners.forEach(callback => callback(message)); } } // State management setState(state: any) { if (this.api) { this.api.setState(state); } } getState(): any { if (this.api) { return this.api.getState(); } return null; } // Convenience methods for common operations refreshAll() { this.postMessage({ type: 'refresh-all' }); } getSpecs() { this.postMessage({ type: 'get-specs' }); } getTasks(specName: string) { this.postMessage({ type: 'get-tasks', specName }); } updateTaskStatus(specName: string, taskId: string, status: TaskStatus) { this.postMessage({ type: 'update-task-status', specName, taskId, status }); } saveDocument(specName: string, docType: string, content: string) { this.postMessage({ type: 'save-document', specName, docType, content }); } getApprovals() { this.postMessage({ type: 'get-approvals' }); } getApprovalCategories() { this.postMessage({ type: 'get-approval-categories' }); } approveRequest(id: string, response: string) { this.postMessage({ type: 'approve-request', id, response }); } rejectRequest(id: string, response: string) { this.postMessage({ type: 'reject-request', id, response }); } requestRevisionRequest(id: string, response: string, annotations?: string, comments?: any[]) { this.postMessage({ type: 'request-revision-request', id, response, annotations, comments }); } getApprovalContent(id: string) { this.postMessage({ type: 'get-approval-content', id }); } getSteering() { this.postMessage({ type: 'get-steering' }); } getSpecDocuments(specName: string) { this.postMessage({ type: 'get-spec-documents', specName }); } getSteeringDocuments() { this.postMessage({ type: 'get-steering-documents' }); } openDocument(specName: string, docType: string) { this.postMessage({ type: 'open-document', specName, docType }); } openSteeringDocument(docType: string) { this.postMessage({ type: 'open-steering-document', docType }); } getSelectedSpec() { this.postMessage({ type: 'get-selected-spec' }); } setSelectedSpec(specName: string) { this.postMessage({ type: 'set-selected-spec', specName }); } getConfig() { this.postMessage({ type: 'get-config' }); } // Archive methods getArchivedSpecs() { this.postMessage({ type: 'get-archived-specs' }); } archiveSpec(specName: string) { this.postMessage({ type: 'archive-spec', specName }); } unarchiveSpec(specName: string) { this.postMessage({ type: 'unarchive-spec', specName }); } openExternalUrl(url: string) { this.postMessage({ type: 'open-external-url', url }); } getLanguagePreference() { this.postMessage({ type: 'get-language-preference' }); } setLanguagePreference(language: string) { this.postMessage({ type: 'set-language-preference', language }); } } // Export singleton instance export const vscodeApi = new VsCodeApiService();

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/Pimzino/spec-workflow-mcp'

If you have feedback or need assistance with the MCP directory API, please join our Discord server