@codemcp/workflows 3.1.21
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.turbo/turbo-build.log +4 -0
- package/.vibe/conversation-state.sqlite +0 -0
- package/LICENSE +674 -0
- package/dist/index.d.ts +9 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +74 -0
- package/dist/index.js.map +1 -0
- package/dist/notification-service.d.ts +14 -0
- package/dist/notification-service.d.ts.map +1 -0
- package/dist/notification-service.js +18 -0
- package/dist/notification-service.js.map +1 -0
- package/dist/resource-handlers/conversation-state.d.ts +15 -0
- package/dist/resource-handlers/conversation-state.d.ts.map +1 -0
- package/dist/resource-handlers/conversation-state.js +40 -0
- package/dist/resource-handlers/conversation-state.js.map +1 -0
- package/dist/resource-handlers/development-plan.d.ts +14 -0
- package/dist/resource-handlers/development-plan.d.ts.map +1 -0
- package/dist/resource-handlers/development-plan.js +31 -0
- package/dist/resource-handlers/development-plan.js.map +1 -0
- package/dist/resource-handlers/index.d.ts +24 -0
- package/dist/resource-handlers/index.d.ts.map +1 -0
- package/dist/resource-handlers/index.js +62 -0
- package/dist/resource-handlers/index.js.map +1 -0
- package/dist/resource-handlers/system-prompt.d.ts +15 -0
- package/dist/resource-handlers/system-prompt.d.ts.map +1 -0
- package/dist/resource-handlers/system-prompt.js +40 -0
- package/dist/resource-handlers/system-prompt.js.map +1 -0
- package/dist/resource-handlers/workflow-resource.d.ts +15 -0
- package/dist/resource-handlers/workflow-resource.d.ts.map +1 -0
- package/dist/resource-handlers/workflow-resource.js +85 -0
- package/dist/resource-handlers/workflow-resource.js.map +1 -0
- package/dist/response-renderer.d.ts +30 -0
- package/dist/response-renderer.d.ts.map +1 -0
- package/dist/response-renderer.js +94 -0
- package/dist/response-renderer.js.map +1 -0
- package/dist/server-config.d.ts +34 -0
- package/dist/server-config.d.ts.map +1 -0
- package/dist/server-config.js +486 -0
- package/dist/server-config.js.map +1 -0
- package/dist/server-helpers.d.ts +62 -0
- package/dist/server-helpers.d.ts.map +1 -0
- package/dist/server-helpers.js +156 -0
- package/dist/server-helpers.js.map +1 -0
- package/dist/server-implementation.d.ts +74 -0
- package/dist/server-implementation.d.ts.map +1 -0
- package/dist/server-implementation.js +201 -0
- package/dist/server-implementation.js.map +1 -0
- package/dist/server.d.ts +6 -0
- package/dist/server.d.ts.map +1 -0
- package/dist/server.js +5 -0
- package/dist/server.js.map +1 -0
- package/dist/tool-handlers/base-tool-handler.d.ts +50 -0
- package/dist/tool-handlers/base-tool-handler.d.ts.map +1 -0
- package/dist/tool-handlers/base-tool-handler.js +74 -0
- package/dist/tool-handlers/base-tool-handler.js.map +1 -0
- package/dist/tool-handlers/conduct-review.d.ts +49 -0
- package/dist/tool-handlers/conduct-review.d.ts.map +1 -0
- package/dist/tool-handlers/conduct-review.js +105 -0
- package/dist/tool-handlers/conduct-review.js.map +1 -0
- package/dist/tool-handlers/get-tool-info.d.ts +76 -0
- package/dist/tool-handlers/get-tool-info.d.ts.map +1 -0
- package/dist/tool-handlers/get-tool-info.js +168 -0
- package/dist/tool-handlers/get-tool-info.js.map +1 -0
- package/dist/tool-handlers/index.d.ts +42 -0
- package/dist/tool-handlers/index.d.ts.map +1 -0
- package/dist/tool-handlers/index.js +74 -0
- package/dist/tool-handlers/index.js.map +1 -0
- package/dist/tool-handlers/install-workflow.d.ts +48 -0
- package/dist/tool-handlers/install-workflow.d.ts.map +1 -0
- package/dist/tool-handlers/install-workflow.js +131 -0
- package/dist/tool-handlers/install-workflow.js.map +1 -0
- package/dist/tool-handlers/list-workflows.d.ts +47 -0
- package/dist/tool-handlers/list-workflows.d.ts.map +1 -0
- package/dist/tool-handlers/list-workflows.js +58 -0
- package/dist/tool-handlers/list-workflows.js.map +1 -0
- package/dist/tool-handlers/no-idea.d.ts +41 -0
- package/dist/tool-handlers/no-idea.d.ts.map +1 -0
- package/dist/tool-handlers/no-idea.js +29 -0
- package/dist/tool-handlers/no-idea.js.map +1 -0
- package/dist/tool-handlers/proceed-to-phase.d.ts +39 -0
- package/dist/tool-handlers/proceed-to-phase.d.ts.map +1 -0
- package/dist/tool-handlers/proceed-to-phase.js +109 -0
- package/dist/tool-handlers/proceed-to-phase.js.map +1 -0
- package/dist/tool-handlers/reset-development.d.ts +31 -0
- package/dist/tool-handlers/reset-development.d.ts.map +1 -0
- package/dist/tool-handlers/reset-development.js +48 -0
- package/dist/tool-handlers/reset-development.js.map +1 -0
- package/dist/tool-handlers/resume-workflow.d.ts +88 -0
- package/dist/tool-handlers/resume-workflow.d.ts.map +1 -0
- package/dist/tool-handlers/resume-workflow.js +213 -0
- package/dist/tool-handlers/resume-workflow.js.map +1 -0
- package/dist/tool-handlers/setup-project-docs.d.ts +36 -0
- package/dist/tool-handlers/setup-project-docs.d.ts.map +1 -0
- package/dist/tool-handlers/setup-project-docs.js +136 -0
- package/dist/tool-handlers/setup-project-docs.js.map +1 -0
- package/dist/tool-handlers/start-development.d.ts +82 -0
- package/dist/tool-handlers/start-development.d.ts.map +1 -0
- package/dist/tool-handlers/start-development.js +448 -0
- package/dist/tool-handlers/start-development.js.map +1 -0
- package/dist/tool-handlers/whats-next.d.ts +42 -0
- package/dist/tool-handlers/whats-next.d.ts.map +1 -0
- package/dist/tool-handlers/whats-next.js +118 -0
- package/dist/tool-handlers/whats-next.js.map +1 -0
- package/dist/types.d.ts +114 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +5 -0
- package/dist/types.js.map +1 -0
- package/package.json +29 -0
- package/src/index.ts +93 -0
- package/src/notification-service.ts +23 -0
- package/src/resource-handlers/conversation-state.ts +55 -0
- package/src/resource-handlers/development-plan.ts +48 -0
- package/src/resource-handlers/index.ts +73 -0
- package/src/resource-handlers/system-prompt.ts +55 -0
- package/src/resource-handlers/workflow-resource.ts +126 -0
- package/src/response-renderer.ts +116 -0
- package/src/server-config.ts +744 -0
- package/src/server-helpers.ts +225 -0
- package/src/server-implementation.ts +277 -0
- package/src/server.ts +9 -0
- package/src/tool-handlers/base-tool-handler.ts +141 -0
- package/src/tool-handlers/conduct-review.ts +191 -0
- package/src/tool-handlers/get-tool-info.ts +274 -0
- package/src/tool-handlers/index.ts +117 -0
- package/src/tool-handlers/install-workflow.ts +185 -0
- package/src/tool-handlers/list-workflows.ts +94 -0
- package/src/tool-handlers/no-idea.ts +47 -0
- package/src/tool-handlers/proceed-to-phase.ts +205 -0
- package/src/tool-handlers/reset-development.ts +90 -0
- package/src/tool-handlers/resume-workflow.ts +380 -0
- package/src/tool-handlers/setup-project-docs.ts +226 -0
- package/src/tool-handlers/start-development.ts +685 -0
- package/src/tool-handlers/whats-next.ts +235 -0
- package/src/types.ts +130 -0
- package/test/e2e/core-functionality.test.ts +176 -0
- package/test/e2e/mcp-contract.test.ts +540 -0
- package/test/e2e/plan-management.test.ts +331 -0
- package/test/e2e/state-management.test.ts +392 -0
- package/test/e2e/workflow-integration.test.ts +506 -0
- package/test/unit/commit-behaviour-interface.test.ts +244 -0
- package/test/unit/conduct-review.test.ts +151 -0
- package/test/unit/reset-functionality.test.ts +72 -0
- package/test/unit/resume-workflow.test.ts +192 -0
- package/test/unit/server-tools.test.ts +311 -0
- package/test/unit/setup-project-docs-handler.test.ts +267 -0
- package/test/unit/start-development-artifact-detection.test.ts +387 -0
- package/test/unit/start-development-gitignore.test.ts +178 -0
- package/test/unit/system-prompt-resource.test.ts +101 -0
- package/test/unit/tool-handlers/no-idea.test.ts +40 -0
- package/test/utils/e2e-test-setup.ts +453 -0
- package/test/utils/run-server-in-dir.sh +27 -0
- package/test/utils/temp-files.ts +308 -0
- package/test/utils/test-access.ts +79 -0
- package/test/utils/test-helpers.ts +286 -0
- package/test/utils/test-setup.ts +78 -0
- package/tsconfig.build.json +9 -0
- package/tsconfig.build.tsbuildinfo +1 -0
- package/tsconfig.json +12 -0
- package/vitest.config.ts +17 -0
|
@@ -0,0 +1,225 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Server Helper Functions
|
|
3
|
+
*
|
|
4
|
+
* Common utility functions used across the server implementation.
|
|
5
|
+
* These are pure functions that don't depend on server state.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
import { homedir } from 'node:os';
|
|
9
|
+
import { createLogger } from '@codemcp/workflows-core';
|
|
10
|
+
import { HandlerResult } from './types.js';
|
|
11
|
+
|
|
12
|
+
const logger = createLogger('ServerHelpers');
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* Normalize and validate project path
|
|
16
|
+
* Ensures we have a valid project path, defaulting to home directory if needed
|
|
17
|
+
*/
|
|
18
|
+
export function normalizeProjectPath(projectPath?: string): string {
|
|
19
|
+
const path = projectPath || process.cwd();
|
|
20
|
+
|
|
21
|
+
if (path === '/' || path === '') {
|
|
22
|
+
const homePath = homedir();
|
|
23
|
+
logger.info('Invalid project path detected, using home directory', {
|
|
24
|
+
originalPath: path,
|
|
25
|
+
normalizedPath: homePath,
|
|
26
|
+
});
|
|
27
|
+
return homePath;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
return path;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
/**
|
|
34
|
+
* Create a standardized success result
|
|
35
|
+
*/
|
|
36
|
+
export function createSuccessResult<T>(
|
|
37
|
+
data: T,
|
|
38
|
+
metadata?: Record<string, unknown>
|
|
39
|
+
): HandlerResult<T> {
|
|
40
|
+
return {
|
|
41
|
+
success: true,
|
|
42
|
+
data,
|
|
43
|
+
metadata,
|
|
44
|
+
};
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
/**
|
|
48
|
+
* Create a standardized error result
|
|
49
|
+
*/
|
|
50
|
+
export function createErrorResult(
|
|
51
|
+
error: string | Error,
|
|
52
|
+
metadata?: Record<string, unknown>
|
|
53
|
+
): HandlerResult<never> {
|
|
54
|
+
const errorMessage = error instanceof Error ? error.message : error;
|
|
55
|
+
|
|
56
|
+
return {
|
|
57
|
+
success: false,
|
|
58
|
+
error: errorMessage,
|
|
59
|
+
metadata,
|
|
60
|
+
};
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
/**
|
|
64
|
+
* Safely execute an async operation and return a HandlerResult
|
|
65
|
+
* This provides consistent error handling across all handlers
|
|
66
|
+
*/
|
|
67
|
+
export async function safeExecute<T>(
|
|
68
|
+
operation: () => Promise<T>,
|
|
69
|
+
errorContext?: string
|
|
70
|
+
): Promise<HandlerResult<T>> {
|
|
71
|
+
try {
|
|
72
|
+
const result = await operation();
|
|
73
|
+
return createSuccessResult(result);
|
|
74
|
+
} catch (error) {
|
|
75
|
+
const errorMessage =
|
|
76
|
+
error instanceof Error ? error.message : 'Unknown error';
|
|
77
|
+
const contextualError = errorContext
|
|
78
|
+
? `${errorContext}: ${errorMessage}`
|
|
79
|
+
: errorMessage;
|
|
80
|
+
|
|
81
|
+
logger.error('Operation failed', error as Error, { errorContext });
|
|
82
|
+
return createErrorResult(contextualError);
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
/**
|
|
87
|
+
* Validate required arguments for tool handlers
|
|
88
|
+
* Throws an error if any required arguments are missing
|
|
89
|
+
*/
|
|
90
|
+
export function validateRequiredArgs(
|
|
91
|
+
args: unknown,
|
|
92
|
+
requiredFields: string[]
|
|
93
|
+
): void {
|
|
94
|
+
const missingFields = requiredFields.filter(
|
|
95
|
+
field =>
|
|
96
|
+
(args as Record<string, unknown>)[field] === undefined ||
|
|
97
|
+
(args as Record<string, unknown>)[field] === null
|
|
98
|
+
);
|
|
99
|
+
|
|
100
|
+
if (missingFields.length > 0) {
|
|
101
|
+
throw new Error(`Missing required arguments: ${missingFields.join(', ')}`);
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
/**
|
|
106
|
+
* Check if a conversation exists and provide helpful error if not
|
|
107
|
+
*/
|
|
108
|
+
export function createConversationNotFoundResult(
|
|
109
|
+
availableWorkflows: string[] = []
|
|
110
|
+
): HandlerResult<never> {
|
|
111
|
+
if (availableWorkflows.length === 0) {
|
|
112
|
+
return createErrorResult(
|
|
113
|
+
'No development conversation has been started for this project and no workflows are available. Please install a workflow first or adjust the VIBE_WORKFLOW_DOMAINS environment variable.',
|
|
114
|
+
{
|
|
115
|
+
suggestion:
|
|
116
|
+
'install_workflow({ source: "waterfall" }) or set VIBE_WORKFLOW_DOMAINS=code,architecture,office',
|
|
117
|
+
availableWorkflows: [],
|
|
118
|
+
}
|
|
119
|
+
);
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
const firstWorkflow = availableWorkflows[0];
|
|
123
|
+
return createErrorResult(
|
|
124
|
+
'No development conversation has been started for this project. Please use the start_development tool first to initialize development with a workflow.',
|
|
125
|
+
{
|
|
126
|
+
suggestion: `start_development({ workflow: "${firstWorkflow}" })`,
|
|
127
|
+
availableWorkflows,
|
|
128
|
+
}
|
|
129
|
+
);
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
/**
|
|
133
|
+
* Extract workflow names for enum generation
|
|
134
|
+
* Used by server configuration to build Zod schemas
|
|
135
|
+
*/
|
|
136
|
+
export function buildWorkflowEnum(
|
|
137
|
+
workflowNames: string[]
|
|
138
|
+
): [string, ...string[]] {
|
|
139
|
+
const allWorkflows = [...workflowNames, 'custom'];
|
|
140
|
+
|
|
141
|
+
// Ensure we have at least one element for TypeScript
|
|
142
|
+
if (allWorkflows.length === 0) {
|
|
143
|
+
return ['waterfall'];
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
return allWorkflows as [string, ...string[]];
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
/**
|
|
150
|
+
* Generate workflow description for tool schemas
|
|
151
|
+
*/
|
|
152
|
+
export function generateWorkflowDescription(
|
|
153
|
+
workflows: Array<{
|
|
154
|
+
name: string;
|
|
155
|
+
displayName: string;
|
|
156
|
+
description: string;
|
|
157
|
+
metadata?: {
|
|
158
|
+
complexity?: 'low' | 'medium' | 'high';
|
|
159
|
+
bestFor?: string[];
|
|
160
|
+
useCases?: string[];
|
|
161
|
+
examples?: string[];
|
|
162
|
+
};
|
|
163
|
+
}>
|
|
164
|
+
): string {
|
|
165
|
+
let description = 'Choose your development workflow:\n\n';
|
|
166
|
+
|
|
167
|
+
for (const workflow of workflows) {
|
|
168
|
+
description += `• **${workflow.name}**: ${workflow.displayName} - ${workflow.description}`;
|
|
169
|
+
|
|
170
|
+
// Add enhanced metadata if available
|
|
171
|
+
if (workflow.metadata) {
|
|
172
|
+
const meta = workflow.metadata;
|
|
173
|
+
|
|
174
|
+
// Add complexity
|
|
175
|
+
if (meta.complexity) {
|
|
176
|
+
description += `\n Complexity: ${meta.complexity}`;
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
// Add best for information
|
|
180
|
+
if (meta.bestFor && meta.bestFor.length > 0) {
|
|
181
|
+
description += `\n Best for: ${meta.bestFor.join(', ')}`;
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
// Add examples
|
|
185
|
+
if (meta.examples && meta.examples.length > 0) {
|
|
186
|
+
description += `\n Examples: ${meta.examples.slice(0, 2).join(', ')}`;
|
|
187
|
+
if (meta.examples.length > 2) {
|
|
188
|
+
description += `, and ${meta.examples.length - 2} more`;
|
|
189
|
+
}
|
|
190
|
+
}
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
description += '\n';
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
description +=
|
|
197
|
+
'• **custom**: Use custom workflow from .vibe/workflows in your project\n\n';
|
|
198
|
+
|
|
199
|
+
return description;
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
/**
|
|
203
|
+
* Log handler execution for debugging
|
|
204
|
+
*/
|
|
205
|
+
export function logHandlerExecution(handlerName: string, args: unknown): void {
|
|
206
|
+
logger.debug(`Executing ${handlerName} handler`, {
|
|
207
|
+
handlerName,
|
|
208
|
+
argsKeys: Object.keys(args || {}),
|
|
209
|
+
});
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
/**
|
|
213
|
+
* Log handler completion for debugging
|
|
214
|
+
*/
|
|
215
|
+
export function logHandlerCompletion(
|
|
216
|
+
handlerName: string,
|
|
217
|
+
result: HandlerResult<unknown>
|
|
218
|
+
): void {
|
|
219
|
+
logger.debug(`Completed ${handlerName} handler`, {
|
|
220
|
+
handlerName,
|
|
221
|
+
success: result.success,
|
|
222
|
+
hasData: !!result.data,
|
|
223
|
+
hasError: !!result.error,
|
|
224
|
+
});
|
|
225
|
+
}
|
|
@@ -0,0 +1,277 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Refactored Vibe Feature MCP Server
|
|
3
|
+
*
|
|
4
|
+
* Main server orchestrator that brings together all the modular components.
|
|
5
|
+
* This replaces the monolithic server.ts with a clean, modular architecture.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
import { setMcpServerForLogging, createLogger } from '@codemcp/workflows-core';
|
|
9
|
+
import { ServerConfig } from './types.js';
|
|
10
|
+
import {
|
|
11
|
+
initializeServerComponents,
|
|
12
|
+
registerMcpTools,
|
|
13
|
+
registerMcpResources,
|
|
14
|
+
ServerComponents,
|
|
15
|
+
} from './server-config.js';
|
|
16
|
+
import { createToolRegistry } from './tool-handlers/index.js';
|
|
17
|
+
import { createResourceRegistry } from './resource-handlers/index.js';
|
|
18
|
+
import { createResponseRenderer } from './response-renderer.js';
|
|
19
|
+
import type {
|
|
20
|
+
ProceedToPhaseArgs,
|
|
21
|
+
ProceedToPhaseResult,
|
|
22
|
+
StartDevelopmentArgs,
|
|
23
|
+
StartDevelopmentResult,
|
|
24
|
+
ResumeWorkflowArgs,
|
|
25
|
+
ResumeWorkflowResult,
|
|
26
|
+
ResetDevelopmentArgs,
|
|
27
|
+
ResetDevelopmentResult,
|
|
28
|
+
} from './tool-handlers/index.js';
|
|
29
|
+
|
|
30
|
+
const logger = createLogger('ResponsibleVibeMCPServer');
|
|
31
|
+
|
|
32
|
+
/**
|
|
33
|
+
* Factory function to create a server with real components
|
|
34
|
+
*/
|
|
35
|
+
export async function createResponsibleVibeMCPServer(
|
|
36
|
+
config: ServerConfig = {}
|
|
37
|
+
): Promise<ResponsibleVibeMCPServer> {
|
|
38
|
+
const components = await initializeServerComponents(config);
|
|
39
|
+
return new ResponsibleVibeMCPServer(config, components);
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
/**
|
|
43
|
+
* Main server class that orchestrates all components
|
|
44
|
+
* Can be used both as a standalone process and in-process for testing
|
|
45
|
+
*/
|
|
46
|
+
export class ResponsibleVibeMCPServer {
|
|
47
|
+
private components: ServerComponents | null = null;
|
|
48
|
+
|
|
49
|
+
constructor(
|
|
50
|
+
private config: ServerConfig,
|
|
51
|
+
private serverComponents: ServerComponents
|
|
52
|
+
) {
|
|
53
|
+
logger.debug('ResponsibleVibeMCPServer created', {
|
|
54
|
+
config: JSON.stringify(this.config),
|
|
55
|
+
});
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
/**
|
|
59
|
+
* Initialize the server and all its components
|
|
60
|
+
*/
|
|
61
|
+
async initialize(): Promise<void> {
|
|
62
|
+
logger.debug('Initializing ResponsibleVibeMCPServer');
|
|
63
|
+
|
|
64
|
+
try {
|
|
65
|
+
// Use injected components
|
|
66
|
+
this.components = this.serverComponents;
|
|
67
|
+
|
|
68
|
+
// Create registries and renderer
|
|
69
|
+
const toolRegistry = createToolRegistry();
|
|
70
|
+
const resourceRegistry = createResourceRegistry();
|
|
71
|
+
const responseRenderer = createResponseRenderer();
|
|
72
|
+
|
|
73
|
+
// Update components with registries and renderer
|
|
74
|
+
this.components.toolRegistry = toolRegistry;
|
|
75
|
+
this.components.resourceRegistry = resourceRegistry;
|
|
76
|
+
this.components.responseRenderer = responseRenderer;
|
|
77
|
+
|
|
78
|
+
// Register MCP server for logging notifications
|
|
79
|
+
setMcpServerForLogging(this.components.mcpServer);
|
|
80
|
+
|
|
81
|
+
// Register tools and resources with MCP server
|
|
82
|
+
await registerMcpTools(
|
|
83
|
+
this.components.mcpServer,
|
|
84
|
+
toolRegistry,
|
|
85
|
+
responseRenderer,
|
|
86
|
+
this.components.context
|
|
87
|
+
);
|
|
88
|
+
|
|
89
|
+
registerMcpResources(
|
|
90
|
+
this.components.mcpServer,
|
|
91
|
+
resourceRegistry,
|
|
92
|
+
responseRenderer,
|
|
93
|
+
this.components.context
|
|
94
|
+
);
|
|
95
|
+
} catch (error) {
|
|
96
|
+
logger.error(
|
|
97
|
+
'Failed to initialize ResponsibleVibeMCPServer',
|
|
98
|
+
error as Error
|
|
99
|
+
);
|
|
100
|
+
throw error;
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
/**
|
|
105
|
+
* Get the underlying MCP server instance
|
|
106
|
+
* This allows for both transport-based and direct testing
|
|
107
|
+
*/
|
|
108
|
+
public getMcpServer() {
|
|
109
|
+
if (!this.components) {
|
|
110
|
+
throw new Error('Server not initialized. Call initialize() first.');
|
|
111
|
+
}
|
|
112
|
+
return this.components.mcpServer;
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
/**
|
|
116
|
+
* Get project path
|
|
117
|
+
*/
|
|
118
|
+
public getProjectPath(): string {
|
|
119
|
+
if (!this.components) {
|
|
120
|
+
throw new Error('Server not initialized. Call initialize() first.');
|
|
121
|
+
}
|
|
122
|
+
return this.components.context.projectPath;
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
/**
|
|
126
|
+
* Get conversation manager (for testing)
|
|
127
|
+
*/
|
|
128
|
+
public getConversationManager() {
|
|
129
|
+
if (!this.components) {
|
|
130
|
+
throw new Error('Server not initialized. Call initialize() first.');
|
|
131
|
+
}
|
|
132
|
+
return this.components.context.conversationManager;
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
/**
|
|
136
|
+
* Get plan manager (for testing)
|
|
137
|
+
*/
|
|
138
|
+
public getPlanManager() {
|
|
139
|
+
if (!this.components) {
|
|
140
|
+
throw new Error('Server not initialized. Call initialize() first.');
|
|
141
|
+
}
|
|
142
|
+
return this.components.context.planManager;
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
/**
|
|
146
|
+
* Direct access to tool handlers for testing
|
|
147
|
+
*/
|
|
148
|
+
public async handleWhatsNext(args: unknown): Promise<unknown> {
|
|
149
|
+
if (!this.components) {
|
|
150
|
+
throw new Error('Server not initialized. Call initialize() first.');
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
const handler = this.components.toolRegistry.get('whats_next');
|
|
154
|
+
if (!handler) {
|
|
155
|
+
throw new Error('whats_next handler not found');
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
const result = await handler.handle(args, this.components.context);
|
|
159
|
+
if (!result.success) {
|
|
160
|
+
throw new Error(result.error || 'Handler execution failed');
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
return result.data;
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
/**
|
|
167
|
+
* Direct access to tool handlers for testing
|
|
168
|
+
*/
|
|
169
|
+
public async handleProceedToPhase(
|
|
170
|
+
args: ProceedToPhaseArgs
|
|
171
|
+
): Promise<ProceedToPhaseResult> {
|
|
172
|
+
if (!this.components) {
|
|
173
|
+
throw new Error('Server not initialized. Call initialize() first.');
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
const handler = this.components.toolRegistry.get('proceed_to_phase');
|
|
177
|
+
if (!handler) {
|
|
178
|
+
throw new Error('proceed_to_phase handler not found');
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
const result = await handler.handle(args, this.components.context);
|
|
182
|
+
if (!result.success) {
|
|
183
|
+
throw new Error(result.error || 'Handler execution failed');
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
return result.data as ProceedToPhaseResult;
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
/**
|
|
190
|
+
* Direct access to tool handlers for testing
|
|
191
|
+
*/
|
|
192
|
+
public async handleStartDevelopment(
|
|
193
|
+
args: StartDevelopmentArgs
|
|
194
|
+
): Promise<StartDevelopmentResult> {
|
|
195
|
+
if (!this.components) {
|
|
196
|
+
throw new Error('Server not initialized. Call initialize() first.');
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
const handler = this.components.toolRegistry.get('start_development');
|
|
200
|
+
if (!handler) {
|
|
201
|
+
throw new Error('start_development handler not found');
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
const result = await handler.handle(args, this.components.context);
|
|
205
|
+
if (!result.success) {
|
|
206
|
+
throw new Error(result.error || 'Handler execution failed');
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
return result.data as StartDevelopmentResult;
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
/**
|
|
213
|
+
* Direct access to tool handlers for testing
|
|
214
|
+
*/
|
|
215
|
+
public async handleResumeWorkflow(
|
|
216
|
+
args: ResumeWorkflowArgs
|
|
217
|
+
): Promise<ResumeWorkflowResult> {
|
|
218
|
+
if (!this.components) {
|
|
219
|
+
throw new Error('Server not initialized. Call initialize() first.');
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
const handler = this.components.toolRegistry.get('resume_workflow');
|
|
223
|
+
if (!handler) {
|
|
224
|
+
throw new Error('resume_workflow handler not found');
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
const result = await handler.handle(args, this.components.context);
|
|
228
|
+
if (!result.success) {
|
|
229
|
+
throw new Error(result.error || 'Handler execution failed');
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
return result.data as ResumeWorkflowResult;
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
/**
|
|
236
|
+
* Direct access to tool handlers for testing
|
|
237
|
+
*/
|
|
238
|
+
public async handleResetDevelopment(
|
|
239
|
+
args: ResetDevelopmentArgs
|
|
240
|
+
): Promise<ResetDevelopmentResult> {
|
|
241
|
+
if (!this.components) {
|
|
242
|
+
throw new Error('Server not initialized. Call initialize() first.');
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
const handler = this.components.toolRegistry.get('reset_development');
|
|
246
|
+
if (!handler) {
|
|
247
|
+
throw new Error('reset_development handler not found');
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
const result = await handler.handle(args, this.components.context);
|
|
251
|
+
if (!result.success) {
|
|
252
|
+
throw new Error(result.error || 'Handler execution failed');
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
return result.data as ResetDevelopmentResult;
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
/**
|
|
259
|
+
* Cleanup server resources
|
|
260
|
+
*/
|
|
261
|
+
public async cleanup(): Promise<void> {
|
|
262
|
+
logger.debug('Cleaning up server resources');
|
|
263
|
+
|
|
264
|
+
if (this.components?.database) {
|
|
265
|
+
await this.components.database.close();
|
|
266
|
+
}
|
|
267
|
+
|
|
268
|
+
logger.info('Server cleanup completed');
|
|
269
|
+
}
|
|
270
|
+
}
|
|
271
|
+
|
|
272
|
+
// Export all types and utilities for external use
|
|
273
|
+
export * from './types.js';
|
|
274
|
+
export * from './server-helpers.js';
|
|
275
|
+
export * from './response-renderer.js';
|
|
276
|
+
export * from './tool-handlers/index.js';
|
|
277
|
+
export * from './resource-handlers/index.js';
|
package/src/server.ts
ADDED
|
@@ -0,0 +1,141 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Base Tool Handler
|
|
3
|
+
*
|
|
4
|
+
* Provides common functionality for all tool handlers including
|
|
5
|
+
* error handling, logging, and conversation state management.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
import { createLogger } from '@codemcp/workflows-core';
|
|
9
|
+
import { ToolHandler, ServerContext, HandlerResult } from '../types.js';
|
|
10
|
+
import type { ConversationContext } from '@codemcp/workflows-core';
|
|
11
|
+
import {
|
|
12
|
+
safeExecute,
|
|
13
|
+
logHandlerExecution,
|
|
14
|
+
logHandlerCompletion,
|
|
15
|
+
} from '../server-helpers.js';
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* Abstract base class for tool handlers
|
|
19
|
+
* Provides common functionality and enforces consistent patterns
|
|
20
|
+
*/
|
|
21
|
+
export abstract class BaseToolHandler<TArgs = unknown, TResult = unknown>
|
|
22
|
+
implements ToolHandler<TArgs, TResult>
|
|
23
|
+
{
|
|
24
|
+
protected readonly logger: ReturnType<typeof createLogger>;
|
|
25
|
+
|
|
26
|
+
constructor() {
|
|
27
|
+
this.logger = createLogger(this.constructor.name);
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
/**
|
|
31
|
+
* Main handler method - implements consistent error handling and logging
|
|
32
|
+
*/
|
|
33
|
+
async handle(
|
|
34
|
+
args: TArgs,
|
|
35
|
+
context: ServerContext
|
|
36
|
+
): Promise<HandlerResult<TResult>> {
|
|
37
|
+
const handlerName = this.constructor.name;
|
|
38
|
+
logHandlerExecution(handlerName, args);
|
|
39
|
+
|
|
40
|
+
const result = await safeExecute(
|
|
41
|
+
() => this.executeHandler(args, context),
|
|
42
|
+
`${handlerName} execution failed`
|
|
43
|
+
);
|
|
44
|
+
|
|
45
|
+
logHandlerCompletion(handlerName, result);
|
|
46
|
+
return result;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
/**
|
|
50
|
+
* Abstract method that subclasses must implement
|
|
51
|
+
* Contains the actual business logic for the tool
|
|
52
|
+
*/
|
|
53
|
+
protected abstract executeHandler(
|
|
54
|
+
args: TArgs,
|
|
55
|
+
context: ServerContext
|
|
56
|
+
): Promise<TResult>;
|
|
57
|
+
|
|
58
|
+
/**
|
|
59
|
+
* Helper method to get conversation context with proper error handling
|
|
60
|
+
*/
|
|
61
|
+
protected async getConversationContext(context: ServerContext) {
|
|
62
|
+
try {
|
|
63
|
+
return await context.conversationManager.getConversationContext();
|
|
64
|
+
} catch (error) {
|
|
65
|
+
this.logger.info('Conversation not found', { error });
|
|
66
|
+
throw new Error('CONVERSATION_NOT_FOUND');
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
/**
|
|
71
|
+
* Helper method to ensure state machine is loaded for a project
|
|
72
|
+
*/
|
|
73
|
+
protected ensureStateMachineForProject(
|
|
74
|
+
context: ServerContext,
|
|
75
|
+
projectPath: string,
|
|
76
|
+
workflowName?: string
|
|
77
|
+
): void {
|
|
78
|
+
const stateMachine = context.transitionEngine.getStateMachine(
|
|
79
|
+
projectPath,
|
|
80
|
+
workflowName
|
|
81
|
+
);
|
|
82
|
+
context.planManager.setStateMachine(stateMachine);
|
|
83
|
+
context.instructionGenerator.setStateMachine(stateMachine);
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
/**
|
|
87
|
+
* Helper method to log interactions if logger is available
|
|
88
|
+
*/
|
|
89
|
+
protected async logInteraction(
|
|
90
|
+
context: ServerContext,
|
|
91
|
+
conversationId: string,
|
|
92
|
+
toolName: string,
|
|
93
|
+
args: unknown,
|
|
94
|
+
response: unknown,
|
|
95
|
+
phase: string
|
|
96
|
+
): Promise<void> {
|
|
97
|
+
if (context.interactionLogger) {
|
|
98
|
+
await context.interactionLogger.logInteraction(
|
|
99
|
+
conversationId,
|
|
100
|
+
toolName,
|
|
101
|
+
args,
|
|
102
|
+
response,
|
|
103
|
+
phase
|
|
104
|
+
);
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
/**
|
|
110
|
+
* Base class for tool handlers that require an existing conversation
|
|
111
|
+
* Automatically handles the conversation-not-found case
|
|
112
|
+
*/
|
|
113
|
+
export abstract class ConversationRequiredToolHandler<
|
|
114
|
+
TArgs = unknown,
|
|
115
|
+
TResult = unknown,
|
|
116
|
+
> extends BaseToolHandler<TArgs, TResult> {
|
|
117
|
+
protected async executeHandler(
|
|
118
|
+
args: TArgs,
|
|
119
|
+
context: ServerContext
|
|
120
|
+
): Promise<TResult> {
|
|
121
|
+
let conversationContext;
|
|
122
|
+
|
|
123
|
+
try {
|
|
124
|
+
conversationContext = await this.getConversationContext(context);
|
|
125
|
+
} catch (_error) {
|
|
126
|
+
// Return a special error result that the response renderer can handle
|
|
127
|
+
throw new Error('CONVERSATION_NOT_FOUND');
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
return this.executeWithConversation(args, context, conversationContext);
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
/**
|
|
134
|
+
* Abstract method for handlers that need conversation context
|
|
135
|
+
*/
|
|
136
|
+
protected abstract executeWithConversation(
|
|
137
|
+
args: TArgs,
|
|
138
|
+
context: ServerContext,
|
|
139
|
+
conversationContext: ConversationContext
|
|
140
|
+
): Promise<TResult>;
|
|
141
|
+
}
|