@corbat-tech/coding-standards-mcp 1.0.0
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/LICENSE +21 -0
- package/README.md +371 -0
- package/assets/demo.gif +0 -0
- package/dist/agent.d.ts +53 -0
- package/dist/agent.d.ts.map +1 -0
- package/dist/agent.js +629 -0
- package/dist/agent.js.map +1 -0
- package/dist/cli/init.d.ts +3 -0
- package/dist/cli/init.d.ts.map +1 -0
- package/dist/cli/init.js +651 -0
- package/dist/cli/init.js.map +1 -0
- package/dist/config.d.ts +73 -0
- package/dist/config.d.ts.map +1 -0
- package/dist/config.js +105 -0
- package/dist/config.js.map +1 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +73 -0
- package/dist/index.js.map +1 -0
- package/dist/profiles.d.ts +39 -0
- package/dist/profiles.d.ts.map +1 -0
- package/dist/profiles.js +526 -0
- package/dist/profiles.js.map +1 -0
- package/dist/prompts-legacy.d.ts +25 -0
- package/dist/prompts-legacy.d.ts.map +1 -0
- package/dist/prompts-legacy.js +600 -0
- package/dist/prompts-legacy.js.map +1 -0
- package/dist/prompts-v2.d.ts +30 -0
- package/dist/prompts-v2.d.ts.map +1 -0
- package/dist/prompts-v2.js +310 -0
- package/dist/prompts-v2.js.map +1 -0
- package/dist/prompts.d.ts +30 -0
- package/dist/prompts.d.ts.map +1 -0
- package/dist/prompts.js +310 -0
- package/dist/prompts.js.map +1 -0
- package/dist/resources.d.ts +18 -0
- package/dist/resources.d.ts.map +1 -0
- package/dist/resources.js +95 -0
- package/dist/resources.js.map +1 -0
- package/dist/tools-legacy.d.ts +196 -0
- package/dist/tools-legacy.d.ts.map +1 -0
- package/dist/tools-legacy.js +1230 -0
- package/dist/tools-legacy.js.map +1 -0
- package/dist/tools-v2.d.ts +92 -0
- package/dist/tools-v2.d.ts.map +1 -0
- package/dist/tools-v2.js +410 -0
- package/dist/tools-v2.js.map +1 -0
- package/dist/tools.d.ts +92 -0
- package/dist/tools.d.ts.map +1 -0
- package/dist/tools.js +410 -0
- package/dist/tools.js.map +1 -0
- package/dist/types.d.ts +3054 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +515 -0
- package/dist/types.js.map +1 -0
- package/dist/utils/index.d.ts +6 -0
- package/dist/utils/index.d.ts.map +1 -0
- package/dist/utils/index.js +5 -0
- package/dist/utils/index.js.map +1 -0
- package/dist/utils/retry.d.ts +44 -0
- package/dist/utils/retry.d.ts.map +1 -0
- package/dist/utils/retry.js +74 -0
- package/dist/utils/retry.js.map +1 -0
- package/package.json +79 -0
- package/profiles/README.md +199 -0
- package/profiles/custom/.gitkeep +2 -0
- package/profiles/templates/_template.yaml +159 -0
- package/profiles/templates/angular.yaml +494 -0
- package/profiles/templates/java-spring-backend.yaml +512 -0
- package/profiles/templates/minimal.yaml +102 -0
- package/profiles/templates/nodejs.yaml +338 -0
- package/profiles/templates/python.yaml +340 -0
- package/profiles/templates/react.yaml +331 -0
- package/profiles/templates/vue.yaml +598 -0
- package/standards/architecture/ddd.md +173 -0
- package/standards/architecture/hexagonal.md +97 -0
- package/standards/cicd/github-actions.md +567 -0
- package/standards/clean-code/naming.md +175 -0
- package/standards/clean-code/principles.md +179 -0
- package/standards/containerization/dockerfile.md +419 -0
- package/standards/database/selection-guide.md +443 -0
- package/standards/documentation/guidelines.md +189 -0
- package/standards/event-driven/domain-events.md +527 -0
- package/standards/kubernetes/deployment.md +518 -0
- package/standards/observability/guidelines.md +665 -0
- package/standards/project-setup/initialization-checklist.md +650 -0
- package/standards/spring-boot/best-practices.md +598 -0
- package/standards/testing/guidelines.md +559 -0
- package/standards/workflow/llm-development-workflow.md +542 -0
|
@@ -0,0 +1,1230 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
import { TECHNICAL_DECISIONS, classifyTaskType, detectProjectStack, formatGuardrailsAsMarkdown, getGuardrails, getProjectRules, getTechnicalDecision, loadProjectConfig, } from './agent.js';
|
|
3
|
+
import { config } from './config.js';
|
|
4
|
+
import { formatProfileAsMarkdown, getProfile, listProfiles, loadStandards } from './profiles.js';
|
|
5
|
+
/**
|
|
6
|
+
* Tool definitions for MCP.
|
|
7
|
+
*/
|
|
8
|
+
export const tools = [
|
|
9
|
+
{
|
|
10
|
+
name: 'get_coding_standards',
|
|
11
|
+
description: 'Get the complete coding standards and best practices for a specific profile. Returns architecture guidelines, DDD patterns, code quality rules, and naming conventions.',
|
|
12
|
+
inputSchema: {
|
|
13
|
+
type: 'object',
|
|
14
|
+
properties: {
|
|
15
|
+
profile: {
|
|
16
|
+
type: 'string',
|
|
17
|
+
description: `Profile ID (e.g., "default", "custom1"). Defaults to "${config.defaultProfile}".`,
|
|
18
|
+
},
|
|
19
|
+
},
|
|
20
|
+
},
|
|
21
|
+
},
|
|
22
|
+
{
|
|
23
|
+
name: 'list_profiles',
|
|
24
|
+
description: 'List all available coding standards profiles with their descriptions.',
|
|
25
|
+
inputSchema: {
|
|
26
|
+
type: 'object',
|
|
27
|
+
properties: {},
|
|
28
|
+
},
|
|
29
|
+
},
|
|
30
|
+
{
|
|
31
|
+
name: 'get_architecture_guidelines',
|
|
32
|
+
description: 'Get architecture-specific guidelines including layer definitions, dependencies, DDD patterns, CQRS, and event-driven architecture.',
|
|
33
|
+
inputSchema: {
|
|
34
|
+
type: 'object',
|
|
35
|
+
properties: {
|
|
36
|
+
profile: {
|
|
37
|
+
type: 'string',
|
|
38
|
+
description: `Profile ID. Defaults to "${config.defaultProfile}".`,
|
|
39
|
+
},
|
|
40
|
+
},
|
|
41
|
+
},
|
|
42
|
+
},
|
|
43
|
+
{
|
|
44
|
+
name: 'get_naming_conventions',
|
|
45
|
+
description: 'Get naming conventions for classes, methods, variables, constants, test classes, etc.',
|
|
46
|
+
inputSchema: {
|
|
47
|
+
type: 'object',
|
|
48
|
+
properties: {
|
|
49
|
+
profile: {
|
|
50
|
+
type: 'string',
|
|
51
|
+
description: `Profile ID. Defaults to "${config.defaultProfile}".`,
|
|
52
|
+
},
|
|
53
|
+
},
|
|
54
|
+
},
|
|
55
|
+
},
|
|
56
|
+
{
|
|
57
|
+
name: 'search_standards',
|
|
58
|
+
description: 'Search the standards documentation for specific topics. Use this to find information about specific technologies, patterns, or practices (e.g., "kafka", "testing", "docker", "kubernetes", "observability").',
|
|
59
|
+
inputSchema: {
|
|
60
|
+
type: 'object',
|
|
61
|
+
properties: {
|
|
62
|
+
query: {
|
|
63
|
+
type: 'string',
|
|
64
|
+
description: 'Search query (e.g., "kafka", "dockerfile", "integration test", "observability")',
|
|
65
|
+
},
|
|
66
|
+
},
|
|
67
|
+
required: ['query'],
|
|
68
|
+
},
|
|
69
|
+
},
|
|
70
|
+
{
|
|
71
|
+
name: 'health_check',
|
|
72
|
+
description: 'Check the health status of corbat-mcp server. Returns information about loaded profiles, standards, cache status, and version.',
|
|
73
|
+
inputSchema: {
|
|
74
|
+
type: 'object',
|
|
75
|
+
properties: {},
|
|
76
|
+
},
|
|
77
|
+
},
|
|
78
|
+
{
|
|
79
|
+
name: 'get_development_workflow',
|
|
80
|
+
description: 'Get the structured LLM development workflow guide. This workflow defines how to implement features following: Clarify → Plan → Build (TDD) → Verify → Review → Refine. Use this when starting to implement any feature or fix.',
|
|
81
|
+
inputSchema: {
|
|
82
|
+
type: 'object',
|
|
83
|
+
properties: {},
|
|
84
|
+
},
|
|
85
|
+
},
|
|
86
|
+
// ============================================================================
|
|
87
|
+
// AGENT MODE TOOLS - Intelligent context injection and decision support
|
|
88
|
+
// ============================================================================
|
|
89
|
+
{
|
|
90
|
+
name: 'get_full_context',
|
|
91
|
+
description: 'Get COMPLETE context for a task in a single call. This is the PRIMARY tool for agent mode - it returns everything needed: guardrails, profile standards, architecture, naming conventions, workflow, and relevant documentation. Use this BEFORE starting any implementation.',
|
|
92
|
+
inputSchema: {
|
|
93
|
+
type: 'object',
|
|
94
|
+
properties: {
|
|
95
|
+
task_description: {
|
|
96
|
+
type: 'string',
|
|
97
|
+
description: 'Description of the task to implement (e.g., "Create a payment service", "Fix login bug")',
|
|
98
|
+
},
|
|
99
|
+
project_dir: {
|
|
100
|
+
type: 'string',
|
|
101
|
+
description: 'Project directory path to detect stack and load .corbat.json (optional)',
|
|
102
|
+
},
|
|
103
|
+
profile: {
|
|
104
|
+
type: 'string',
|
|
105
|
+
description: `Override profile ID. If not provided, will be auto-detected or default to "${config.defaultProfile}"`,
|
|
106
|
+
},
|
|
107
|
+
},
|
|
108
|
+
required: ['task_description'],
|
|
109
|
+
},
|
|
110
|
+
},
|
|
111
|
+
{
|
|
112
|
+
name: 'detect_project_stack',
|
|
113
|
+
description: 'Auto-detect the technology stack of a project by analyzing files (package.json, pom.xml, etc.). Returns suggested profile, language, framework, and confidence level.',
|
|
114
|
+
inputSchema: {
|
|
115
|
+
type: 'object',
|
|
116
|
+
properties: {
|
|
117
|
+
project_dir: {
|
|
118
|
+
type: 'string',
|
|
119
|
+
description: 'Path to the project directory to analyze',
|
|
120
|
+
},
|
|
121
|
+
},
|
|
122
|
+
required: ['project_dir'],
|
|
123
|
+
},
|
|
124
|
+
},
|
|
125
|
+
{
|
|
126
|
+
name: 'get_guardrails',
|
|
127
|
+
description: 'Get mandatory rules, recommendations, and things to avoid for a specific task type. Guardrails ensure quality and consistency.',
|
|
128
|
+
inputSchema: {
|
|
129
|
+
type: 'object',
|
|
130
|
+
properties: {
|
|
131
|
+
task_type: {
|
|
132
|
+
type: 'string',
|
|
133
|
+
enum: ['feature', 'bugfix', 'refactor', 'test', 'documentation', 'performance', 'security', 'infrastructure'],
|
|
134
|
+
description: 'Type of task to get guardrails for',
|
|
135
|
+
},
|
|
136
|
+
project_dir: {
|
|
137
|
+
type: 'string',
|
|
138
|
+
description: 'Project directory to load custom guardrails from .corbat.json (optional)',
|
|
139
|
+
},
|
|
140
|
+
},
|
|
141
|
+
required: ['task_type'],
|
|
142
|
+
},
|
|
143
|
+
},
|
|
144
|
+
{
|
|
145
|
+
name: 'validate_against_standards',
|
|
146
|
+
description: 'Validate code or implementation plan against the coding standards. Returns compliance score, issues found, and suggestions for improvement.',
|
|
147
|
+
inputSchema: {
|
|
148
|
+
type: 'object',
|
|
149
|
+
properties: {
|
|
150
|
+
code: {
|
|
151
|
+
type: 'string',
|
|
152
|
+
description: 'The code or implementation description to validate',
|
|
153
|
+
},
|
|
154
|
+
profile: {
|
|
155
|
+
type: 'string',
|
|
156
|
+
description: `Profile ID to validate against. Defaults to "${config.defaultProfile}"`,
|
|
157
|
+
},
|
|
158
|
+
task_type: {
|
|
159
|
+
type: 'string',
|
|
160
|
+
enum: ['feature', 'bugfix', 'refactor', 'test', 'documentation', 'performance', 'security', 'infrastructure'],
|
|
161
|
+
description: 'Type of task for context-aware validation',
|
|
162
|
+
},
|
|
163
|
+
},
|
|
164
|
+
required: ['code'],
|
|
165
|
+
},
|
|
166
|
+
},
|
|
167
|
+
{
|
|
168
|
+
name: 'make_technical_decision',
|
|
169
|
+
description: 'Get a recommendation for a technical decision (database, cache, messaging, authentication, testing strategy, etc.). Returns options with pros/cons and a recommendation aligned with project standards.',
|
|
170
|
+
inputSchema: {
|
|
171
|
+
type: 'object',
|
|
172
|
+
properties: {
|
|
173
|
+
category: {
|
|
174
|
+
type: 'string',
|
|
175
|
+
enum: ['database', 'cache', 'messaging', 'authentication', 'testing'],
|
|
176
|
+
description: 'Category of technical decision',
|
|
177
|
+
},
|
|
178
|
+
context: {
|
|
179
|
+
type: 'string',
|
|
180
|
+
description: 'Context about the requirement (e.g., "Need to store user sessions for 100k concurrent users")',
|
|
181
|
+
},
|
|
182
|
+
project_dir: {
|
|
183
|
+
type: 'string',
|
|
184
|
+
description: 'Project directory to check for predefined decisions in .corbat.json (optional)',
|
|
185
|
+
},
|
|
186
|
+
},
|
|
187
|
+
required: ['category', 'context'],
|
|
188
|
+
},
|
|
189
|
+
},
|
|
190
|
+
{
|
|
191
|
+
name: 'load_project_config',
|
|
192
|
+
description: 'Load project-specific configuration from .corbat.json. Returns profile override, custom rules, technical decisions, and guardrails defined for the project.',
|
|
193
|
+
inputSchema: {
|
|
194
|
+
type: 'object',
|
|
195
|
+
properties: {
|
|
196
|
+
project_dir: {
|
|
197
|
+
type: 'string',
|
|
198
|
+
description: 'Path to project directory containing .corbat.json',
|
|
199
|
+
},
|
|
200
|
+
},
|
|
201
|
+
required: ['project_dir'],
|
|
202
|
+
},
|
|
203
|
+
},
|
|
204
|
+
];
|
|
205
|
+
/**
|
|
206
|
+
* Input schemas for validation.
|
|
207
|
+
*/
|
|
208
|
+
const ProfileInputSchema = z.object({
|
|
209
|
+
profile: z.string().optional(),
|
|
210
|
+
});
|
|
211
|
+
const SearchInputSchema = z.object({
|
|
212
|
+
query: z.string(),
|
|
213
|
+
});
|
|
214
|
+
const FullContextInputSchema = z.object({
|
|
215
|
+
task_description: z.string(),
|
|
216
|
+
project_dir: z.string().optional(),
|
|
217
|
+
profile: z.string().optional(),
|
|
218
|
+
});
|
|
219
|
+
const DetectStackInputSchema = z.object({
|
|
220
|
+
project_dir: z.string(),
|
|
221
|
+
});
|
|
222
|
+
const GuardrailsInputSchema = z.object({
|
|
223
|
+
task_type: z.enum([
|
|
224
|
+
'feature',
|
|
225
|
+
'bugfix',
|
|
226
|
+
'refactor',
|
|
227
|
+
'test',
|
|
228
|
+
'documentation',
|
|
229
|
+
'performance',
|
|
230
|
+
'security',
|
|
231
|
+
'infrastructure',
|
|
232
|
+
]),
|
|
233
|
+
project_dir: z.string().optional(),
|
|
234
|
+
});
|
|
235
|
+
const ValidateInputSchema = z.object({
|
|
236
|
+
code: z.string(),
|
|
237
|
+
profile: z.string().optional(),
|
|
238
|
+
task_type: z
|
|
239
|
+
.enum(['feature', 'bugfix', 'refactor', 'test', 'documentation', 'performance', 'security', 'infrastructure'])
|
|
240
|
+
.optional(),
|
|
241
|
+
});
|
|
242
|
+
const TechnicalDecisionInputSchema = z.object({
|
|
243
|
+
category: z.enum(['database', 'cache', 'messaging', 'authentication', 'testing']),
|
|
244
|
+
context: z.string(),
|
|
245
|
+
project_dir: z.string().optional(),
|
|
246
|
+
});
|
|
247
|
+
const ProjectConfigInputSchema = z.object({
|
|
248
|
+
project_dir: z.string(),
|
|
249
|
+
});
|
|
250
|
+
/**
|
|
251
|
+
* Handle tool calls.
|
|
252
|
+
*/
|
|
253
|
+
export async function handleToolCall(name, args) {
|
|
254
|
+
switch (name) {
|
|
255
|
+
case 'get_coding_standards':
|
|
256
|
+
return handleGetCodingStandards(args);
|
|
257
|
+
case 'list_profiles':
|
|
258
|
+
return handleListProfiles();
|
|
259
|
+
case 'get_architecture_guidelines':
|
|
260
|
+
return handleGetArchitectureGuidelines(args);
|
|
261
|
+
case 'get_naming_conventions':
|
|
262
|
+
return handleGetNamingConventions(args);
|
|
263
|
+
case 'search_standards':
|
|
264
|
+
return handleSearchStandards(args);
|
|
265
|
+
case 'health_check':
|
|
266
|
+
return handleHealthCheck();
|
|
267
|
+
case 'get_development_workflow':
|
|
268
|
+
return handleGetDevelopmentWorkflow();
|
|
269
|
+
// Agent mode tools
|
|
270
|
+
case 'get_full_context':
|
|
271
|
+
return handleGetFullContext(args);
|
|
272
|
+
case 'detect_project_stack':
|
|
273
|
+
return handleDetectProjectStack(args);
|
|
274
|
+
case 'get_guardrails':
|
|
275
|
+
return handleGetGuardrails(args);
|
|
276
|
+
case 'validate_against_standards':
|
|
277
|
+
return handleValidateAgainstStandards(args);
|
|
278
|
+
case 'make_technical_decision':
|
|
279
|
+
return handleMakeTechnicalDecision(args);
|
|
280
|
+
case 'load_project_config':
|
|
281
|
+
return handleLoadProjectConfig(args);
|
|
282
|
+
default:
|
|
283
|
+
return {
|
|
284
|
+
content: [{ type: 'text', text: `Unknown tool: ${name}` }],
|
|
285
|
+
isError: true,
|
|
286
|
+
};
|
|
287
|
+
}
|
|
288
|
+
}
|
|
289
|
+
async function handleGetCodingStandards(args) {
|
|
290
|
+
const { profile: profileId = config.defaultProfile } = ProfileInputSchema.parse(args);
|
|
291
|
+
const profile = await getProfile(profileId);
|
|
292
|
+
if (!profile) {
|
|
293
|
+
return {
|
|
294
|
+
content: [{ type: 'text', text: `Profile not found: ${profileId}` }],
|
|
295
|
+
isError: true,
|
|
296
|
+
};
|
|
297
|
+
}
|
|
298
|
+
const standards = await loadStandards();
|
|
299
|
+
const profileMarkdown = formatProfileAsMarkdown(profileId, profile);
|
|
300
|
+
const standardsMarkdown = standards.map((s) => `## ${s.name}\n\n${s.content}`).join('\n\n---\n\n');
|
|
301
|
+
const fullContext = `${profileMarkdown}\n\n---\n\n# Standards Documentation\n\n${standardsMarkdown}`;
|
|
302
|
+
return { content: [{ type: 'text', text: fullContext }] };
|
|
303
|
+
}
|
|
304
|
+
async function handleListProfiles() {
|
|
305
|
+
const profiles = await listProfiles();
|
|
306
|
+
if (profiles.length === 0) {
|
|
307
|
+
return {
|
|
308
|
+
content: [{ type: 'text', text: 'No profiles found.' }],
|
|
309
|
+
};
|
|
310
|
+
}
|
|
311
|
+
const list = profiles
|
|
312
|
+
.map(({ id, profile }) => `- **${id}**: ${profile.name} - ${profile.description || 'No description'}`)
|
|
313
|
+
.join('\n');
|
|
314
|
+
return {
|
|
315
|
+
content: [{ type: 'text', text: `# Available Profiles\n\n${list}` }],
|
|
316
|
+
};
|
|
317
|
+
}
|
|
318
|
+
async function handleGetArchitectureGuidelines(args) {
|
|
319
|
+
const { profile: profileId = config.defaultProfile } = ProfileInputSchema.parse(args);
|
|
320
|
+
const profile = await getProfile(profileId);
|
|
321
|
+
if (!profile) {
|
|
322
|
+
return {
|
|
323
|
+
content: [{ type: 'text', text: `Profile not found: ${profileId}` }],
|
|
324
|
+
isError: true,
|
|
325
|
+
};
|
|
326
|
+
}
|
|
327
|
+
const lines = ['# Architecture Guidelines', ''];
|
|
328
|
+
if (profile.architecture) {
|
|
329
|
+
lines.push(`## Pattern: ${profile.architecture.type}`, '');
|
|
330
|
+
lines.push(`**Enforce Layer Dependencies:** ${profile.architecture.enforceLayerDependencies}`, '');
|
|
331
|
+
if (profile.architecture.layers) {
|
|
332
|
+
lines.push('', '## Layers', '');
|
|
333
|
+
for (const layer of profile.architecture.layers) {
|
|
334
|
+
lines.push(`### ${layer.name}`);
|
|
335
|
+
lines.push(layer.description);
|
|
336
|
+
lines.push('');
|
|
337
|
+
const deps = layer.allowedDependencies.length > 0 ? layer.allowedDependencies.join(', ') : 'none';
|
|
338
|
+
lines.push(`**Allowed dependencies:** ${deps}`);
|
|
339
|
+
if (layer.packages && layer.packages.length > 0) {
|
|
340
|
+
lines.push(`**Packages:** ${layer.packages.join(', ')}`);
|
|
341
|
+
}
|
|
342
|
+
lines.push('');
|
|
343
|
+
}
|
|
344
|
+
}
|
|
345
|
+
if (profile.architecture.archUnit) {
|
|
346
|
+
lines.push('## ArchUnit', '');
|
|
347
|
+
lines.push(`- Enabled: ${profile.architecture.archUnit.enabled}`);
|
|
348
|
+
lines.push(`- Recommended: ${profile.architecture.archUnit.recommended}`);
|
|
349
|
+
if (profile.architecture.archUnit.rules && profile.architecture.archUnit.rules.length > 0) {
|
|
350
|
+
lines.push('', '**Validation Rules:**');
|
|
351
|
+
for (const rule of profile.architecture.archUnit.rules) {
|
|
352
|
+
lines.push(`- ${rule}`);
|
|
353
|
+
}
|
|
354
|
+
}
|
|
355
|
+
lines.push('');
|
|
356
|
+
}
|
|
357
|
+
}
|
|
358
|
+
if (profile.ddd?.enabled) {
|
|
359
|
+
lines.push('## DDD Patterns', '');
|
|
360
|
+
lines.push(`**Ubiquitous Language Enforced:** ${profile.ddd.ubiquitousLanguageEnforced}`, '');
|
|
361
|
+
if (profile.ddd.patterns) {
|
|
362
|
+
lines.push('### Enabled Patterns', '');
|
|
363
|
+
for (const [pattern, enabled] of Object.entries(profile.ddd.patterns)) {
|
|
364
|
+
if (enabled)
|
|
365
|
+
lines.push(`- ${pattern}`);
|
|
366
|
+
}
|
|
367
|
+
lines.push('');
|
|
368
|
+
}
|
|
369
|
+
if (profile.ddd.valueObjectGuidelines) {
|
|
370
|
+
lines.push('### Value Object Guidelines', '');
|
|
371
|
+
lines.push(`- Use Records: ${profile.ddd.valueObjectGuidelines.useRecords}`);
|
|
372
|
+
lines.push(`- Immutable: ${profile.ddd.valueObjectGuidelines.immutable}`);
|
|
373
|
+
lines.push(`- Self-validating: ${profile.ddd.valueObjectGuidelines.selfValidating}`);
|
|
374
|
+
if (profile.ddd.valueObjectGuidelines.examples) {
|
|
375
|
+
lines.push('', '**Examples:**');
|
|
376
|
+
for (const ex of profile.ddd.valueObjectGuidelines.examples) {
|
|
377
|
+
lines.push(`- ${ex}`);
|
|
378
|
+
}
|
|
379
|
+
}
|
|
380
|
+
lines.push('');
|
|
381
|
+
}
|
|
382
|
+
if (profile.ddd.aggregateGuidelines) {
|
|
383
|
+
lines.push('### Aggregate Guidelines', '');
|
|
384
|
+
lines.push(`- Single Entry Point: ${profile.ddd.aggregateGuidelines.singleEntryPoint}`);
|
|
385
|
+
lines.push(`- Protect Invariants: ${profile.ddd.aggregateGuidelines.protectInvariants}`);
|
|
386
|
+
lines.push(`- Small Aggregates: ${profile.ddd.aggregateGuidelines.smallAggregates}`);
|
|
387
|
+
lines.push(`- Reference by Identity: ${profile.ddd.aggregateGuidelines.referenceByIdentity}`);
|
|
388
|
+
lines.push('');
|
|
389
|
+
}
|
|
390
|
+
}
|
|
391
|
+
// CQRS
|
|
392
|
+
if (profile.cqrs?.enabled) {
|
|
393
|
+
lines.push('## CQRS', '');
|
|
394
|
+
lines.push(`**Separation:** ${profile.cqrs.separation}`, '');
|
|
395
|
+
if (profile.cqrs.patterns?.commands) {
|
|
396
|
+
lines.push('### Commands', '');
|
|
397
|
+
lines.push(`- Suffix: ${profile.cqrs.patterns.commands.suffix}`);
|
|
398
|
+
lines.push(`- Handler: ${profile.cqrs.patterns.commands.handler}`);
|
|
399
|
+
if (profile.cqrs.patterns.commands.examples) {
|
|
400
|
+
lines.push(`- Examples: ${profile.cqrs.patterns.commands.examples.join(', ')}`);
|
|
401
|
+
}
|
|
402
|
+
lines.push('');
|
|
403
|
+
}
|
|
404
|
+
if (profile.cqrs.patterns?.queries) {
|
|
405
|
+
lines.push('### Queries', '');
|
|
406
|
+
lines.push(`- Suffix: ${profile.cqrs.patterns.queries.suffix}`);
|
|
407
|
+
lines.push(`- Handler: ${profile.cqrs.patterns.queries.handler}`);
|
|
408
|
+
if (profile.cqrs.patterns.queries.examples) {
|
|
409
|
+
lines.push(`- Examples: ${profile.cqrs.patterns.queries.examples.join(', ')}`);
|
|
410
|
+
}
|
|
411
|
+
lines.push('');
|
|
412
|
+
}
|
|
413
|
+
}
|
|
414
|
+
// Event-Driven
|
|
415
|
+
if (profile.eventDriven?.enabled) {
|
|
416
|
+
lines.push('## Event-Driven Architecture', '');
|
|
417
|
+
lines.push(`**Approach:** ${profile.eventDriven.approach}`, '');
|
|
418
|
+
if (profile.eventDriven.patterns?.domainEvents) {
|
|
419
|
+
lines.push('### Domain Events', '');
|
|
420
|
+
lines.push(`- Suffix: ${profile.eventDriven.patterns.domainEvents.suffix}`);
|
|
421
|
+
lines.push(`- Past Tense: ${profile.eventDriven.patterns.domainEvents.pastTense}`);
|
|
422
|
+
if (profile.eventDriven.patterns.domainEvents.examples) {
|
|
423
|
+
lines.push(`- Examples: ${profile.eventDriven.patterns.domainEvents.examples.join(', ')}`);
|
|
424
|
+
}
|
|
425
|
+
lines.push('');
|
|
426
|
+
}
|
|
427
|
+
if (profile.eventDriven.patterns?.messaging) {
|
|
428
|
+
lines.push('### Messaging', '');
|
|
429
|
+
lines.push(`- Broker: ${profile.eventDriven.patterns.messaging.broker}`);
|
|
430
|
+
if (profile.eventDriven.patterns.messaging.topicNaming) {
|
|
431
|
+
lines.push(`- Topic Naming: ${profile.eventDriven.patterns.messaging.topicNaming}`);
|
|
432
|
+
}
|
|
433
|
+
if (profile.eventDriven.patterns.messaging.examples) {
|
|
434
|
+
lines.push(`- Examples: ${profile.eventDriven.patterns.messaging.examples.join(', ')}`);
|
|
435
|
+
}
|
|
436
|
+
lines.push('');
|
|
437
|
+
}
|
|
438
|
+
}
|
|
439
|
+
return { content: [{ type: 'text', text: lines.join('\n') }] };
|
|
440
|
+
}
|
|
441
|
+
async function handleGetNamingConventions(args) {
|
|
442
|
+
const { profile: profileId = config.defaultProfile } = ProfileInputSchema.parse(args);
|
|
443
|
+
const profile = await getProfile(profileId);
|
|
444
|
+
if (!profile) {
|
|
445
|
+
return {
|
|
446
|
+
content: [{ type: 'text', text: `Profile not found: ${profileId}` }],
|
|
447
|
+
isError: true,
|
|
448
|
+
};
|
|
449
|
+
}
|
|
450
|
+
const lines = ['# Naming Conventions', ''];
|
|
451
|
+
if (profile.naming && Object.keys(profile.naming).length > 0) {
|
|
452
|
+
const naming = profile.naming;
|
|
453
|
+
// Handle new nested structure
|
|
454
|
+
if (naming.general && typeof naming.general === 'object') {
|
|
455
|
+
lines.push('## General Naming', '');
|
|
456
|
+
for (const [key, value] of Object.entries(naming.general)) {
|
|
457
|
+
lines.push(`- **${key}**: ${value}`);
|
|
458
|
+
}
|
|
459
|
+
lines.push('');
|
|
460
|
+
}
|
|
461
|
+
if (naming.suffixes && typeof naming.suffixes === 'object') {
|
|
462
|
+
lines.push('## Class Suffixes', '');
|
|
463
|
+
for (const [key, value] of Object.entries(naming.suffixes)) {
|
|
464
|
+
lines.push(`- **${key}**: ${value}`);
|
|
465
|
+
}
|
|
466
|
+
lines.push('');
|
|
467
|
+
}
|
|
468
|
+
if (naming.testing && typeof naming.testing === 'object') {
|
|
469
|
+
lines.push('## Testing Naming', '');
|
|
470
|
+
for (const [key, value] of Object.entries(naming.testing)) {
|
|
471
|
+
lines.push(`- **${key}**: ${value}`);
|
|
472
|
+
}
|
|
473
|
+
lines.push('');
|
|
474
|
+
}
|
|
475
|
+
// Handle flat naming structure (backwards compatibility)
|
|
476
|
+
const flatKeys = Object.keys(naming).filter((k) => !['general', 'suffixes', 'testing'].includes(k));
|
|
477
|
+
if (flatKeys.length > 0) {
|
|
478
|
+
lines.push('## Other Conventions', '');
|
|
479
|
+
for (const key of flatKeys) {
|
|
480
|
+
if (typeof naming[key] === 'string') {
|
|
481
|
+
lines.push(`- **${key}**: ${naming[key]}`);
|
|
482
|
+
}
|
|
483
|
+
}
|
|
484
|
+
lines.push('');
|
|
485
|
+
}
|
|
486
|
+
}
|
|
487
|
+
else {
|
|
488
|
+
lines.push('Using default conventions:', '');
|
|
489
|
+
lines.push('');
|
|
490
|
+
lines.push('## General Naming', '');
|
|
491
|
+
lines.push('- **class**: PascalCase');
|
|
492
|
+
lines.push('- **interface**: PascalCase');
|
|
493
|
+
lines.push('- **method**: camelCase');
|
|
494
|
+
lines.push('- **variable**: camelCase');
|
|
495
|
+
lines.push('- **constant**: SCREAMING_SNAKE_CASE');
|
|
496
|
+
lines.push('- **package**: lowercase.dot.separated');
|
|
497
|
+
lines.push('- **enum**: PascalCase');
|
|
498
|
+
lines.push('- **enumValue**: SCREAMING_SNAKE_CASE');
|
|
499
|
+
lines.push('');
|
|
500
|
+
lines.push('## Testing Naming', '');
|
|
501
|
+
lines.push('- **unitTest**: Test suffix (*Test.java)');
|
|
502
|
+
lines.push('- **integrationTest**: IT suffix (*IT.java)');
|
|
503
|
+
lines.push('- **testMethod**: should_ExpectedBehavior_When_Condition');
|
|
504
|
+
}
|
|
505
|
+
return { content: [{ type: 'text', text: lines.join('\n') }] };
|
|
506
|
+
}
|
|
507
|
+
async function handleSearchStandards(args) {
|
|
508
|
+
const { query } = SearchInputSchema.parse(args);
|
|
509
|
+
const standards = await loadStandards();
|
|
510
|
+
if (!query.trim()) {
|
|
511
|
+
return {
|
|
512
|
+
content: [{ type: 'text', text: 'Please provide a search query.' }],
|
|
513
|
+
isError: true,
|
|
514
|
+
};
|
|
515
|
+
}
|
|
516
|
+
const queryLower = query.toLowerCase();
|
|
517
|
+
const results = [];
|
|
518
|
+
for (const standard of standards) {
|
|
519
|
+
const contentLower = standard.content.toLowerCase();
|
|
520
|
+
if (contentLower.includes(queryLower)) {
|
|
521
|
+
// Extract relevant sections containing the query
|
|
522
|
+
const lines = standard.content.split('\n');
|
|
523
|
+
const matches = [];
|
|
524
|
+
let currentSection = '';
|
|
525
|
+
let sectionContent = [];
|
|
526
|
+
for (const line of lines) {
|
|
527
|
+
if (line.startsWith('#')) {
|
|
528
|
+
// Save previous section if it had matches
|
|
529
|
+
if (sectionContent.some((l) => l.toLowerCase().includes(queryLower))) {
|
|
530
|
+
matches.push(`${currentSection}\n${sectionContent.join('\n')}`);
|
|
531
|
+
}
|
|
532
|
+
currentSection = line;
|
|
533
|
+
sectionContent = [];
|
|
534
|
+
}
|
|
535
|
+
else {
|
|
536
|
+
sectionContent.push(line);
|
|
537
|
+
}
|
|
538
|
+
}
|
|
539
|
+
// Check last section
|
|
540
|
+
if (sectionContent.some((l) => l.toLowerCase().includes(queryLower))) {
|
|
541
|
+
matches.push(`${currentSection}\n${sectionContent.join('\n')}`);
|
|
542
|
+
}
|
|
543
|
+
if (matches.length > 0) {
|
|
544
|
+
results.push({
|
|
545
|
+
name: standard.name,
|
|
546
|
+
category: standard.category,
|
|
547
|
+
matches: matches.slice(0, 3), // Limit to 3 matches per document
|
|
548
|
+
});
|
|
549
|
+
}
|
|
550
|
+
}
|
|
551
|
+
}
|
|
552
|
+
if (results.length === 0) {
|
|
553
|
+
return {
|
|
554
|
+
content: [
|
|
555
|
+
{
|
|
556
|
+
type: 'text',
|
|
557
|
+
text: `No results found for "${query}". Try searching for: testing, kafka, docker, kubernetes, observability, logging, metrics, tracing, archunit, flyway, etc.`,
|
|
558
|
+
},
|
|
559
|
+
],
|
|
560
|
+
};
|
|
561
|
+
}
|
|
562
|
+
const output = [`# Search Results for "${query}"`, ''];
|
|
563
|
+
for (const result of results) {
|
|
564
|
+
output.push(`## ${result.name} (${result.category})`, '');
|
|
565
|
+
for (const match of result.matches) {
|
|
566
|
+
output.push(match.trim(), '');
|
|
567
|
+
}
|
|
568
|
+
output.push('---', '');
|
|
569
|
+
}
|
|
570
|
+
return { content: [{ type: 'text', text: output.join('\n') }] };
|
|
571
|
+
}
|
|
572
|
+
async function handleHealthCheck() {
|
|
573
|
+
const startTime = Date.now();
|
|
574
|
+
try {
|
|
575
|
+
const profiles = await listProfiles();
|
|
576
|
+
const standards = await loadStandards();
|
|
577
|
+
const loadTimeMs = Date.now() - startTime;
|
|
578
|
+
const healthInfo = {
|
|
579
|
+
status: 'healthy',
|
|
580
|
+
version: config.serverVersion,
|
|
581
|
+
serverName: config.serverName,
|
|
582
|
+
timestamp: new Date().toISOString(),
|
|
583
|
+
profiles: {
|
|
584
|
+
count: profiles.length,
|
|
585
|
+
ids: profiles.map((p) => p.id),
|
|
586
|
+
},
|
|
587
|
+
standards: {
|
|
588
|
+
count: standards.length,
|
|
589
|
+
categories: [...new Set(standards.map((s) => s.category))],
|
|
590
|
+
},
|
|
591
|
+
configuration: {
|
|
592
|
+
profilesDir: config.profilesDir,
|
|
593
|
+
standardsDir: config.standardsDir,
|
|
594
|
+
defaultProfile: config.defaultProfile,
|
|
595
|
+
},
|
|
596
|
+
performance: {
|
|
597
|
+
loadTimeMs,
|
|
598
|
+
},
|
|
599
|
+
};
|
|
600
|
+
const lines = [
|
|
601
|
+
'# Corbat MCP Health Check',
|
|
602
|
+
'',
|
|
603
|
+
`**Status:** ${healthInfo.status}`,
|
|
604
|
+
`**Version:** ${healthInfo.version}`,
|
|
605
|
+
`**Timestamp:** ${healthInfo.timestamp}`,
|
|
606
|
+
'',
|
|
607
|
+
'## Profiles',
|
|
608
|
+
`- Count: ${healthInfo.profiles.count}`,
|
|
609
|
+
`- Available: ${healthInfo.profiles.ids.join(', ')}`,
|
|
610
|
+
'',
|
|
611
|
+
'## Standards',
|
|
612
|
+
`- Documents: ${healthInfo.standards.count}`,
|
|
613
|
+
`- Categories: ${healthInfo.standards.categories.join(', ')}`,
|
|
614
|
+
'',
|
|
615
|
+
'## Configuration',
|
|
616
|
+
`- Profiles Directory: ${healthInfo.configuration.profilesDir}`,
|
|
617
|
+
`- Standards Directory: ${healthInfo.configuration.standardsDir}`,
|
|
618
|
+
`- Default Profile: ${healthInfo.configuration.defaultProfile}`,
|
|
619
|
+
'',
|
|
620
|
+
'## Performance',
|
|
621
|
+
`- Load Time: ${healthInfo.performance.loadTimeMs}ms`,
|
|
622
|
+
];
|
|
623
|
+
return { content: [{ type: 'text', text: lines.join('\n') }] };
|
|
624
|
+
}
|
|
625
|
+
catch (error) {
|
|
626
|
+
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
627
|
+
return {
|
|
628
|
+
content: [
|
|
629
|
+
{
|
|
630
|
+
type: 'text',
|
|
631
|
+
text: `# Corbat MCP Health Check\n\n**Status:** unhealthy\n**Error:** ${errorMessage}`,
|
|
632
|
+
},
|
|
633
|
+
],
|
|
634
|
+
};
|
|
635
|
+
}
|
|
636
|
+
}
|
|
637
|
+
async function handleGetDevelopmentWorkflow() {
|
|
638
|
+
const workflow = `# LLM Development Workflow
|
|
639
|
+
|
|
640
|
+
## Overview
|
|
641
|
+
This workflow defines the structured process for implementing features, fixes, or any development task.
|
|
642
|
+
|
|
643
|
+
**Phases:** Clarify → Plan → Build (TDD) → Verify → Review → Refine
|
|
644
|
+
|
|
645
|
+
---
|
|
646
|
+
|
|
647
|
+
## PHASE 1: CLARIFICACIÓN (Ask)
|
|
648
|
+
|
|
649
|
+
**Before writing any code, you MUST:**
|
|
650
|
+
|
|
651
|
+
1. Analyze the request for:
|
|
652
|
+
- Explicit functional requirements
|
|
653
|
+
- Implicit or assumed requirements
|
|
654
|
+
- Ambiguities or contradictions
|
|
655
|
+
- Missing technical context
|
|
656
|
+
|
|
657
|
+
2. **ASK if you detect:**
|
|
658
|
+
- Missing functional context
|
|
659
|
+
- Contradictory requirements
|
|
660
|
+
- Multiple possible interpretations
|
|
661
|
+
- Unclear acceptance criteria
|
|
662
|
+
|
|
663
|
+
3. Confirm understanding by reformulating requirements
|
|
664
|
+
|
|
665
|
+
---
|
|
666
|
+
|
|
667
|
+
## PHASE 2: PLANIFICACIÓN (Plan)
|
|
668
|
+
|
|
669
|
+
1. **List requirements and constraints**
|
|
670
|
+
2. **Evaluate 2-3 alternatives** (when applicable):
|
|
671
|
+
- Describe each approach
|
|
672
|
+
- List pros/cons
|
|
673
|
+
- Recommend best option with justification
|
|
674
|
+
|
|
675
|
+
3. **Create task checklist:**
|
|
676
|
+
\`\`\`
|
|
677
|
+
[ ] 1. Task A - Description
|
|
678
|
+
[ ] 1.1 Write tests
|
|
679
|
+
[ ] 1.2 Implement
|
|
680
|
+
[ ] 2. Task B - Description
|
|
681
|
+
[ ] 2.1 Write tests
|
|
682
|
+
[ ] 2.2 Implement
|
|
683
|
+
\`\`\`
|
|
684
|
+
|
|
685
|
+
4. **Define acceptance criteria**
|
|
686
|
+
|
|
687
|
+
---
|
|
688
|
+
|
|
689
|
+
## PHASE 3: IMPLEMENTACIÓN (Build with TDD)
|
|
690
|
+
|
|
691
|
+
**For EACH task, follow TDD strictly:**
|
|
692
|
+
|
|
693
|
+
\`\`\`
|
|
694
|
+
┌─────────────────────────────────────────┐
|
|
695
|
+
│ 1. RED: Write failing test first │
|
|
696
|
+
│ - Test describes expected behavior │
|
|
697
|
+
│ - Run test, confirm it fails │
|
|
698
|
+
├─────────────────────────────────────────┤
|
|
699
|
+
│ 2. GREEN: Implement minimum to pass │
|
|
700
|
+
│ - Only necessary code │
|
|
701
|
+
│ - Run test, confirm it passes │
|
|
702
|
+
├─────────────────────────────────────────┤
|
|
703
|
+
│ 3. REFACTOR: Clean up │
|
|
704
|
+
│ - Apply project patterns │
|
|
705
|
+
│ - Tests still pass │
|
|
706
|
+
└─────────────────────────────────────────┘
|
|
707
|
+
\`\`\`
|
|
708
|
+
|
|
709
|
+
**Test coverage:**
|
|
710
|
+
- Unit tests: 80%+ coverage
|
|
711
|
+
- Integration tests: Critical flows
|
|
712
|
+
- Architecture tests: When applicable
|
|
713
|
+
|
|
714
|
+
---
|
|
715
|
+
|
|
716
|
+
## PHASE 4: VERIFICACIÓN (Verify)
|
|
717
|
+
|
|
718
|
+
**Checklist:**
|
|
719
|
+
- [ ] Code compiles without errors
|
|
720
|
+
- [ ] All tests pass
|
|
721
|
+
- [ ] Linter passes
|
|
722
|
+
- [ ] Application starts correctly
|
|
723
|
+
- [ ] No regressions
|
|
724
|
+
|
|
725
|
+
**If something fails:** Fix → Re-verify → Don't proceed until green
|
|
726
|
+
|
|
727
|
+
---
|
|
728
|
+
|
|
729
|
+
## PHASE 5: REVISIÓN EXPERTA (Review)
|
|
730
|
+
|
|
731
|
+
1. **Clear mental context** - Forget implementation process
|
|
732
|
+
2. **Adopt expert role** based on work type:
|
|
733
|
+
- Architecture → Software Architect
|
|
734
|
+
- Backend → Senior Backend Developer
|
|
735
|
+
- Frontend → Senior Frontend Developer
|
|
736
|
+
- Security → Security Engineer
|
|
737
|
+
- Performance → Performance Engineer
|
|
738
|
+
- Database → DBA
|
|
739
|
+
- DevOps → DevOps Engineer
|
|
740
|
+
|
|
741
|
+
3. **Review from scratch, looking for:**
|
|
742
|
+
|
|
743
|
+
**CRITICAL (must fix):**
|
|
744
|
+
- Bugs, security vulnerabilities
|
|
745
|
+
- Architecture violations
|
|
746
|
+
- Severe performance issues
|
|
747
|
+
|
|
748
|
+
**RECOMMENDED (should fix):**
|
|
749
|
+
- Readability improvements
|
|
750
|
+
- Minor optimizations
|
|
751
|
+
- Missing best practices
|
|
752
|
+
|
|
753
|
+
**SUGGESTIONS (nice to have):**
|
|
754
|
+
- Optional refactorings
|
|
755
|
+
- Future improvements
|
|
756
|
+
|
|
757
|
+
---
|
|
758
|
+
|
|
759
|
+
## PHASE 6: REFINAMIENTO (Refine)
|
|
760
|
+
|
|
761
|
+
**Apply improvements in up to 3 cycles:**
|
|
762
|
+
|
|
763
|
+
- **Cycle 1:** Fix ALL critical issues
|
|
764
|
+
- **Cycle 2:** Apply recommended improvements
|
|
765
|
+
- **Cycle 3:** Final polish
|
|
766
|
+
|
|
767
|
+
**Completion criteria:**
|
|
768
|
+
- [ ] All CRITICAL issues resolved
|
|
769
|
+
- [ ] 80%+ RECOMMENDED issues resolved
|
|
770
|
+
- [ ] All tests pass
|
|
771
|
+
- [ ] Code compiles without warnings
|
|
772
|
+
- [ ] Application works correctly
|
|
773
|
+
|
|
774
|
+
---
|
|
775
|
+
|
|
776
|
+
## Quick Reference
|
|
777
|
+
|
|
778
|
+
\`\`\`
|
|
779
|
+
Developer Request
|
|
780
|
+
│
|
|
781
|
+
▼
|
|
782
|
+
┌──────────────┐
|
|
783
|
+
│ 1. CLARIFY │◄── Questions? Ask!
|
|
784
|
+
└──────────────┘
|
|
785
|
+
│
|
|
786
|
+
▼
|
|
787
|
+
┌──────────────┐
|
|
788
|
+
│ 2. PLAN │◄── Task checklist
|
|
789
|
+
└──────────────┘
|
|
790
|
+
│
|
|
791
|
+
▼
|
|
792
|
+
┌──────────────┐
|
|
793
|
+
│ 3. BUILD │◄── TDD: Test → Code → Refactor
|
|
794
|
+
└──────────────┘
|
|
795
|
+
│
|
|
796
|
+
▼
|
|
797
|
+
┌──────────────┐
|
|
798
|
+
│ 4. VERIFY │◄── All green?
|
|
799
|
+
└──────────────┘
|
|
800
|
+
│
|
|
801
|
+
▼
|
|
802
|
+
┌──────────────┐
|
|
803
|
+
│ 5. REVIEW │◄── Expert perspective
|
|
804
|
+
└──────────────┘
|
|
805
|
+
│
|
|
806
|
+
▼
|
|
807
|
+
┌──────────────┐
|
|
808
|
+
│ 6. REFINE │◄── Up to 3 cycles
|
|
809
|
+
└──────────────┘
|
|
810
|
+
│
|
|
811
|
+
▼
|
|
812
|
+
✅ Done
|
|
813
|
+
\`\`\``;
|
|
814
|
+
return { content: [{ type: 'text', text: workflow }] };
|
|
815
|
+
}
|
|
816
|
+
// ============================================================================
|
|
817
|
+
// AGENT MODE HANDLERS
|
|
818
|
+
// ============================================================================
|
|
819
|
+
async function handleGetFullContext(args) {
|
|
820
|
+
const { task_description, project_dir, profile: profileOverride } = FullContextInputSchema.parse(args);
|
|
821
|
+
// Classify task type
|
|
822
|
+
const taskType = classifyTaskType(task_description);
|
|
823
|
+
// Try to detect project stack if directory provided
|
|
824
|
+
let detectedStack = null;
|
|
825
|
+
let projectConfig = null;
|
|
826
|
+
if (project_dir) {
|
|
827
|
+
detectedStack = await detectProjectStack(project_dir);
|
|
828
|
+
projectConfig = await loadProjectConfig(project_dir);
|
|
829
|
+
}
|
|
830
|
+
// Determine profile to use (priority: override > project config > detected > default)
|
|
831
|
+
const profileId = profileOverride || projectConfig?.profile || detectedStack?.suggestedProfile || config.defaultProfile;
|
|
832
|
+
const profile = await getProfile(profileId);
|
|
833
|
+
if (!profile) {
|
|
834
|
+
return {
|
|
835
|
+
content: [{ type: 'text', text: `Profile not found: ${profileId}` }],
|
|
836
|
+
isError: true,
|
|
837
|
+
};
|
|
838
|
+
}
|
|
839
|
+
// Get guardrails for this task type
|
|
840
|
+
const guardrails = getGuardrails(taskType, projectConfig);
|
|
841
|
+
// Get project-specific rules
|
|
842
|
+
const projectRules = getProjectRules(taskType, projectConfig);
|
|
843
|
+
// Load standards
|
|
844
|
+
const standards = await loadStandards();
|
|
845
|
+
// Build comprehensive context
|
|
846
|
+
const lines = [
|
|
847
|
+
'# CORBAT AGENT CONTEXT',
|
|
848
|
+
'',
|
|
849
|
+
'> This context was auto-generated by corbat-mcp agent mode.',
|
|
850
|
+
'> Apply ALL guidelines below to your implementation.',
|
|
851
|
+
'',
|
|
852
|
+
'---',
|
|
853
|
+
'',
|
|
854
|
+
`## Task Analysis`,
|
|
855
|
+
'',
|
|
856
|
+
`**Task:** ${task_description}`,
|
|
857
|
+
`**Classified as:** ${taskType.toUpperCase()}`,
|
|
858
|
+
`**Profile:** ${profileId}`,
|
|
859
|
+
'',
|
|
860
|
+
];
|
|
861
|
+
// Add detected stack info if available
|
|
862
|
+
if (detectedStack) {
|
|
863
|
+
lines.push('## Detected Project Stack', '');
|
|
864
|
+
lines.push(`- **Language:** ${detectedStack.language}`);
|
|
865
|
+
if (detectedStack.framework)
|
|
866
|
+
lines.push(`- **Framework:** ${detectedStack.framework}`);
|
|
867
|
+
if (detectedStack.buildTool)
|
|
868
|
+
lines.push(`- **Build Tool:** ${detectedStack.buildTool}`);
|
|
869
|
+
if (detectedStack.testFramework)
|
|
870
|
+
lines.push(`- **Test Framework:** ${detectedStack.testFramework}`);
|
|
871
|
+
lines.push(`- **Confidence:** ${detectedStack.confidence}`);
|
|
872
|
+
lines.push('');
|
|
873
|
+
}
|
|
874
|
+
// Add guardrails
|
|
875
|
+
lines.push('---', '');
|
|
876
|
+
lines.push(formatGuardrailsAsMarkdown(guardrails));
|
|
877
|
+
lines.push('');
|
|
878
|
+
// Add project-specific rules if any
|
|
879
|
+
if (projectRules.length > 0) {
|
|
880
|
+
lines.push('---', '', '## Project-Specific Rules', '');
|
|
881
|
+
for (const rule of projectRules) {
|
|
882
|
+
lines.push(`- 📌 ${rule}`);
|
|
883
|
+
}
|
|
884
|
+
lines.push('');
|
|
885
|
+
}
|
|
886
|
+
// Add profile configuration
|
|
887
|
+
lines.push('---', '');
|
|
888
|
+
lines.push(formatProfileAsMarkdown(profileId, profile));
|
|
889
|
+
// Add relevant standards based on task type and detected stack
|
|
890
|
+
const relevantCategories = getRelevantCategories(taskType, detectedStack?.language);
|
|
891
|
+
const relevantStandards = standards.filter((s) => relevantCategories.some((cat) => s.category.toLowerCase().includes(cat.toLowerCase())));
|
|
892
|
+
if (relevantStandards.length > 0) {
|
|
893
|
+
lines.push('---', '', '## Relevant Standards Documentation', '');
|
|
894
|
+
for (const standard of relevantStandards.slice(0, 5)) {
|
|
895
|
+
lines.push(`### ${standard.name}`, '');
|
|
896
|
+
// Truncate long content
|
|
897
|
+
const content = standard.content.length > 2000 ? standard.content.slice(0, 2000) + '\n\n...(truncated)' : standard.content;
|
|
898
|
+
lines.push(content, '');
|
|
899
|
+
}
|
|
900
|
+
}
|
|
901
|
+
// Add workflow reminder
|
|
902
|
+
lines.push('---', '', '## Development Workflow Reminder', '');
|
|
903
|
+
lines.push('Follow the phases: **Clarify → Plan → Build (TDD) → Verify → Review → Refine**');
|
|
904
|
+
lines.push('');
|
|
905
|
+
lines.push('1. ❓ **CLARIFY** - Ask if requirements are unclear');
|
|
906
|
+
lines.push('2. 📋 **PLAN** - Create task checklist before coding');
|
|
907
|
+
lines.push('3. 🔨 **BUILD** - Use TDD: Test → Code → Refactor');
|
|
908
|
+
lines.push('4. ✅ **VERIFY** - Ensure all tests pass');
|
|
909
|
+
lines.push('5. 🔍 **REVIEW** - Self-review as expert');
|
|
910
|
+
lines.push('6. 🔄 **REFINE** - Fix issues in up to 3 cycles');
|
|
911
|
+
lines.push('');
|
|
912
|
+
return { content: [{ type: 'text', text: lines.join('\n') }] };
|
|
913
|
+
}
|
|
914
|
+
/**
|
|
915
|
+
* Get relevant documentation categories based on task type and language.
|
|
916
|
+
*/
|
|
917
|
+
function getRelevantCategories(taskType, language) {
|
|
918
|
+
const categories = ['clean-code'];
|
|
919
|
+
switch (taskType) {
|
|
920
|
+
case 'feature':
|
|
921
|
+
categories.push('architecture', 'testing');
|
|
922
|
+
break;
|
|
923
|
+
case 'bugfix':
|
|
924
|
+
categories.push('testing');
|
|
925
|
+
break;
|
|
926
|
+
case 'refactor':
|
|
927
|
+
categories.push('architecture', 'clean-code');
|
|
928
|
+
break;
|
|
929
|
+
case 'test':
|
|
930
|
+
categories.push('testing');
|
|
931
|
+
break;
|
|
932
|
+
case 'performance':
|
|
933
|
+
categories.push('observability');
|
|
934
|
+
break;
|
|
935
|
+
case 'security':
|
|
936
|
+
categories.push('security');
|
|
937
|
+
break;
|
|
938
|
+
case 'infrastructure':
|
|
939
|
+
categories.push('containerization', 'kubernetes', 'cicd');
|
|
940
|
+
break;
|
|
941
|
+
}
|
|
942
|
+
// Add language-specific categories
|
|
943
|
+
if (language?.toLowerCase().includes('java')) {
|
|
944
|
+
categories.push('spring-boot');
|
|
945
|
+
}
|
|
946
|
+
return [...new Set(categories)];
|
|
947
|
+
}
|
|
948
|
+
async function handleDetectProjectStack(args) {
|
|
949
|
+
const { project_dir } = DetectStackInputSchema.parse(args);
|
|
950
|
+
const stack = await detectProjectStack(project_dir);
|
|
951
|
+
if (!stack) {
|
|
952
|
+
return {
|
|
953
|
+
content: [
|
|
954
|
+
{
|
|
955
|
+
type: 'text',
|
|
956
|
+
text: `# Project Stack Detection\n\n**Status:** Unable to detect project stack\n\nNo recognizable configuration files found (package.json, pom.xml, pyproject.toml, etc.).\n\n**Suggestion:** Use the default profile or specify one manually.`,
|
|
957
|
+
},
|
|
958
|
+
],
|
|
959
|
+
};
|
|
960
|
+
}
|
|
961
|
+
const lines = [
|
|
962
|
+
'# Project Stack Detection',
|
|
963
|
+
'',
|
|
964
|
+
`**Confidence:** ${stack.confidence.toUpperCase()}`,
|
|
965
|
+
'',
|
|
966
|
+
'## Detected Stack',
|
|
967
|
+
'',
|
|
968
|
+
`| Property | Value |`,
|
|
969
|
+
`|----------|-------|`,
|
|
970
|
+
`| Language | ${stack.language} |`,
|
|
971
|
+
`| Framework | ${stack.framework || 'N/A'} |`,
|
|
972
|
+
`| Build Tool | ${stack.buildTool || 'N/A'} |`,
|
|
973
|
+
`| Test Framework | ${stack.testFramework || 'N/A'} |`,
|
|
974
|
+
'',
|
|
975
|
+
'## Recommendation',
|
|
976
|
+
'',
|
|
977
|
+
`**Suggested Profile:** \`${stack.suggestedProfile}\``,
|
|
978
|
+
'',
|
|
979
|
+
'## Detected Files',
|
|
980
|
+
'',
|
|
981
|
+
];
|
|
982
|
+
for (const file of stack.detectedFiles) {
|
|
983
|
+
lines.push(`- ${file}`);
|
|
984
|
+
}
|
|
985
|
+
return { content: [{ type: 'text', text: lines.join('\n') }] };
|
|
986
|
+
}
|
|
987
|
+
async function handleGetGuardrails(args) {
|
|
988
|
+
const { task_type, project_dir } = GuardrailsInputSchema.parse(args);
|
|
989
|
+
let projectConfig = null;
|
|
990
|
+
if (project_dir) {
|
|
991
|
+
projectConfig = await loadProjectConfig(project_dir);
|
|
992
|
+
}
|
|
993
|
+
const guardrails = getGuardrails(task_type, projectConfig);
|
|
994
|
+
return { content: [{ type: 'text', text: formatGuardrailsAsMarkdown(guardrails) }] };
|
|
995
|
+
}
|
|
996
|
+
async function handleValidateAgainstStandards(args) {
|
|
997
|
+
const { code, profile: profileId = config.defaultProfile, task_type } = ValidateInputSchema.parse(args);
|
|
998
|
+
const profile = await getProfile(profileId);
|
|
999
|
+
if (!profile) {
|
|
1000
|
+
return {
|
|
1001
|
+
content: [{ type: 'text', text: `Profile not found: ${profileId}` }],
|
|
1002
|
+
isError: true,
|
|
1003
|
+
};
|
|
1004
|
+
}
|
|
1005
|
+
// Get guardrails if task type specified
|
|
1006
|
+
const guardrails = task_type ? getGuardrails(task_type, null) : null;
|
|
1007
|
+
// Build validation prompt
|
|
1008
|
+
const lines = [
|
|
1009
|
+
'# Code Validation Against Standards',
|
|
1010
|
+
'',
|
|
1011
|
+
'## Code Provided',
|
|
1012
|
+
'',
|
|
1013
|
+
'```',
|
|
1014
|
+
code,
|
|
1015
|
+
'```',
|
|
1016
|
+
'',
|
|
1017
|
+
'## Validation Criteria',
|
|
1018
|
+
'',
|
|
1019
|
+
`**Profile:** ${profileId}`,
|
|
1020
|
+
'',
|
|
1021
|
+
];
|
|
1022
|
+
// Add code quality rules
|
|
1023
|
+
if (profile.codeQuality) {
|
|
1024
|
+
lines.push('### Code Quality Thresholds', '');
|
|
1025
|
+
lines.push(`- Max method lines: ${profile.codeQuality.maxMethodLines}`);
|
|
1026
|
+
lines.push(`- Max class lines: ${profile.codeQuality.maxClassLines}`);
|
|
1027
|
+
lines.push(`- Max parameters: ${profile.codeQuality.maxMethodParameters}`);
|
|
1028
|
+
lines.push(`- Min test coverage: ${profile.codeQuality.minimumTestCoverage}%`);
|
|
1029
|
+
lines.push('');
|
|
1030
|
+
}
|
|
1031
|
+
// Add guardrails if available
|
|
1032
|
+
if (guardrails) {
|
|
1033
|
+
lines.push(`### Guardrails for ${task_type?.toUpperCase()} task`, '');
|
|
1034
|
+
lines.push('**Must follow:**');
|
|
1035
|
+
for (const rule of guardrails.mandatory.slice(0, 5)) {
|
|
1036
|
+
lines.push(`- ${rule}`);
|
|
1037
|
+
}
|
|
1038
|
+
lines.push('');
|
|
1039
|
+
lines.push('**Should avoid:**');
|
|
1040
|
+
for (const rule of guardrails.avoid.slice(0, 5)) {
|
|
1041
|
+
lines.push(`- ${rule}`);
|
|
1042
|
+
}
|
|
1043
|
+
lines.push('');
|
|
1044
|
+
}
|
|
1045
|
+
// Add naming conventions
|
|
1046
|
+
if (profile.naming) {
|
|
1047
|
+
lines.push('### Naming Conventions', '');
|
|
1048
|
+
const naming = profile.naming;
|
|
1049
|
+
if (naming.general && typeof naming.general === 'object') {
|
|
1050
|
+
for (const [key, value] of Object.entries(naming.general)) {
|
|
1051
|
+
lines.push(`- **${key}**: ${value}`);
|
|
1052
|
+
}
|
|
1053
|
+
}
|
|
1054
|
+
lines.push('');
|
|
1055
|
+
}
|
|
1056
|
+
lines.push('---', '');
|
|
1057
|
+
lines.push('## Validation Instructions', '');
|
|
1058
|
+
lines.push('Review the code above against the criteria and identify:', '');
|
|
1059
|
+
lines.push('1. **CRITICAL issues** - Must be fixed (bugs, security, architecture violations)');
|
|
1060
|
+
lines.push('2. **WARNINGS** - Should be fixed (style, best practices)');
|
|
1061
|
+
lines.push('3. **SUGGESTIONS** - Nice to have improvements');
|
|
1062
|
+
lines.push('');
|
|
1063
|
+
lines.push('Provide a compliance score from 0-100 with justification.');
|
|
1064
|
+
return { content: [{ type: 'text', text: lines.join('\n') }] };
|
|
1065
|
+
}
|
|
1066
|
+
async function handleMakeTechnicalDecision(args) {
|
|
1067
|
+
const { category, context, project_dir } = TechnicalDecisionInputSchema.parse(args);
|
|
1068
|
+
let projectConfig = null;
|
|
1069
|
+
if (project_dir) {
|
|
1070
|
+
projectConfig = await loadProjectConfig(project_dir);
|
|
1071
|
+
}
|
|
1072
|
+
const decision = getTechnicalDecision(category, context, projectConfig);
|
|
1073
|
+
if (!decision) {
|
|
1074
|
+
return {
|
|
1075
|
+
content: [
|
|
1076
|
+
{
|
|
1077
|
+
type: 'text',
|
|
1078
|
+
text: `Unknown decision category: ${category}. Available categories: ${Object.keys(TECHNICAL_DECISIONS).join(', ')}`,
|
|
1079
|
+
},
|
|
1080
|
+
],
|
|
1081
|
+
isError: true,
|
|
1082
|
+
};
|
|
1083
|
+
}
|
|
1084
|
+
const lines = [
|
|
1085
|
+
`# Technical Decision: ${category.toUpperCase()}`,
|
|
1086
|
+
'',
|
|
1087
|
+
`## Context`,
|
|
1088
|
+
'',
|
|
1089
|
+
context,
|
|
1090
|
+
'',
|
|
1091
|
+
'---',
|
|
1092
|
+
'',
|
|
1093
|
+
'## Options',
|
|
1094
|
+
'',
|
|
1095
|
+
];
|
|
1096
|
+
for (const option of decision.options) {
|
|
1097
|
+
const isRecommended = option.name === decision.recommendation;
|
|
1098
|
+
lines.push(`### ${option.name}${isRecommended ? ' ⭐ RECOMMENDED' : ''}`, '');
|
|
1099
|
+
lines.push(option.description, '');
|
|
1100
|
+
lines.push('**Pros:**');
|
|
1101
|
+
for (const pro of option.pros) {
|
|
1102
|
+
lines.push(`- ✅ ${pro}`);
|
|
1103
|
+
}
|
|
1104
|
+
lines.push('');
|
|
1105
|
+
lines.push('**Cons:**');
|
|
1106
|
+
for (const con of option.cons) {
|
|
1107
|
+
lines.push(`- ❌ ${con}`);
|
|
1108
|
+
}
|
|
1109
|
+
lines.push('');
|
|
1110
|
+
lines.push('**Use when:**');
|
|
1111
|
+
for (const use of option.useWhen) {
|
|
1112
|
+
lines.push(`- ${use}`);
|
|
1113
|
+
}
|
|
1114
|
+
lines.push('');
|
|
1115
|
+
}
|
|
1116
|
+
lines.push('---', '', '## Recommendation', '');
|
|
1117
|
+
lines.push(`**${decision.recommendation}**`, '');
|
|
1118
|
+
lines.push(decision.reasoning);
|
|
1119
|
+
return { content: [{ type: 'text', text: lines.join('\n') }] };
|
|
1120
|
+
}
|
|
1121
|
+
async function handleLoadProjectConfig(args) {
|
|
1122
|
+
const { project_dir } = ProjectConfigInputSchema.parse(args);
|
|
1123
|
+
const projectConfig = await loadProjectConfig(project_dir);
|
|
1124
|
+
if (!projectConfig) {
|
|
1125
|
+
const exampleConfig = {
|
|
1126
|
+
profile: 'nodejs',
|
|
1127
|
+
autoInject: true,
|
|
1128
|
+
rules: {
|
|
1129
|
+
always: ['Use TypeScript strict mode', 'Prefer composition over inheritance'],
|
|
1130
|
+
onNewFile: ['Add license header', 'Export types first'],
|
|
1131
|
+
onTest: ['Use Arrange-Act-Assert pattern', 'One assertion per test'],
|
|
1132
|
+
onRefactor: ['Ensure all tests pass before and after'],
|
|
1133
|
+
},
|
|
1134
|
+
overrides: {
|
|
1135
|
+
maxMethodLines: 25,
|
|
1136
|
+
minimumTestCoverage: 90,
|
|
1137
|
+
},
|
|
1138
|
+
decisions: {
|
|
1139
|
+
database: 'PostgreSQL',
|
|
1140
|
+
cache: 'Redis',
|
|
1141
|
+
messaging: 'Kafka',
|
|
1142
|
+
},
|
|
1143
|
+
};
|
|
1144
|
+
return {
|
|
1145
|
+
content: [
|
|
1146
|
+
{
|
|
1147
|
+
type: 'text',
|
|
1148
|
+
text: `# Project Configuration
|
|
1149
|
+
|
|
1150
|
+
**Status:** No .corbat.json found in ${project_dir}
|
|
1151
|
+
|
|
1152
|
+
## How to Create a Project Configuration
|
|
1153
|
+
|
|
1154
|
+
Create a \`.corbat.json\` file in your project root:
|
|
1155
|
+
|
|
1156
|
+
\`\`\`json
|
|
1157
|
+
${JSON.stringify(exampleConfig, null, 2)}
|
|
1158
|
+
\`\`\`
|
|
1159
|
+
|
|
1160
|
+
### Configuration Options
|
|
1161
|
+
|
|
1162
|
+
| Option | Description |
|
|
1163
|
+
|--------|-------------|
|
|
1164
|
+
| \`profile\` | Override default profile |
|
|
1165
|
+
| \`autoInject\` | Enable auto context injection |
|
|
1166
|
+
| \`rules.always\` | Rules applied to all tasks |
|
|
1167
|
+
| \`rules.onNewFile\` | Rules for new file creation |
|
|
1168
|
+
| \`rules.onTest\` | Rules for test-related tasks |
|
|
1169
|
+
| \`rules.onRefactor\` | Rules for refactoring tasks |
|
|
1170
|
+
| \`overrides\` | Override code quality thresholds |
|
|
1171
|
+
| \`decisions\` | Pre-made technical decisions |`,
|
|
1172
|
+
},
|
|
1173
|
+
],
|
|
1174
|
+
};
|
|
1175
|
+
}
|
|
1176
|
+
const lines = ['# Project Configuration', '', `**Source:** ${project_dir}/.corbat.json`, ''];
|
|
1177
|
+
if (projectConfig.profile) {
|
|
1178
|
+
lines.push(`## Profile Override`, '', `Using profile: \`${projectConfig.profile}\``, '');
|
|
1179
|
+
}
|
|
1180
|
+
lines.push(`## Auto Inject`, '', `Enabled: ${projectConfig.autoInject}`, '');
|
|
1181
|
+
if (projectConfig.rules) {
|
|
1182
|
+
lines.push('## Custom Rules', '');
|
|
1183
|
+
if (projectConfig.rules.always?.length) {
|
|
1184
|
+
lines.push('### Always Apply', '');
|
|
1185
|
+
for (const rule of projectConfig.rules.always) {
|
|
1186
|
+
lines.push(`- ${rule}`);
|
|
1187
|
+
}
|
|
1188
|
+
lines.push('');
|
|
1189
|
+
}
|
|
1190
|
+
if (projectConfig.rules.onNewFile?.length) {
|
|
1191
|
+
lines.push('### On New File', '');
|
|
1192
|
+
for (const rule of projectConfig.rules.onNewFile) {
|
|
1193
|
+
lines.push(`- ${rule}`);
|
|
1194
|
+
}
|
|
1195
|
+
lines.push('');
|
|
1196
|
+
}
|
|
1197
|
+
if (projectConfig.rules.onTest?.length) {
|
|
1198
|
+
lines.push('### On Test Tasks', '');
|
|
1199
|
+
for (const rule of projectConfig.rules.onTest) {
|
|
1200
|
+
lines.push(`- ${rule}`);
|
|
1201
|
+
}
|
|
1202
|
+
lines.push('');
|
|
1203
|
+
}
|
|
1204
|
+
if (projectConfig.rules.onRefactor?.length) {
|
|
1205
|
+
lines.push('### On Refactor Tasks', '');
|
|
1206
|
+
for (const rule of projectConfig.rules.onRefactor) {
|
|
1207
|
+
lines.push(`- ${rule}`);
|
|
1208
|
+
}
|
|
1209
|
+
lines.push('');
|
|
1210
|
+
}
|
|
1211
|
+
}
|
|
1212
|
+
if (projectConfig.overrides) {
|
|
1213
|
+
lines.push('## Code Quality Overrides', '');
|
|
1214
|
+
for (const [key, value] of Object.entries(projectConfig.overrides)) {
|
|
1215
|
+
if (value !== undefined) {
|
|
1216
|
+
lines.push(`- **${key}:** ${value}`);
|
|
1217
|
+
}
|
|
1218
|
+
}
|
|
1219
|
+
lines.push('');
|
|
1220
|
+
}
|
|
1221
|
+
if (projectConfig.decisions) {
|
|
1222
|
+
lines.push('## Technical Decisions', '');
|
|
1223
|
+
for (const [category, decision] of Object.entries(projectConfig.decisions)) {
|
|
1224
|
+
lines.push(`- **${category}:** ${decision}`);
|
|
1225
|
+
}
|
|
1226
|
+
lines.push('');
|
|
1227
|
+
}
|
|
1228
|
+
return { content: [{ type: 'text', text: lines.join('\n') }] };
|
|
1229
|
+
}
|
|
1230
|
+
//# sourceMappingURL=tools-legacy.js.map
|