@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.
Files changed (89) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +371 -0
  3. package/assets/demo.gif +0 -0
  4. package/dist/agent.d.ts +53 -0
  5. package/dist/agent.d.ts.map +1 -0
  6. package/dist/agent.js +629 -0
  7. package/dist/agent.js.map +1 -0
  8. package/dist/cli/init.d.ts +3 -0
  9. package/dist/cli/init.d.ts.map +1 -0
  10. package/dist/cli/init.js +651 -0
  11. package/dist/cli/init.js.map +1 -0
  12. package/dist/config.d.ts +73 -0
  13. package/dist/config.d.ts.map +1 -0
  14. package/dist/config.js +105 -0
  15. package/dist/config.js.map +1 -0
  16. package/dist/index.d.ts +3 -0
  17. package/dist/index.d.ts.map +1 -0
  18. package/dist/index.js +73 -0
  19. package/dist/index.js.map +1 -0
  20. package/dist/profiles.d.ts +39 -0
  21. package/dist/profiles.d.ts.map +1 -0
  22. package/dist/profiles.js +526 -0
  23. package/dist/profiles.js.map +1 -0
  24. package/dist/prompts-legacy.d.ts +25 -0
  25. package/dist/prompts-legacy.d.ts.map +1 -0
  26. package/dist/prompts-legacy.js +600 -0
  27. package/dist/prompts-legacy.js.map +1 -0
  28. package/dist/prompts-v2.d.ts +30 -0
  29. package/dist/prompts-v2.d.ts.map +1 -0
  30. package/dist/prompts-v2.js +310 -0
  31. package/dist/prompts-v2.js.map +1 -0
  32. package/dist/prompts.d.ts +30 -0
  33. package/dist/prompts.d.ts.map +1 -0
  34. package/dist/prompts.js +310 -0
  35. package/dist/prompts.js.map +1 -0
  36. package/dist/resources.d.ts +18 -0
  37. package/dist/resources.d.ts.map +1 -0
  38. package/dist/resources.js +95 -0
  39. package/dist/resources.js.map +1 -0
  40. package/dist/tools-legacy.d.ts +196 -0
  41. package/dist/tools-legacy.d.ts.map +1 -0
  42. package/dist/tools-legacy.js +1230 -0
  43. package/dist/tools-legacy.js.map +1 -0
  44. package/dist/tools-v2.d.ts +92 -0
  45. package/dist/tools-v2.d.ts.map +1 -0
  46. package/dist/tools-v2.js +410 -0
  47. package/dist/tools-v2.js.map +1 -0
  48. package/dist/tools.d.ts +92 -0
  49. package/dist/tools.d.ts.map +1 -0
  50. package/dist/tools.js +410 -0
  51. package/dist/tools.js.map +1 -0
  52. package/dist/types.d.ts +3054 -0
  53. package/dist/types.d.ts.map +1 -0
  54. package/dist/types.js +515 -0
  55. package/dist/types.js.map +1 -0
  56. package/dist/utils/index.d.ts +6 -0
  57. package/dist/utils/index.d.ts.map +1 -0
  58. package/dist/utils/index.js +5 -0
  59. package/dist/utils/index.js.map +1 -0
  60. package/dist/utils/retry.d.ts +44 -0
  61. package/dist/utils/retry.d.ts.map +1 -0
  62. package/dist/utils/retry.js +74 -0
  63. package/dist/utils/retry.js.map +1 -0
  64. package/package.json +79 -0
  65. package/profiles/README.md +199 -0
  66. package/profiles/custom/.gitkeep +2 -0
  67. package/profiles/templates/_template.yaml +159 -0
  68. package/profiles/templates/angular.yaml +494 -0
  69. package/profiles/templates/java-spring-backend.yaml +512 -0
  70. package/profiles/templates/minimal.yaml +102 -0
  71. package/profiles/templates/nodejs.yaml +338 -0
  72. package/profiles/templates/python.yaml +340 -0
  73. package/profiles/templates/react.yaml +331 -0
  74. package/profiles/templates/vue.yaml +598 -0
  75. package/standards/architecture/ddd.md +173 -0
  76. package/standards/architecture/hexagonal.md +97 -0
  77. package/standards/cicd/github-actions.md +567 -0
  78. package/standards/clean-code/naming.md +175 -0
  79. package/standards/clean-code/principles.md +179 -0
  80. package/standards/containerization/dockerfile.md +419 -0
  81. package/standards/database/selection-guide.md +443 -0
  82. package/standards/documentation/guidelines.md +189 -0
  83. package/standards/event-driven/domain-events.md +527 -0
  84. package/standards/kubernetes/deployment.md +518 -0
  85. package/standards/observability/guidelines.md +665 -0
  86. package/standards/project-setup/initialization-checklist.md +650 -0
  87. package/standards/spring-boot/best-practices.md +598 -0
  88. package/standards/testing/guidelines.md +559 -0
  89. 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