mcp-adr-analysis-server 2.7.39 → 2.7.40
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/dist/.tsbuildinfo +1 -1
- package/dist/src/index.d.ts +6 -276
- package/dist/src/index.d.ts.map +1 -1
- package/dist/src/index.js +9 -8361
- package/dist/src/index.js.map +1 -1
- package/dist/src/mcp-adr-analysis-server.d.ts +320 -0
- package/dist/src/mcp-adr-analysis-server.d.ts.map +1 -0
- package/dist/src/mcp-adr-analysis-server.js +4700 -0
- package/dist/src/mcp-adr-analysis-server.js.map +1 -0
- package/dist/src/tools/mcp-tool-schemas.d.ts +9 -0
- package/dist/src/tools/mcp-tool-schemas.d.ts.map +1 -0
- package/dist/src/tools/mcp-tool-schemas.js +3371 -0
- package/dist/src/tools/mcp-tool-schemas.js.map +1 -0
- package/dist/src/tools/tool-catalog.d.ts.map +1 -1
- package/dist/src/tools/tool-catalog.js +24 -0
- package/dist/src/tools/tool-catalog.js.map +1 -1
- package/dist/src/tools/tool-dispatch.d.ts +9 -0
- package/dist/src/tools/tool-dispatch.d.ts.map +1 -0
- package/dist/src/tools/tool-dispatch.js +264 -0
- package/dist/src/tools/tool-dispatch.js.map +1 -0
- package/dist/src/tools/tool-dispatcher.d.ts +2 -4
- package/dist/src/tools/tool-dispatcher.d.ts.map +1 -1
- package/dist/src/tools/tool-dispatcher.js +4 -60
- package/dist/src/tools/tool-dispatcher.js.map +1 -1
- package/dist/src/types/memory-entities.d.ts +4 -4
- package/package.json +1 -1
|
@@ -0,0 +1,4700 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* MCP ADR Analysis Server
|
|
3
|
+
* Main entry point for the Model Context Protocol server
|
|
4
|
+
*
|
|
5
|
+
* This server provides Tools, Resources, and Prompts for analyzing
|
|
6
|
+
* Architectural Decision Records and project architecture.
|
|
7
|
+
*/
|
|
8
|
+
import { Server } from '@modelcontextprotocol/sdk/server/index.js';
|
|
9
|
+
import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';
|
|
10
|
+
import { CallToolRequestSchema, ListToolsRequestSchema, ListResourcesRequestSchema, ReadResourceRequestSchema, ListPromptsRequestSchema, GetPromptRequestSchema, } from '@modelcontextprotocol/sdk/types.js';
|
|
11
|
+
import { readFileSync } from 'fs';
|
|
12
|
+
import { join } from 'path';
|
|
13
|
+
import { getCurrentDirCompat } from './utils/directory-compat.js';
|
|
14
|
+
import { McpAdrError } from './types/index.js';
|
|
15
|
+
import { maskMcpResponse, createMaskingConfig, } from './utils/output-masking.js';
|
|
16
|
+
import { loadConfig, validateProjectPath, createLogger, printConfigSummary, } from './utils/config.js';
|
|
17
|
+
import { KnowledgeGraphManager } from './utils/knowledge-graph-manager.js';
|
|
18
|
+
import { getEnhancedModeDefault, getKnowledgeEnhancementDefault, } from './utils/test-aware-defaults.js';
|
|
19
|
+
import { StateReinforcementManager } from './utils/state-reinforcement-manager.js';
|
|
20
|
+
import { ConversationMemoryManager } from './utils/conversation-memory-manager.js';
|
|
21
|
+
import { MemoryEntityManager } from './utils/memory-entity-manager.js';
|
|
22
|
+
import { RootManager } from './utils/root-manager.js';
|
|
23
|
+
import { ServerContextGenerator } from './utils/server-context-generator.js';
|
|
24
|
+
import { createNoOpContext } from './types/tool-context.js';
|
|
25
|
+
import { getToolListForMCP } from './tools/tool-dispatcher.js';
|
|
26
|
+
import { dispatchTool } from './tools/tool-dispatch.js';
|
|
27
|
+
import { shouldUseCEMCPDirective, getCEMCPDirective, formatDirectiveResponse, } from './tools/ce-mcp-tools.js';
|
|
28
|
+
import { loadAIConfig, isCEMCPEnabled } from './config/ai-config.js';
|
|
29
|
+
/**
|
|
30
|
+
* Get version from package.json
|
|
31
|
+
*/
|
|
32
|
+
export function getPackageVersion() {
|
|
33
|
+
try {
|
|
34
|
+
// Handle both Jest environment and normal execution
|
|
35
|
+
const currentDir = getCurrentDirCompat();
|
|
36
|
+
// Strategy 1: Try multiple possible locations for package.json
|
|
37
|
+
const possiblePaths = [
|
|
38
|
+
join(currentDir, 'package.json'),
|
|
39
|
+
join(currentDir, '..', 'package.json'),
|
|
40
|
+
join(currentDir, '..', '..', 'package.json'),
|
|
41
|
+
join(process.cwd(), 'package.json'),
|
|
42
|
+
];
|
|
43
|
+
for (const packageJsonPath of possiblePaths) {
|
|
44
|
+
try {
|
|
45
|
+
const packageJson = JSON.parse(readFileSync(packageJsonPath, 'utf-8'));
|
|
46
|
+
if (packageJson.name === 'mcp-adr-analysis-server') {
|
|
47
|
+
return packageJson.version;
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
catch {
|
|
51
|
+
// Try next path
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
// Strategy 2: Use process.env.npm_package_version if available (during npm scripts)
|
|
55
|
+
if (process.env['npm_package_version']) {
|
|
56
|
+
return process.env['npm_package_version'];
|
|
57
|
+
}
|
|
58
|
+
// Final fallback: Use generic version instead of hardcoded specific version
|
|
59
|
+
// This prevents the need to update this code when version changes
|
|
60
|
+
return 'unknown'; // Generic fallback - no longer tied to specific version
|
|
61
|
+
}
|
|
62
|
+
catch (error) {
|
|
63
|
+
console.error('Error reading package.json:', error);
|
|
64
|
+
return 'unknown'; // Generic fallback - no longer tied to specific version
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
/**
|
|
68
|
+
* Server configuration
|
|
69
|
+
*/
|
|
70
|
+
const SERVER_INFO = {
|
|
71
|
+
name: 'mcp-adr-analysis-server',
|
|
72
|
+
version: getPackageVersion(),
|
|
73
|
+
description: 'MCP server for analyzing Architectural Decision Records and project architecture',
|
|
74
|
+
};
|
|
75
|
+
/**
|
|
76
|
+
* Main server class
|
|
77
|
+
*/
|
|
78
|
+
export class McpAdrAnalysisServer {
|
|
79
|
+
server;
|
|
80
|
+
maskingConfig;
|
|
81
|
+
config;
|
|
82
|
+
logger;
|
|
83
|
+
kgManager;
|
|
84
|
+
stateReinforcementManager;
|
|
85
|
+
conversationMemoryManager;
|
|
86
|
+
memoryEntityManager;
|
|
87
|
+
rootManager;
|
|
88
|
+
contextGenerator;
|
|
89
|
+
constructor() {
|
|
90
|
+
// Load and validate configuration
|
|
91
|
+
this.config = loadConfig();
|
|
92
|
+
this.logger = createLogger(this.config);
|
|
93
|
+
this.kgManager = new KnowledgeGraphManager();
|
|
94
|
+
this.stateReinforcementManager = new StateReinforcementManager(this.kgManager);
|
|
95
|
+
this.conversationMemoryManager = new ConversationMemoryManager(this.kgManager);
|
|
96
|
+
this.memoryEntityManager = new MemoryEntityManager();
|
|
97
|
+
// Initialize root manager for file access control
|
|
98
|
+
this.rootManager = new RootManager(this.config.projectPath, this.config.adrDirectory);
|
|
99
|
+
// Initialize server context generator
|
|
100
|
+
this.contextGenerator = new ServerContextGenerator();
|
|
101
|
+
// Print configuration summary
|
|
102
|
+
printConfigSummary(this.config);
|
|
103
|
+
// Note: Validation will be done during startup
|
|
104
|
+
this.server = new Server(SERVER_INFO, {
|
|
105
|
+
capabilities: {
|
|
106
|
+
tools: {},
|
|
107
|
+
resources: {},
|
|
108
|
+
prompts: {},
|
|
109
|
+
},
|
|
110
|
+
});
|
|
111
|
+
this.maskingConfig = createMaskingConfig();
|
|
112
|
+
this.setupHandlers();
|
|
113
|
+
}
|
|
114
|
+
/**
|
|
115
|
+
* Validate configuration and project setup
|
|
116
|
+
*/
|
|
117
|
+
async validateConfiguration() {
|
|
118
|
+
try {
|
|
119
|
+
await validateProjectPath(this.config.projectPath);
|
|
120
|
+
this.logger.info(`Project path validated: ${this.config.projectPath}`);
|
|
121
|
+
}
|
|
122
|
+
catch (error) {
|
|
123
|
+
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
124
|
+
this.logger.error(`Configuration validation failed: ${errorMessage}`);
|
|
125
|
+
throw error;
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
/**
|
|
129
|
+
* Public health check method for testing
|
|
130
|
+
*/
|
|
131
|
+
async healthCheck() {
|
|
132
|
+
await this.validateConfiguration();
|
|
133
|
+
this.logger.info('Health check completed successfully');
|
|
134
|
+
}
|
|
135
|
+
/**
|
|
136
|
+
* Setup MCP protocol handlers
|
|
137
|
+
*
|
|
138
|
+
* @description Configures all Model Context Protocol request handlers for the ADR Analysis Server.
|
|
139
|
+
* Implements the complete MCP specification including tools, resources, and prompts.
|
|
140
|
+
*
|
|
141
|
+
* @private
|
|
142
|
+
* @since 2.0.0
|
|
143
|
+
* @category MCP Protocol
|
|
144
|
+
*/
|
|
145
|
+
setupHandlers() {
|
|
146
|
+
/**
|
|
147
|
+
* List Tools Handler - MCP Protocol Endpoint
|
|
148
|
+
*
|
|
149
|
+
* @description Returns the complete catalog of available tools for ADR analysis,
|
|
150
|
+
* research, validation, and deployment operations. Each tool includes comprehensive
|
|
151
|
+
* input schemas and descriptions for client integration.
|
|
152
|
+
*
|
|
153
|
+
* @returns {Promise<{tools: Array}>} Complete tool catalog with schemas
|
|
154
|
+
*
|
|
155
|
+
* @example
|
|
156
|
+
* ```typescript
|
|
157
|
+
* // MCP Client usage
|
|
158
|
+
* const tools = await mcpClient.listTools();
|
|
159
|
+
* console.log(tools.tools.length); // 20+ available tools
|
|
160
|
+
*
|
|
161
|
+
* // Find specific tool
|
|
162
|
+
* const researchTool = tools.tools.find(t => t.name === 'perform_research');
|
|
163
|
+
* console.log(researchTool.description); // Tool description
|
|
164
|
+
* ```
|
|
165
|
+
*
|
|
166
|
+
* @mcp-endpoint
|
|
167
|
+
* @category Tools
|
|
168
|
+
*/
|
|
169
|
+
this.server.setRequestHandler(ListToolsRequestSchema, async () => {
|
|
170
|
+
return getToolListForMCP({ mode: 'full' });
|
|
171
|
+
});
|
|
172
|
+
/**
|
|
173
|
+
* Call Tool Handler - MCP Protocol Endpoint
|
|
174
|
+
*/
|
|
175
|
+
this.server.setRequestHandler(CallToolRequestSchema, async (request) => {
|
|
176
|
+
const { name, arguments: args } = request.params;
|
|
177
|
+
// Create context for progress notifications and logging
|
|
178
|
+
const context = {
|
|
179
|
+
info: (message) => {
|
|
180
|
+
this.logger.info(message);
|
|
181
|
+
// Note: MCP progress notifications will be available in future SDK versions
|
|
182
|
+
// For now, we log to server console for visibility
|
|
183
|
+
},
|
|
184
|
+
report_progress: (progress, total) => {
|
|
185
|
+
const percentage = total ? Math.round((progress / total) * 100) : progress;
|
|
186
|
+
this.logger.info(`Progress: ${percentage}%${total ? ` (${progress}/${total})` : ''}`);
|
|
187
|
+
},
|
|
188
|
+
warn: (message) => {
|
|
189
|
+
this.logger.warn(message);
|
|
190
|
+
},
|
|
191
|
+
error: (message) => {
|
|
192
|
+
this.logger.error(message);
|
|
193
|
+
},
|
|
194
|
+
};
|
|
195
|
+
try {
|
|
196
|
+
const safeArgs = args || {};
|
|
197
|
+
// CE-MCP Mode: Check if tool should return directive instead of executing
|
|
198
|
+
const aiConfig = loadAIConfig();
|
|
199
|
+
if (isCEMCPEnabled(aiConfig) &&
|
|
200
|
+
shouldUseCEMCPDirective(name, { mode: aiConfig.executionMode })) {
|
|
201
|
+
const directive = getCEMCPDirective(name, safeArgs);
|
|
202
|
+
if (directive) {
|
|
203
|
+
this.logger.info(`[CE-MCP] Returning directive for tool: ${name}`);
|
|
204
|
+
const directiveResponse = formatDirectiveResponse(directive);
|
|
205
|
+
// Record BEFORE returning. This early return skips the dispatch
|
|
206
|
+
// switch below and, with it, the trackToolExecution call on the
|
|
207
|
+
// success path -- so every tool in CE_MCP_DIRECTIVE_TOOLS was
|
|
208
|
+
// invisible to usage tracking whenever CE-MCP mode was on. All
|
|
209
|
+
// twelve of them, including `perform_research`, whose disposition
|
|
210
|
+
// ADR-023 defers *pending usage data*. See #1489.
|
|
211
|
+
//
|
|
212
|
+
// Deliberately not fatal: a directive is the tool's real answer, and
|
|
213
|
+
// failing to record it must never withhold it. trackToolExecution
|
|
214
|
+
// already swallows and warns internally; the catch here covers a
|
|
215
|
+
// throw before that boundary.
|
|
216
|
+
try {
|
|
217
|
+
await this.trackToolExecution(name, args, directiveResponse, true);
|
|
218
|
+
}
|
|
219
|
+
catch (trackingError) {
|
|
220
|
+
this.logger.warn(`[CE-MCP] Usage tracking failed for ${name}: ${trackingError instanceof Error ? trackingError.message : String(trackingError)}`);
|
|
221
|
+
}
|
|
222
|
+
return directiveResponse;
|
|
223
|
+
}
|
|
224
|
+
// Fall through to legacy execution if no directive available
|
|
225
|
+
this.logger.info(`[CE-MCP] No directive available for ${name}, using legacy path`);
|
|
226
|
+
}
|
|
227
|
+
const response = await dispatchTool(this, name, safeArgs, context);
|
|
228
|
+
// Track tool execution in knowledge graph
|
|
229
|
+
await this.trackToolExecution(name, args, response, true);
|
|
230
|
+
// Apply state reinforcement (Phase 2: Context Decay Mitigation) and content masking
|
|
231
|
+
// Also record conversation turn (Phase 3: Structured External Memory)
|
|
232
|
+
return await this.enrichResponseWithStateReinforcement(response, name, args);
|
|
233
|
+
}
|
|
234
|
+
catch (error) {
|
|
235
|
+
// Track failed execution
|
|
236
|
+
await this.trackToolExecution(name, args, {}, false, error instanceof Error ? error.message : String(error));
|
|
237
|
+
if (error instanceof McpAdrError) {
|
|
238
|
+
throw error;
|
|
239
|
+
}
|
|
240
|
+
throw new McpAdrError(`Tool execution failed: ${error instanceof Error ? error.message : String(error)}`, 'TOOL_EXECUTION_ERROR');
|
|
241
|
+
}
|
|
242
|
+
});
|
|
243
|
+
/**
|
|
244
|
+
* List Resources Handler - MCP Protocol Endpoint
|
|
245
|
+
*
|
|
246
|
+
* @description Returns available resources for client access including the
|
|
247
|
+
* architectural knowledge graph and project analysis data. Resources provide
|
|
248
|
+
* read-only access to server-managed data structures.
|
|
249
|
+
*
|
|
250
|
+
* @returns {Promise<{resources: Array}>} Available resources with URIs and descriptions
|
|
251
|
+
*
|
|
252
|
+
* @example
|
|
253
|
+
* ```typescript
|
|
254
|
+
* // List available resources
|
|
255
|
+
* const resources = await mcpClient.listResources();
|
|
256
|
+
* console.log(resources.resources.length); // Available resources
|
|
257
|
+
*
|
|
258
|
+
* // Find knowledge graph resource
|
|
259
|
+
* const kgResource = resources.resources.find(r =>
|
|
260
|
+
* r.uri === 'adr://architectural_knowledge_graph'
|
|
261
|
+
* );
|
|
262
|
+
* console.log(kgResource.name); // "Architectural Knowledge Graph"
|
|
263
|
+
* ```
|
|
264
|
+
*
|
|
265
|
+
* @mcp-endpoint
|
|
266
|
+
* @category Resources
|
|
267
|
+
*/
|
|
268
|
+
this.server.setRequestHandler(ListResourcesRequestSchema, async () => {
|
|
269
|
+
return {
|
|
270
|
+
resources: [
|
|
271
|
+
// Existing resources (refactored to return data)
|
|
272
|
+
{
|
|
273
|
+
uri: 'adr://architectural_knowledge_graph',
|
|
274
|
+
name: 'Architectural Knowledge Graph',
|
|
275
|
+
description: 'Complete architectural knowledge graph with technologies, patterns, and relationships',
|
|
276
|
+
mimeType: 'application/json',
|
|
277
|
+
},
|
|
278
|
+
{
|
|
279
|
+
uri: 'adr://analysis_report',
|
|
280
|
+
name: 'Analysis Report',
|
|
281
|
+
description: 'Comprehensive project analysis report with metrics and recommendations',
|
|
282
|
+
mimeType: 'application/json',
|
|
283
|
+
},
|
|
284
|
+
{
|
|
285
|
+
uri: 'adr://adr_list',
|
|
286
|
+
name: 'ADR List',
|
|
287
|
+
description: 'List of all Architectural Decision Records with status and metadata',
|
|
288
|
+
mimeType: 'application/json',
|
|
289
|
+
},
|
|
290
|
+
// NEW Phase 1 Resources
|
|
291
|
+
{
|
|
292
|
+
uri: 'adr://todo_list',
|
|
293
|
+
name: 'Todo List',
|
|
294
|
+
description: 'Current project task list with status, priorities, and dependencies',
|
|
295
|
+
mimeType: 'application/json',
|
|
296
|
+
},
|
|
297
|
+
{
|
|
298
|
+
uri: 'adr://research_index',
|
|
299
|
+
name: 'Research Index',
|
|
300
|
+
description: 'Index of all research documents and findings with metadata',
|
|
301
|
+
mimeType: 'application/json',
|
|
302
|
+
},
|
|
303
|
+
{
|
|
304
|
+
uri: 'adr://rule_catalog',
|
|
305
|
+
name: 'Rule Catalog',
|
|
306
|
+
description: 'Catalog of all architectural and validation rules from ADRs and code',
|
|
307
|
+
mimeType: 'application/json',
|
|
308
|
+
},
|
|
309
|
+
{
|
|
310
|
+
uri: 'adr://rule_generation',
|
|
311
|
+
name: 'Rule Generation',
|
|
312
|
+
description: 'AI-powered rule generation from ADRs and code patterns. Supports query parameters: ?operation=generate|validate|create_set, ?source=adrs|patterns|both, ?knowledge=true|false, ?enhanced=true|false, ?format=json|yaml|both, ?comprehensive=true|false',
|
|
313
|
+
mimeType: 'application/json',
|
|
314
|
+
},
|
|
315
|
+
{
|
|
316
|
+
uri: 'adr://project_status',
|
|
317
|
+
name: 'Project Status',
|
|
318
|
+
description: 'Current project status and health metrics aggregated from all sources',
|
|
319
|
+
mimeType: 'application/json',
|
|
320
|
+
},
|
|
321
|
+
// NEW Phase 2 Templated Resources
|
|
322
|
+
{
|
|
323
|
+
uri: 'adr://adr/{id}',
|
|
324
|
+
name: 'ADR by ID',
|
|
325
|
+
description: 'Individual Architectural Decision Record by ID or title match',
|
|
326
|
+
mimeType: 'application/json',
|
|
327
|
+
},
|
|
328
|
+
{
|
|
329
|
+
uri: 'adr://research/{topic}',
|
|
330
|
+
name: 'Research by Topic',
|
|
331
|
+
description: 'Research documents filtered by topic with full content',
|
|
332
|
+
mimeType: 'application/json',
|
|
333
|
+
},
|
|
334
|
+
{
|
|
335
|
+
uri: 'adr://todo/{task_id}',
|
|
336
|
+
name: 'Todo by Task ID',
|
|
337
|
+
description: 'Individual task details by ID or title match with dependencies and history',
|
|
338
|
+
mimeType: 'application/json',
|
|
339
|
+
},
|
|
340
|
+
{
|
|
341
|
+
uri: 'adr://rule/{rule_id}',
|
|
342
|
+
name: 'Rule by ID',
|
|
343
|
+
description: 'Individual architectural rule by ID or name match with violations and usage stats',
|
|
344
|
+
mimeType: 'application/json',
|
|
345
|
+
},
|
|
346
|
+
// NEW Phase 3 Advanced Resources
|
|
347
|
+
{
|
|
348
|
+
uri: 'adr://deployment_status',
|
|
349
|
+
name: 'Deployment Status',
|
|
350
|
+
description: 'Current deployment state with health checks, build status, and readiness score',
|
|
351
|
+
mimeType: 'application/json',
|
|
352
|
+
},
|
|
353
|
+
{
|
|
354
|
+
uri: 'adr://environment_analysis',
|
|
355
|
+
name: 'Environment Analysis',
|
|
356
|
+
description: 'System environment details including platform, dependencies, and capabilities',
|
|
357
|
+
mimeType: 'application/json',
|
|
358
|
+
},
|
|
359
|
+
{
|
|
360
|
+
uri: 'adr://memory_snapshots',
|
|
361
|
+
name: 'Memory Snapshots',
|
|
362
|
+
description: 'Knowledge graph snapshots with statistics, insights, and relationship data',
|
|
363
|
+
mimeType: 'application/json',
|
|
364
|
+
},
|
|
365
|
+
{
|
|
366
|
+
uri: 'adr://project_metrics',
|
|
367
|
+
name: 'Project Metrics',
|
|
368
|
+
description: 'Code metrics and quality scores including codebase stats, quality assessment, and git metrics',
|
|
369
|
+
mimeType: 'application/json',
|
|
370
|
+
},
|
|
371
|
+
{
|
|
372
|
+
uri: 'adr://technology/{name}',
|
|
373
|
+
name: 'Technology by Name',
|
|
374
|
+
description: 'Individual technology analysis by name with usage, relationships, and adoption status',
|
|
375
|
+
mimeType: 'application/json',
|
|
376
|
+
},
|
|
377
|
+
{
|
|
378
|
+
uri: 'adr://pattern/{name}',
|
|
379
|
+
name: 'Pattern by Name',
|
|
380
|
+
description: 'Individual pattern analysis by name with quality metrics, relationships, and examples',
|
|
381
|
+
mimeType: 'application/json',
|
|
382
|
+
},
|
|
383
|
+
// NEW Phase 4 Final Resources
|
|
384
|
+
{
|
|
385
|
+
uri: 'adr://deployment_history',
|
|
386
|
+
name: 'Deployment History',
|
|
387
|
+
description: 'Historical deployment data with trends, failure analysis, and patterns. Supports query parameters: ?period=7d|30d|90d|1y|all, ?environment=production|staging|development|all, ?includeFailures=true|false, ?includeMetrics=true|false, ?format=summary|detailed',
|
|
388
|
+
mimeType: 'application/json',
|
|
389
|
+
},
|
|
390
|
+
{
|
|
391
|
+
uri: 'adr://release_history',
|
|
392
|
+
name: 'Release History',
|
|
393
|
+
description: 'Release tracking state with releases mapped to ADRs, milestones, and project metadata. Shows release timeline, ADR-to-release mappings with confidence scores, and unmapped ADRs.',
|
|
394
|
+
mimeType: 'application/json',
|
|
395
|
+
},
|
|
396
|
+
{
|
|
397
|
+
uri: 'adr://code_quality',
|
|
398
|
+
name: 'Code Quality',
|
|
399
|
+
description: 'Comprehensive code quality assessment with metrics, issues, and recommendations. Supports query parameters: ?scope=full|changes|critical, ?includeMetrics=true|false, ?includeRecommendations=true|false, ?threshold=0-100, ?format=summary|detailed',
|
|
400
|
+
mimeType: 'application/json',
|
|
401
|
+
},
|
|
402
|
+
// NEW Phase 5 Validated Pattern Resources
|
|
403
|
+
{
|
|
404
|
+
uri: 'adr://validated_patterns',
|
|
405
|
+
name: 'Validated Patterns Catalog',
|
|
406
|
+
description: 'Complete catalog of validated deployment patterns for different platforms (OpenShift, Kubernetes, Docker, Node.js, Python, MCP, A2A) with bill of materials, deployment phases, validation checks, and authoritative sources',
|
|
407
|
+
mimeType: 'application/json',
|
|
408
|
+
},
|
|
409
|
+
{
|
|
410
|
+
uri: 'adr://validated_pattern/{platform}',
|
|
411
|
+
name: 'Validated Pattern by Platform',
|
|
412
|
+
description: 'Individual validated pattern by platform type (openshift, kubernetes, docker, nodejs, python, mcp, a2a) with complete bill of materials, deployment phases, validation checks, health checks, and authoritative sources for LLM research',
|
|
413
|
+
mimeType: 'application/json',
|
|
414
|
+
},
|
|
415
|
+
{
|
|
416
|
+
uri: 'adr://pattern_sources/{platform}',
|
|
417
|
+
name: 'Pattern Authoritative Sources',
|
|
418
|
+
description: 'Authoritative documentation and repository sources for a specific platform pattern, prioritized by importance with query instructions for LLMs',
|
|
419
|
+
mimeType: 'application/json',
|
|
420
|
+
},
|
|
421
|
+
{
|
|
422
|
+
uri: 'adr://pattern_base_code/{platform}',
|
|
423
|
+
name: 'Pattern Base Code Repository',
|
|
424
|
+
description: 'Base code repository information for a platform pattern including URL, integration instructions, required files, and script entrypoint',
|
|
425
|
+
mimeType: 'application/json',
|
|
426
|
+
},
|
|
427
|
+
// NEW Knowledge Graph Resource (ADR-018)
|
|
428
|
+
{
|
|
429
|
+
uri: 'knowledge://graph',
|
|
430
|
+
name: 'Knowledge Graph',
|
|
431
|
+
description: 'Read-only knowledge graph structure with nodes (intents, ADRs, tools, code files) and edges (relationships). Zero token cost for querying graph state. Use update_knowledge tool to modify.',
|
|
432
|
+
mimeType: 'application/json',
|
|
433
|
+
},
|
|
434
|
+
],
|
|
435
|
+
};
|
|
436
|
+
});
|
|
437
|
+
/**
|
|
438
|
+
* Read Resource Handler - MCP Protocol Endpoint
|
|
439
|
+
*
|
|
440
|
+
* @description Reads specific resource content by URI. Provides access to
|
|
441
|
+
* architectural knowledge graphs, project analysis data, and other server-managed
|
|
442
|
+
* resources with appropriate content masking applied.
|
|
443
|
+
*
|
|
444
|
+
* @param {ReadResourceRequest} request - MCP resource read request
|
|
445
|
+
* @param {string} request.params.uri - Resource URI to read
|
|
446
|
+
*
|
|
447
|
+
* @returns {Promise<ReadResourceResult>} Resource content with metadata
|
|
448
|
+
*
|
|
449
|
+
* @throws {McpAdrError} When resource URI is invalid or access fails
|
|
450
|
+
*
|
|
451
|
+
* @example
|
|
452
|
+
* ```typescript
|
|
453
|
+
* // Read knowledge graph resource
|
|
454
|
+
* const kgData = await mcpClient.readResource(
|
|
455
|
+
* 'adr://architectural_knowledge_graph'
|
|
456
|
+
* );
|
|
457
|
+
* console.log(kgData.contents); // Knowledge graph JSON
|
|
458
|
+
* ```
|
|
459
|
+
*
|
|
460
|
+
* @mcp-endpoint
|
|
461
|
+
* @category Resources
|
|
462
|
+
*/
|
|
463
|
+
this.server.setRequestHandler(ReadResourceRequestSchema, async (request) => {
|
|
464
|
+
const { uri } = request.params;
|
|
465
|
+
try {
|
|
466
|
+
const response = await this.readResource(uri);
|
|
467
|
+
return await this.applyOutputMasking(response);
|
|
468
|
+
}
|
|
469
|
+
catch (error) {
|
|
470
|
+
if (error instanceof McpAdrError) {
|
|
471
|
+
throw error;
|
|
472
|
+
}
|
|
473
|
+
throw new McpAdrError(`Resource reading failed: ${error instanceof Error ? error.message : String(error)}`, 'RESOURCE_ERROR');
|
|
474
|
+
}
|
|
475
|
+
});
|
|
476
|
+
/**
|
|
477
|
+
* List Prompts Handler - MCP Protocol Endpoint
|
|
478
|
+
*
|
|
479
|
+
* @description Returns available prompt templates for ADR analysis, research,
|
|
480
|
+
* and architectural decision support. Prompts can be executed directly or
|
|
481
|
+
* used as templates for custom implementations.
|
|
482
|
+
*
|
|
483
|
+
* @returns {Promise<{prompts: Array}>} Available prompt templates with metadata
|
|
484
|
+
*
|
|
485
|
+
* @example
|
|
486
|
+
* ```typescript
|
|
487
|
+
* // List available prompts
|
|
488
|
+
* const prompts = await mcpClient.listPrompts();
|
|
489
|
+
* console.log(prompts.prompts.length); // Available prompt templates
|
|
490
|
+
*
|
|
491
|
+
* // Find ADR analysis prompt
|
|
492
|
+
* const adrPrompt = prompts.prompts.find(p =>
|
|
493
|
+
* p.name === 'adr_analysis_prompt'
|
|
494
|
+
* );
|
|
495
|
+
* console.log(adrPrompt.description); // Prompt description
|
|
496
|
+
* ```
|
|
497
|
+
*
|
|
498
|
+
* @mcp-endpoint
|
|
499
|
+
* @category Prompts
|
|
500
|
+
*/
|
|
501
|
+
this.server.setRequestHandler(ListPromptsRequestSchema, async () => {
|
|
502
|
+
const { allPrompts } = await import('./prompts/index.js');
|
|
503
|
+
return {
|
|
504
|
+
prompts: allPrompts.map(prompt => ({
|
|
505
|
+
name: prompt.name,
|
|
506
|
+
description: prompt.description,
|
|
507
|
+
arguments: prompt.arguments,
|
|
508
|
+
})),
|
|
509
|
+
};
|
|
510
|
+
});
|
|
511
|
+
/**
|
|
512
|
+
* Get Prompt Handler - MCP Protocol Endpoint
|
|
513
|
+
*
|
|
514
|
+
* @description Executes specific prompt templates with provided arguments.
|
|
515
|
+
* Returns formatted prompts ready for AI execution or further processing.
|
|
516
|
+
* Supports dynamic argument injection and template customization.
|
|
517
|
+
*
|
|
518
|
+
* @param {GetPromptRequest} request - MCP prompt execution request
|
|
519
|
+
* @param {string} request.params.name - Prompt template name
|
|
520
|
+
* @param {Object} request.params.arguments - Template-specific arguments
|
|
521
|
+
*
|
|
522
|
+
* @returns {Promise<GetPromptResult>} Formatted prompt with metadata
|
|
523
|
+
*
|
|
524
|
+
* @throws {McpAdrError} When prompt template is not found or arguments are invalid
|
|
525
|
+
*
|
|
526
|
+
* @example
|
|
527
|
+
* ```typescript
|
|
528
|
+
* // Execute ADR analysis prompt
|
|
529
|
+
* const prompt = await mcpClient.getPrompt('adr_analysis_prompt', {
|
|
530
|
+
* adrPath: 'docs/adrs/0001-auth.md',
|
|
531
|
+
* projectContext: 'microservices architecture'
|
|
532
|
+
* });
|
|
533
|
+
*
|
|
534
|
+
* console.log(prompt.messages); // Formatted prompt messages
|
|
535
|
+
* ```
|
|
536
|
+
*
|
|
537
|
+
* @example
|
|
538
|
+
* ```typescript
|
|
539
|
+
* // Execute research prompt
|
|
540
|
+
* const researchPrompt = await mcpClient.getPrompt('research_question_prompt', {
|
|
541
|
+
* domain: 'authentication',
|
|
542
|
+
* complexity: 'advanced'
|
|
543
|
+
* });
|
|
544
|
+
*
|
|
545
|
+
* console.log(researchPrompt.messages[0].content); // Research prompt
|
|
546
|
+
* ```
|
|
547
|
+
*
|
|
548
|
+
* @mcp-endpoint
|
|
549
|
+
* @category Prompts
|
|
550
|
+
* @category Execution
|
|
551
|
+
*/
|
|
552
|
+
this.server.setRequestHandler(GetPromptRequestSchema, async (request) => {
|
|
553
|
+
const { name, arguments: args } = request.params;
|
|
554
|
+
try {
|
|
555
|
+
const { allPrompts } = await import('./prompts/index.js');
|
|
556
|
+
const prompt = allPrompts.find(p => p.name === name);
|
|
557
|
+
if (!prompt) {
|
|
558
|
+
throw new McpAdrError(`Unknown prompt: ${name}`, 'UNKNOWN_PROMPT');
|
|
559
|
+
}
|
|
560
|
+
// Simple template rendering (replace {{variable}} with values)
|
|
561
|
+
let renderedTemplate = prompt.template;
|
|
562
|
+
if (args) {
|
|
563
|
+
for (const [key, value] of Object.entries(args)) {
|
|
564
|
+
const regex = new RegExp(`{{${key}}}`, 'g');
|
|
565
|
+
renderedTemplate = renderedTemplate.replace(regex, String(value));
|
|
566
|
+
}
|
|
567
|
+
}
|
|
568
|
+
const response = {
|
|
569
|
+
description: prompt.description,
|
|
570
|
+
messages: [
|
|
571
|
+
{
|
|
572
|
+
role: 'user',
|
|
573
|
+
content: {
|
|
574
|
+
type: 'text',
|
|
575
|
+
text: renderedTemplate,
|
|
576
|
+
},
|
|
577
|
+
},
|
|
578
|
+
],
|
|
579
|
+
};
|
|
580
|
+
return await this.applyOutputMasking(response);
|
|
581
|
+
}
|
|
582
|
+
catch (error) {
|
|
583
|
+
if (error instanceof McpAdrError) {
|
|
584
|
+
throw error;
|
|
585
|
+
}
|
|
586
|
+
throw new McpAdrError(`Prompt execution failed: ${error instanceof Error ? error.message : String(error)}`, 'PROMPT_EXECUTION_ERROR');
|
|
587
|
+
}
|
|
588
|
+
});
|
|
589
|
+
}
|
|
590
|
+
/**
|
|
591
|
+
* Tool implementations
|
|
592
|
+
*/
|
|
593
|
+
async checkAIExecutionStatus(_args) {
|
|
594
|
+
try {
|
|
595
|
+
const { getAIExecutionStatus } = await import('./utils/prompt-execution.js');
|
|
596
|
+
const status = getAIExecutionStatus();
|
|
597
|
+
return {
|
|
598
|
+
content: [
|
|
599
|
+
{
|
|
600
|
+
type: 'text',
|
|
601
|
+
text: `# AI Execution Status Diagnostic
|
|
602
|
+
|
|
603
|
+
> **Note**: As of Phase 5, this server uses CE-MCP (Claude-Enriched MCP) mode by default.
|
|
604
|
+
> In CE-MCP mode, tools return orchestration directives that the host LLM executes directly,
|
|
605
|
+
> eliminating the need for external API calls. The configuration below applies to legacy mode only.
|
|
606
|
+
|
|
607
|
+
## Current Configuration
|
|
608
|
+
- **AI Execution Enabled**: ${status.isEnabled ? '✅ YES' : '❌ NO'}
|
|
609
|
+
- **Has API Key**: ${status.hasApiKey ? '✅ YES' : '❌ NO'}
|
|
610
|
+
- **Execution Mode**: ${status.executionMode}
|
|
611
|
+
- **AI Model**: ${status.model}
|
|
612
|
+
|
|
613
|
+
${
|
|
614
|
+
// CE-MCP is the DEFAULT mode and needs no API key. Reporting the absence of
|
|
615
|
+
// one as an "Issue Detected" -- immediately after saying no external API call
|
|
616
|
+
// is needed -- told every new user to go and buy a key they do not need.
|
|
617
|
+
// Legacy configuration is only a problem for someone who asked for it. (#1414)
|
|
618
|
+
status.executionMode === 'ce-mcp'
|
|
619
|
+
? `## ✅ Running in CE-MCP mode
|
|
620
|
+
|
|
621
|
+
No API key is required. Tools return orchestration directives that your host LLM
|
|
622
|
+
executes directly, which is why **AI Execution Enabled: NO** above is expected and
|
|
623
|
+
correct rather than a fault.
|
|
624
|
+
|
|
625
|
+
Note that only some tools currently return a directive; the rest return their
|
|
626
|
+
result directly. See ADR-014 and ADR-021.
|
|
627
|
+
|
|
628
|
+
Legacy OpenRouter execution is off by design. You only need the configuration
|
|
629
|
+
below if you deliberately want that older path.`
|
|
630
|
+
: status.reason
|
|
631
|
+
? `## ⚠️ Issue Detected
|
|
632
|
+
**Problem**: ${status.reason}
|
|
633
|
+
|
|
634
|
+
## Solution
|
|
635
|
+
${!status.hasApiKey
|
|
636
|
+
? `
|
|
637
|
+
1. Get an OpenRouter API key from https://openrouter.ai/keys
|
|
638
|
+
2. Add it to your MCP configuration:
|
|
639
|
+
\`\`\`json
|
|
640
|
+
{
|
|
641
|
+
"mcpServers": {
|
|
642
|
+
"adr-analysis": {
|
|
643
|
+
"command": "mcp-adr-analysis-server",
|
|
644
|
+
"env": {
|
|
645
|
+
"OPENROUTER_API_KEY": "your_api_key_here",
|
|
646
|
+
"EXECUTION_MODE": "full",
|
|
647
|
+
"AI_MODEL": "anthropic/claude-3-sonnet"
|
|
648
|
+
}
|
|
649
|
+
}
|
|
650
|
+
}
|
|
651
|
+
}
|
|
652
|
+
\`\`\`
|
|
653
|
+
3. Restart your MCP client (Claude Desktop, etc.)
|
|
654
|
+
`
|
|
655
|
+
: status.executionMode !== 'full'
|
|
656
|
+
? `
|
|
657
|
+
1. Update your MCP configuration to set EXECUTION_MODE to "full":
|
|
658
|
+
\`\`\`json
|
|
659
|
+
{
|
|
660
|
+
"mcpServers": {
|
|
661
|
+
"adr-analysis": {
|
|
662
|
+
"env": {
|
|
663
|
+
"EXECUTION_MODE": "full"
|
|
664
|
+
}
|
|
665
|
+
}
|
|
666
|
+
}
|
|
667
|
+
}
|
|
668
|
+
\`\`\`
|
|
669
|
+
2. Restart your MCP client
|
|
670
|
+
`
|
|
671
|
+
: ''}`
|
|
672
|
+
: `## ✅ Configuration Looks Good!
|
|
673
|
+
|
|
674
|
+
AI execution is properly configured. Tools should return actual results instead of prompts.
|
|
675
|
+
|
|
676
|
+
If you're still seeing prompts instead of results, try:
|
|
677
|
+
1. Restart your MCP client
|
|
678
|
+
2. Check your OpenRouter API key has sufficient credits
|
|
679
|
+
3. Verify network connectivity to OpenRouter.ai`}
|
|
680
|
+
|
|
681
|
+
## Environment Variables Expected
|
|
682
|
+
- **OPENROUTER_API_KEY**: Your OpenRouter API key
|
|
683
|
+
- **EXECUTION_MODE**: Set to "full" for AI execution
|
|
684
|
+
- **AI_MODEL**: AI model to use (optional, defaults to claude-3-sonnet)
|
|
685
|
+
|
|
686
|
+
## Testing
|
|
687
|
+
After fixing the configuration, try calling \`suggest_adrs\` - it should return actual ADR suggestions instead of prompts.
|
|
688
|
+
`,
|
|
689
|
+
},
|
|
690
|
+
],
|
|
691
|
+
};
|
|
692
|
+
}
|
|
693
|
+
catch (error) {
|
|
694
|
+
return {
|
|
695
|
+
content: [
|
|
696
|
+
{
|
|
697
|
+
type: 'text',
|
|
698
|
+
text: `# AI Execution Status Check Failed
|
|
699
|
+
|
|
700
|
+
**Error**: ${error instanceof Error ? error.message : String(error)}
|
|
701
|
+
|
|
702
|
+
This diagnostic tool helps identify why tools return prompts instead of actual results.
|
|
703
|
+
|
|
704
|
+
## Manual Check
|
|
705
|
+
Verify these environment variables are set in your MCP configuration:
|
|
706
|
+
- OPENROUTER_API_KEY
|
|
707
|
+
- EXECUTION_MODE=full
|
|
708
|
+
- AI_MODEL (optional)
|
|
709
|
+
`,
|
|
710
|
+
},
|
|
711
|
+
],
|
|
712
|
+
};
|
|
713
|
+
}
|
|
714
|
+
}
|
|
715
|
+
async getWorkflowGuidance(args) {
|
|
716
|
+
const { goal, projectContext, availableAssets = [], timeframe = 'thorough_review', primaryConcerns = [], } = args;
|
|
717
|
+
try {
|
|
718
|
+
const workflowPrompt = `
|
|
719
|
+
# Workflow Guidance & Tool Recommendation System
|
|
720
|
+
|
|
721
|
+
## User Context Analysis
|
|
722
|
+
- **Goal**: ${goal}
|
|
723
|
+
- **Project Context**: ${projectContext}
|
|
724
|
+
- **Available Assets**: ${availableAssets.length > 0 ? availableAssets.join(', ') : 'None specified'}
|
|
725
|
+
- **Timeframe**: ${timeframe}
|
|
726
|
+
- **Primary Concerns**: ${primaryConcerns.length > 0 ? primaryConcerns.join(', ') : 'General analysis'}
|
|
727
|
+
|
|
728
|
+
## Available MCP Tools (24 Total)
|
|
729
|
+
|
|
730
|
+
### 🎯 **Core Analysis Tools** (AI-Powered ✅)
|
|
731
|
+
1. **analyze_project_ecosystem** - Comprehensive technology and pattern detection
|
|
732
|
+
2. **get_architectural_context** - Generate intelligent architectural insights + ADR setup
|
|
733
|
+
3. **generate_adrs_from_prd** - Convert requirements to structured ADRs
|
|
734
|
+
4. **analyze_content_security** - Detect sensitive information patterns
|
|
735
|
+
|
|
736
|
+
### 📋 **ADR Management Tools** (AI-Powered ✅)
|
|
737
|
+
5. **suggest_adrs** - Auto-suggest ADRs from implicit decisions
|
|
738
|
+
6. **generate_adr_from_decision** - Create ADRs from specific decisions
|
|
739
|
+
7. **discover_existing_adrs** - Intelligent ADR discovery and analysis
|
|
740
|
+
|
|
741
|
+
### 🔍 **Research & Documentation Tools** (AI-Powered ✅)
|
|
742
|
+
8. **generate_research_questions** - Create context-aware research questions
|
|
743
|
+
9. **incorporate_research** - Integrate research findings into decisions
|
|
744
|
+
10. **create_research_template** - Generate research documentation templates
|
|
745
|
+
|
|
746
|
+
### 🛡️ **Security & Compliance Tools** (AI-Powered ✅)
|
|
747
|
+
11. **generate_content_masking** - Intelligent content masking and protection
|
|
748
|
+
12. **configure_custom_patterns** - Customize security and masking settings
|
|
749
|
+
13. **apply_basic_content_masking** - Basic content masking (fallback)
|
|
750
|
+
14. **validate_content_masking** - Validate masking effectiveness
|
|
751
|
+
|
|
752
|
+
### 🏗️ **Rule & Governance Tools** (AI-Powered ✅)
|
|
753
|
+
16. **generate_rules** - Extract architectural rules from ADRs
|
|
754
|
+
17. **validate_rules** - Validate code against architectural rules
|
|
755
|
+
18. **create_rule_set** - Create comprehensive rule management systems
|
|
756
|
+
|
|
757
|
+
### 🚀 **Deployment & Environment Tools** (AI-Powered ✅)
|
|
758
|
+
19. **analyze_environment** - Environment analysis and optimization
|
|
759
|
+
20. **analyze_deployment_progress** - Deployment tracking and verification
|
|
760
|
+
|
|
761
|
+
### ⚙️ **Utility & Management Tools**
|
|
762
|
+
21. **manage_cache** - Cache management and optimization
|
|
763
|
+
22. **configure_output_masking** - Configure global output masking
|
|
764
|
+
23. **request_action_confirmation** - Interactive user confirmation workflows
|
|
765
|
+
24. **get_workflow_guidance** - This tool - intelligent workflow advisor
|
|
766
|
+
|
|
767
|
+
## Workflow Recommendation Instructions
|
|
768
|
+
|
|
769
|
+
Based on the user's goal, project context, available assets, timeframe, and concerns, provide:
|
|
770
|
+
|
|
771
|
+
### 1. **Recommended Tool Sequence**
|
|
772
|
+
Provide a step-by-step workflow with:
|
|
773
|
+
- **Tool Name**: Exact tool to call
|
|
774
|
+
- **Purpose**: Why this tool is needed
|
|
775
|
+
- **Expected Outcome**: What it will deliver
|
|
776
|
+
- **Parameters**: Suggested parameters for the tool call
|
|
777
|
+
- **Success Criteria**: How to know it worked
|
|
778
|
+
|
|
779
|
+
### 2. **Alternative Workflows**
|
|
780
|
+
Provide 2-3 alternative approaches based on:
|
|
781
|
+
- Different time constraints
|
|
782
|
+
- Different priorities
|
|
783
|
+
- Different starting points
|
|
784
|
+
|
|
785
|
+
### 3. **Expected Timeline & Effort**
|
|
786
|
+
For each recommended workflow:
|
|
787
|
+
- **Estimated Time**: How long each step takes
|
|
788
|
+
- **Effort Level**: Low/Medium/High effort required
|
|
789
|
+
- **Dependencies**: Which steps must be completed first
|
|
790
|
+
|
|
791
|
+
### 4. **Success Metrics**
|
|
792
|
+
Define how to measure success:
|
|
793
|
+
- **Immediate Indicators**: Quick wins and early signals
|
|
794
|
+
- **Progress Milestones**: Key checkpoints
|
|
795
|
+
- **Final Outcomes**: Ultimate success criteria
|
|
796
|
+
|
|
797
|
+
### 5. **Common Pitfalls & Tips**
|
|
798
|
+
- **What to Avoid**: Common mistakes in this workflow
|
|
799
|
+
- **Pro Tips**: Best practices for maximum effectiveness
|
|
800
|
+
- **Troubleshooting**: What to do if steps fail
|
|
801
|
+
|
|
802
|
+
## Common Workflow Patterns
|
|
803
|
+
|
|
804
|
+
### **New Project Setup**
|
|
805
|
+
1. analyze_project_ecosystem → 2. get_architectural_context → 3. suggest_adrs → 4. generate_adr_from_decision
|
|
806
|
+
|
|
807
|
+
### **Existing Project Analysis**
|
|
808
|
+
1. discover_existing_adrs → 2. get_architectural_context → 3. validate_rules
|
|
809
|
+
|
|
810
|
+
### **Security Audit**
|
|
811
|
+
1. analyze_content_security → 2. generate_content_masking → 3. configure_custom_patterns → 4. validate_content_masking
|
|
812
|
+
|
|
813
|
+
### **PRD to Implementation**
|
|
814
|
+
1. generate_adrs_from_prd → 2. analyze_deployment_progress
|
|
815
|
+
|
|
816
|
+
### **Legacy Modernization**
|
|
817
|
+
1. analyze_project_ecosystem → 2. get_architectural_context → 3. suggest_adrs → 4. generate_rules → 5. validate_rules
|
|
818
|
+
|
|
819
|
+
## Output Format
|
|
820
|
+
|
|
821
|
+
Provide a comprehensive workflow guide that includes:
|
|
822
|
+
|
|
823
|
+
1. **🎯 Recommended Primary Workflow** (step-by-step with tool calls)
|
|
824
|
+
2. **🔄 Alternative Approaches** (2-3 different paths)
|
|
825
|
+
3. **⏱️ Timeline & Effort Estimates** (realistic expectations)
|
|
826
|
+
4. **📊 Success Metrics** (how to measure progress)
|
|
827
|
+
5. **💡 Pro Tips & Best Practices** (maximize effectiveness)
|
|
828
|
+
6. **⚠️ Common Pitfalls** (what to avoid)
|
|
829
|
+
|
|
830
|
+
Make the guidance **actionable, specific, and outcome-focused** so the user can immediately start executing the recommended workflow.
|
|
831
|
+
`;
|
|
832
|
+
// Execute the workflow guidance with AI if enabled
|
|
833
|
+
const { executePromptWithFallback, formatMCPResponse } = await import('./utils/prompt-execution.js');
|
|
834
|
+
const executionResult = await executePromptWithFallback(workflowPrompt, 'Analyze the user context and provide intelligent workflow guidance with specific tool recommendations.', {
|
|
835
|
+
temperature: 0.1,
|
|
836
|
+
maxTokens: 6000,
|
|
837
|
+
systemPrompt: `You are an expert workflow advisor for the MCP ADR Analysis Server.
|
|
838
|
+
Your role is to analyze user goals and project context, then recommend the optimal sequence of tools to achieve their objectives efficiently.
|
|
839
|
+
Provide specific, actionable guidance with clear tool sequences, expected outcomes, and success criteria.
|
|
840
|
+
Focus on practical workflows that deliver measurable results.`,
|
|
841
|
+
});
|
|
842
|
+
if (executionResult.isAIGenerated) {
|
|
843
|
+
// AI execution successful - return actual workflow guidance
|
|
844
|
+
return formatMCPResponse({
|
|
845
|
+
...executionResult,
|
|
846
|
+
content: `# Workflow Guidance & Tool Recommendations
|
|
847
|
+
|
|
848
|
+
## Your Context
|
|
849
|
+
- **Goal**: ${goal}
|
|
850
|
+
- **Project Context**: ${projectContext}
|
|
851
|
+
- **Available Assets**: ${availableAssets.length > 0 ? availableAssets.join(', ') : 'None specified'}
|
|
852
|
+
- **Timeframe**: ${timeframe}
|
|
853
|
+
- **Primary Concerns**: ${primaryConcerns.length > 0 ? primaryConcerns.join(', ') : 'General analysis'}
|
|
854
|
+
|
|
855
|
+
## AI-Generated Workflow Guidance
|
|
856
|
+
|
|
857
|
+
${executionResult.content}
|
|
858
|
+
|
|
859
|
+
## Quick Reference: Available Tools
|
|
860
|
+
|
|
861
|
+
**Core Analysis**: analyze_project_ecosystem, get_architectural_context, generate_adrs_from_prd, analyze_content_security
|
|
862
|
+
**ADR Management**: suggest_adrs, generate_adr_from_decision, discover_existing_adrs
|
|
863
|
+
**Security**: generate_content_masking, configure_custom_patterns, validate_content_masking
|
|
864
|
+
**Governance**: generate_rules, validate_rules, create_rule_set
|
|
865
|
+
**Environment**: analyze_environment, analyze_deployment_progress
|
|
866
|
+
**Utilities**: manage_cache, configure_output_masking, check_ai_execution_status
|
|
867
|
+
|
|
868
|
+
## Next Steps
|
|
869
|
+
|
|
870
|
+
1. **Start with the recommended primary workflow** above
|
|
871
|
+
2. **Call the first tool** with the suggested parameters
|
|
872
|
+
3. **Review the results** and proceed to the next step
|
|
873
|
+
4. **Track progress** using the success metrics provided
|
|
874
|
+
5. **Adjust as needed** based on your specific findings
|
|
875
|
+
|
|
876
|
+
This guidance is tailored to your specific context and goals for maximum effectiveness!
|
|
877
|
+
`,
|
|
878
|
+
});
|
|
879
|
+
}
|
|
880
|
+
else {
|
|
881
|
+
// Fallback to prompt-only mode
|
|
882
|
+
return {
|
|
883
|
+
content: [
|
|
884
|
+
{
|
|
885
|
+
type: 'text',
|
|
886
|
+
text: workflowPrompt,
|
|
887
|
+
},
|
|
888
|
+
],
|
|
889
|
+
};
|
|
890
|
+
}
|
|
891
|
+
}
|
|
892
|
+
catch (error) {
|
|
893
|
+
throw new McpAdrError(`Failed to generate workflow guidance: ${error instanceof Error ? error.message : String(error)}`, 'WORKFLOW_ERROR');
|
|
894
|
+
}
|
|
895
|
+
}
|
|
896
|
+
async getDevelopmentGuidance(args) {
|
|
897
|
+
const { developmentPhase, adrsToImplement = [], technologyStack = [], currentProgress = '', teamContext = { size: 'small_team', experienceLevel: 'mixed' }, timeline = '', focusAreas = [], } = args;
|
|
898
|
+
try {
|
|
899
|
+
// Use actual ADR discovery if ADRs are specified
|
|
900
|
+
let adrAnalysisPrompt = '';
|
|
901
|
+
if (adrsToImplement.length > 0) {
|
|
902
|
+
const { getAdrDirectoryPath } = await import('./utils/config.js');
|
|
903
|
+
const { discoverAdrsInDirectory } = await import('./utils/adr-discovery.js');
|
|
904
|
+
const absoluteAdrPath = getAdrDirectoryPath(this.config);
|
|
905
|
+
const discoveryResult = await discoverAdrsInDirectory(absoluteAdrPath, this.config.projectPath, {
|
|
906
|
+
includeContent: true,
|
|
907
|
+
includeTimeline: false,
|
|
908
|
+
});
|
|
909
|
+
// Filter ADRs to only those specified for implementation
|
|
910
|
+
const targetAdrs = discoveryResult.adrs.filter(adr => adrsToImplement.some((target) => adr.title.toLowerCase().includes(target.toLowerCase()) ||
|
|
911
|
+
adr.filename.toLowerCase().includes(target.toLowerCase())));
|
|
912
|
+
adrAnalysisPrompt = `
|
|
913
|
+
## ADR Analysis for Implementation
|
|
914
|
+
|
|
915
|
+
**ADRs to Implement**: ${adrsToImplement.join(', ')}
|
|
916
|
+
**ADR Directory**: ${absoluteAdrPath}
|
|
917
|
+
**Found ${targetAdrs.length} matching ADRs**
|
|
918
|
+
|
|
919
|
+
${targetAdrs
|
|
920
|
+
.map(adr => `
|
|
921
|
+
### ${adr.title}
|
|
922
|
+
- **File**: ${adr.filename}
|
|
923
|
+
- **Status**: ${adr.status}
|
|
924
|
+
- **Context**: ${adr.context}
|
|
925
|
+
- **Decision**: ${adr.decision}
|
|
926
|
+
- **Consequences**: ${adr.consequences}
|
|
927
|
+
`)
|
|
928
|
+
.join('\n')}
|
|
929
|
+
`;
|
|
930
|
+
}
|
|
931
|
+
const developmentPrompt = `
|
|
932
|
+
# Development Guidance & Implementation Roadmap
|
|
933
|
+
|
|
934
|
+
## Development Context
|
|
935
|
+
- **Development Phase**: ${developmentPhase}
|
|
936
|
+
- **Technology Stack**: ${technologyStack.length > 0 ? technologyStack.join(', ') : 'Not specified'}
|
|
937
|
+
- **Current Progress**: ${currentProgress || 'Starting fresh'}
|
|
938
|
+
- **Team Size**: ${teamContext.size}
|
|
939
|
+
- **Team Experience**: ${teamContext.experienceLevel}
|
|
940
|
+
- **Timeline**: ${timeline || 'Not specified'}
|
|
941
|
+
- **Focus Areas**: ${focusAreas.length > 0 ? focusAreas.join(', ') : 'General development'}
|
|
942
|
+
|
|
943
|
+
${adrAnalysisPrompt}
|
|
944
|
+
|
|
945
|
+
## Development Guidance Instructions
|
|
946
|
+
|
|
947
|
+
Based on the development context, ADRs to implement, and technology stack, provide comprehensive development guidance including:
|
|
948
|
+
|
|
949
|
+
### 1. **Implementation Roadmap**
|
|
950
|
+
Create a detailed development plan with:
|
|
951
|
+
- **Phase-by-Phase Breakdown**: Logical development phases
|
|
952
|
+
- **Task Prioritization**: Order tasks by dependencies and impact
|
|
953
|
+
- **Milestone Definition**: Clear checkpoints and deliverables
|
|
954
|
+
- **Risk Assessment**: Potential blockers and mitigation strategies
|
|
955
|
+
|
|
956
|
+
### 2. **Code Structure & Architecture**
|
|
957
|
+
Provide specific guidance on:
|
|
958
|
+
- **Project Structure**: How to organize code files and directories
|
|
959
|
+
- **Module Architecture**: How to structure components/modules
|
|
960
|
+
- **Design Patterns**: Which patterns to use and where
|
|
961
|
+
- **Code Organization**: Separation of concerns and layering
|
|
962
|
+
|
|
963
|
+
### 3. **Implementation Patterns & Best Practices**
|
|
964
|
+
For each technology in the stack, provide:
|
|
965
|
+
- **Framework-Specific Patterns**: Best practices for the chosen frameworks
|
|
966
|
+
- **API Design**: How to structure APIs and endpoints
|
|
967
|
+
- **Data Layer**: Database schema and data access patterns
|
|
968
|
+
- **State Management**: How to handle application state
|
|
969
|
+
- **Error Handling**: Consistent error handling strategies
|
|
970
|
+
|
|
971
|
+
### 4. **ADR-to-Code Translation**
|
|
972
|
+
For each ADR to implement:
|
|
973
|
+
- **Implementation Tasks**: Specific coding tasks derived from the ADR
|
|
974
|
+
- **Code Examples**: Pseudo-code or pattern examples
|
|
975
|
+
- **Integration Points**: How this ADR affects other parts of the system
|
|
976
|
+
- **Validation Criteria**: How to verify the ADR is properly implemented
|
|
977
|
+
|
|
978
|
+
### 5. **Testing Strategy**
|
|
979
|
+
Comprehensive testing approach:
|
|
980
|
+
- **Unit Testing**: What to test and how
|
|
981
|
+
- **Integration Testing**: API and component integration tests
|
|
982
|
+
- **End-to-End Testing**: User workflow testing
|
|
983
|
+
- **Performance Testing**: Load and performance validation
|
|
984
|
+
- **Security Testing**: Security validation approaches
|
|
985
|
+
|
|
986
|
+
### 6. **Development Workflow**
|
|
987
|
+
Team-specific guidance:
|
|
988
|
+
- **Git Workflow**: Branching strategy and code review process
|
|
989
|
+
- **CI/CD Pipeline**: Automated testing and deployment
|
|
990
|
+
- **Code Quality**: Linting, formatting, and quality gates
|
|
991
|
+
- **Documentation**: What to document and how
|
|
992
|
+
|
|
993
|
+
### 7. **Quality Gates & Checkpoints**
|
|
994
|
+
Define success criteria:
|
|
995
|
+
- **Code Quality Metrics**: Coverage, complexity, maintainability
|
|
996
|
+
- **Performance Benchmarks**: Response times, throughput targets
|
|
997
|
+
- **Security Checkpoints**: Security validation at each phase
|
|
998
|
+
- **Architectural Compliance**: Adherence to ADR decisions
|
|
999
|
+
|
|
1000
|
+
### 8. **Technology-Specific Implementation**
|
|
1001
|
+
For each technology in the stack, provide:
|
|
1002
|
+
- **Setup Instructions**: Environment and tooling setup
|
|
1003
|
+
- **Configuration**: Framework and tool configuration
|
|
1004
|
+
- **Optimization**: Performance and build optimization
|
|
1005
|
+
- **Deployment**: Technology-specific deployment considerations
|
|
1006
|
+
|
|
1007
|
+
## Expected Output Format
|
|
1008
|
+
|
|
1009
|
+
Provide a comprehensive development guide that includes:
|
|
1010
|
+
|
|
1011
|
+
### 📋 **1. Development Roadmap**
|
|
1012
|
+
- **Phase 1-N**: Logical development phases with tasks
|
|
1013
|
+
- **Dependencies**: Task dependencies and critical path
|
|
1014
|
+
- **Timeline**: Estimated effort and duration
|
|
1015
|
+
- **Milestones**: Key deliverables and checkpoints
|
|
1016
|
+
|
|
1017
|
+
### 🏗️ **2. Implementation Guide**
|
|
1018
|
+
- **Code Structure**: Detailed project organization
|
|
1019
|
+
- **Design Patterns**: Specific patterns to implement
|
|
1020
|
+
- **API Design**: Endpoint structure and conventions
|
|
1021
|
+
- **Data Architecture**: Database and data flow design
|
|
1022
|
+
|
|
1023
|
+
### 🧪 **3. Testing & Quality Strategy**
|
|
1024
|
+
- **Test Types**: Unit, integration, e2e testing approach
|
|
1025
|
+
- **Quality Gates**: Code quality and performance criteria
|
|
1026
|
+
- **Automation**: CI/CD and automated testing setup
|
|
1027
|
+
|
|
1028
|
+
### 🚀 **4. Deployment & Operations**
|
|
1029
|
+
- **Environment Setup**: Development, staging, production
|
|
1030
|
+
- **Deployment Pipeline**: Automated deployment process
|
|
1031
|
+
- **Monitoring**: Logging, metrics, and alerting
|
|
1032
|
+
- **Maintenance**: Ongoing maintenance and updates
|
|
1033
|
+
|
|
1034
|
+
### 📊 **5. Progress Tracking**
|
|
1035
|
+
- **Success Metrics**: How to measure development progress
|
|
1036
|
+
- **Quality Indicators**: Code quality and performance metrics
|
|
1037
|
+
- **Milestone Validation**: How to verify milestone completion
|
|
1038
|
+
- **Risk Monitoring**: Early warning signs and mitigation
|
|
1039
|
+
|
|
1040
|
+
### 💡 **6. Team-Specific Recommendations**
|
|
1041
|
+
Based on team size (${teamContext.size}) and experience (${teamContext.experienceLevel}):
|
|
1042
|
+
- **Workflow Adaptations**: Process adjustments for team context
|
|
1043
|
+
- **Skill Development**: Areas for team skill building
|
|
1044
|
+
- **Tool Recommendations**: Development tools and practices
|
|
1045
|
+
- **Communication**: Coordination and documentation practices
|
|
1046
|
+
|
|
1047
|
+
## Integration with Architectural Decisions
|
|
1048
|
+
|
|
1049
|
+
Ensure all development guidance:
|
|
1050
|
+
- **Aligns with ADRs**: Every recommendation supports architectural decisions
|
|
1051
|
+
- **Maintains Consistency**: Consistent patterns across the codebase
|
|
1052
|
+
- **Enables Evolution**: Flexible design for future changes
|
|
1053
|
+
- **Supports Quality**: Built-in quality and maintainability
|
|
1054
|
+
|
|
1055
|
+
Make the guidance **actionable, specific, and immediately implementable** so developers can start coding with confidence and architectural alignment.
|
|
1056
|
+
`;
|
|
1057
|
+
// Execute the development guidance with AI if enabled
|
|
1058
|
+
const { executePromptWithFallback, formatMCPResponse } = await import('./utils/prompt-execution.js');
|
|
1059
|
+
const executionResult = await executePromptWithFallback(developmentPrompt, 'Analyze the development context and provide comprehensive implementation guidance that translates architectural decisions into specific coding tasks and development roadmap.', {
|
|
1060
|
+
temperature: 0.1,
|
|
1061
|
+
maxTokens: 8000,
|
|
1062
|
+
systemPrompt: `You are an expert software development advisor specializing in translating architectural decisions into practical implementation guidance.
|
|
1063
|
+
Your role is to bridge the gap between architectural planning and actual code development.
|
|
1064
|
+
Provide specific, actionable development guidance with clear implementation steps, code patterns, and quality criteria.
|
|
1065
|
+
Focus on practical guidance that ensures architectural decisions are properly implemented in code.
|
|
1066
|
+
Consider team context, technology stack, and development phase to provide tailored recommendations.`,
|
|
1067
|
+
});
|
|
1068
|
+
if (executionResult.isAIGenerated) {
|
|
1069
|
+
// AI execution successful - return actual development guidance
|
|
1070
|
+
return formatMCPResponse({
|
|
1071
|
+
...executionResult,
|
|
1072
|
+
content: `# Development Guidance & Implementation Roadmap
|
|
1073
|
+
|
|
1074
|
+
## Your Development Context
|
|
1075
|
+
- **Development Phase**: ${developmentPhase}
|
|
1076
|
+
- **Technology Stack**: ${technologyStack.length > 0 ? technologyStack.join(', ') : 'Not specified'}
|
|
1077
|
+
- **Current Progress**: ${currentProgress || 'Starting fresh'}
|
|
1078
|
+
- **Team Context**: ${teamContext.size} team with ${teamContext.experienceLevel} experience
|
|
1079
|
+
- **Timeline**: ${timeline || 'Not specified'}
|
|
1080
|
+
- **Focus Areas**: ${focusAreas.length > 0 ? focusAreas.join(', ') : 'General development'}
|
|
1081
|
+
- **ADRs to Implement**: ${adrsToImplement.length > 0 ? adrsToImplement.join(', ') : 'None specified'}
|
|
1082
|
+
|
|
1083
|
+
## AI-Generated Development Guidance
|
|
1084
|
+
|
|
1085
|
+
${executionResult.content}
|
|
1086
|
+
|
|
1087
|
+
## Integration with Workflow Tools
|
|
1088
|
+
|
|
1089
|
+
This development guidance works seamlessly with other MCP tools:
|
|
1090
|
+
|
|
1091
|
+
### **Workflow Integration**
|
|
1092
|
+
1. **get_workflow_guidance** → Recommends architectural process
|
|
1093
|
+
2. **get_development_guidance** → Guides implementation (this tool)
|
|
1094
|
+
3. **validate_rules** → Ensures code follows architectural decisions
|
|
1095
|
+
4. **analyze_deployment_progress** → Tracks implementation progress
|
|
1096
|
+
|
|
1097
|
+
### **Quality Assurance Tools**
|
|
1098
|
+
- **generate_rules** → Extract coding standards from ADRs
|
|
1099
|
+
- **validate_rules** → Validate code against architectural rules
|
|
1100
|
+
- **analyze_content_security** → Security validation during development
|
|
1101
|
+
|
|
1102
|
+
### **Documentation Tools**
|
|
1103
|
+
- **discover_existing_adrs** → Reference existing architectural decisions
|
|
1104
|
+
|
|
1105
|
+
## Next Steps: From Architecture to Code
|
|
1106
|
+
|
|
1107
|
+
1. **📋 Review the Development Roadmap** above
|
|
1108
|
+
2. **🏗️ Set Up Project Structure** as recommended
|
|
1109
|
+
3. **🧪 Implement Testing Strategy** early in development
|
|
1110
|
+
4. **📊 Track Progress** using the success metrics provided
|
|
1111
|
+
5. **🔄 Iterate and Refine** based on implementation learnings
|
|
1112
|
+
|
|
1113
|
+
This guidance ensures your development work is **architecturally aligned**, **quality-focused**, and **efficiently executed**!
|
|
1114
|
+
`,
|
|
1115
|
+
});
|
|
1116
|
+
}
|
|
1117
|
+
else {
|
|
1118
|
+
// Fallback to prompt-only mode
|
|
1119
|
+
return {
|
|
1120
|
+
content: [
|
|
1121
|
+
{
|
|
1122
|
+
type: 'text',
|
|
1123
|
+
text: developmentPrompt,
|
|
1124
|
+
},
|
|
1125
|
+
],
|
|
1126
|
+
};
|
|
1127
|
+
}
|
|
1128
|
+
}
|
|
1129
|
+
catch (error) {
|
|
1130
|
+
throw new McpAdrError(`Failed to generate development guidance: ${error instanceof Error ? error.message : String(error)}`, 'DEVELOPMENT_ERROR');
|
|
1131
|
+
}
|
|
1132
|
+
}
|
|
1133
|
+
async analyzeProjectEcosystem(args, context) {
|
|
1134
|
+
const ctx = context || createNoOpContext();
|
|
1135
|
+
// Use configured project path if not provided in args
|
|
1136
|
+
const projectPath = args.projectPath || this.config.projectPath;
|
|
1137
|
+
const { includePatterns, enhancedMode = getEnhancedModeDefault(), // Environment-aware default
|
|
1138
|
+
knowledgeEnhancement = getKnowledgeEnhancementDefault(), // Environment-aware default
|
|
1139
|
+
learningEnabled = true, technologyFocus = [], analysisDepth = 'comprehensive', includeEnvironment = true, recursiveDepth = 'comprehensive', analysisScope = [],
|
|
1140
|
+
// conversationContext - TODO: implement context integration for ecosystem analysis
|
|
1141
|
+
} = args;
|
|
1142
|
+
this.logger.info(`Generating comprehensive ecosystem analysis for project at: ${projectPath}`);
|
|
1143
|
+
this.logger.info(`Analysis configuration - Depth: ${analysisDepth}, Recursive: ${recursiveDepth}, Environment: ${includeEnvironment}`);
|
|
1144
|
+
this.logger.info(`Enhancement features - Knowledge: ${knowledgeEnhancement}, Learning: ${learningEnabled}`);
|
|
1145
|
+
this.logger.info(`Analysis scope: ${analysisScope.length > 0 ? analysisScope.join(', ') : 'Full ecosystem analysis'}`);
|
|
1146
|
+
ctx.info(`🌐 Starting comprehensive ecosystem analysis: ${projectPath}`);
|
|
1147
|
+
ctx.report_progress(0, 100);
|
|
1148
|
+
try {
|
|
1149
|
+
ctx.info('📊 Phase 1: Analyzing project structure');
|
|
1150
|
+
ctx.report_progress(10, 100);
|
|
1151
|
+
// Import utilities dynamically to avoid circular dependencies
|
|
1152
|
+
const { analyzeProjectStructureCompat: analyzeProjectStructure } = await import('./utils/file-system.js');
|
|
1153
|
+
// Initialize ADR knowledge base on first run
|
|
1154
|
+
ctx.info('📚 Phase 1.5: Initializing ADR knowledge base');
|
|
1155
|
+
ctx.report_progress(15, 100);
|
|
1156
|
+
try {
|
|
1157
|
+
const { initializeAdrKnowledgeBase, isAdrKnowledgeBaseInitialized } = await import('./utils/adr-knowledge-initializer.js');
|
|
1158
|
+
const isInitialized = await isAdrKnowledgeBaseInitialized(this.kgManager);
|
|
1159
|
+
if (!isInitialized) {
|
|
1160
|
+
this.logger.info('First run detected - initializing ADR knowledge base');
|
|
1161
|
+
const initResult = await initializeAdrKnowledgeBase(this.kgManager, this.config.adrDirectory, projectPath);
|
|
1162
|
+
if (initResult.success) {
|
|
1163
|
+
this.logger.info(`✅ ADR knowledge base initialized with ${initResult.adrsIndexed} ADRs`);
|
|
1164
|
+
ctx.info(`📚 Indexed ${initResult.adrsIndexed} existing ADRs to knowledge base`);
|
|
1165
|
+
}
|
|
1166
|
+
else {
|
|
1167
|
+
this.logger.warn(`ADR knowledge base initialization completed with errors: ${initResult.errors.join(', ')}`);
|
|
1168
|
+
}
|
|
1169
|
+
}
|
|
1170
|
+
else {
|
|
1171
|
+
this.logger.info('ADR knowledge base already initialized - skipping');
|
|
1172
|
+
}
|
|
1173
|
+
}
|
|
1174
|
+
catch (error) {
|
|
1175
|
+
this.logger.warn('Failed to initialize ADR knowledge base:', error);
|
|
1176
|
+
// Don't fail the entire analysis if ADR initialization fails
|
|
1177
|
+
}
|
|
1178
|
+
// DEPRECATED: Legacy context assembly for enhanced mode
|
|
1179
|
+
// This section is part of the OpenRouter execution path and will be removed
|
|
1180
|
+
// in a future release. For CE-MCP mode, use createAnalyzeProjectEcosystemDirective()
|
|
1181
|
+
// from src/tools/ce-mcp-tools.ts instead. See ADR-014.
|
|
1182
|
+
let generateArchitecturalKnowledge = null;
|
|
1183
|
+
let executeWithReflexion = null;
|
|
1184
|
+
let retrieveRelevantMemories = null;
|
|
1185
|
+
let createToolReflexionConfig = null;
|
|
1186
|
+
if (enhancedMode) {
|
|
1187
|
+
if (knowledgeEnhancement) {
|
|
1188
|
+
const knowledgeModule = await import('./utils/knowledge-generation.js');
|
|
1189
|
+
generateArchitecturalKnowledge = knowledgeModule.generateArchitecturalKnowledge;
|
|
1190
|
+
}
|
|
1191
|
+
if (learningEnabled) {
|
|
1192
|
+
const reflexionModule = await import('./utils/reflexion.js');
|
|
1193
|
+
executeWithReflexion = reflexionModule.executeWithReflexion;
|
|
1194
|
+
retrieveRelevantMemories = reflexionModule.retrieveRelevantMemories;
|
|
1195
|
+
createToolReflexionConfig = reflexionModule.createToolReflexionConfig;
|
|
1196
|
+
}
|
|
1197
|
+
}
|
|
1198
|
+
// Step 1: Generate technology-specific knowledge if enabled
|
|
1199
|
+
ctx.info('🧠 Phase 2: Generating architectural knowledge');
|
|
1200
|
+
ctx.report_progress(25, 100);
|
|
1201
|
+
let knowledgeContext = '';
|
|
1202
|
+
if (enhancedMode && knowledgeEnhancement && generateArchitecturalKnowledge) {
|
|
1203
|
+
try {
|
|
1204
|
+
const knowledgeResult = await generateArchitecturalKnowledge({
|
|
1205
|
+
projectPath,
|
|
1206
|
+
technologies: technologyFocus,
|
|
1207
|
+
patterns: [],
|
|
1208
|
+
projectType: 'ecosystem-analysis',
|
|
1209
|
+
existingAdrs: [],
|
|
1210
|
+
}, {
|
|
1211
|
+
domains: this.getEcosystemAnalysisDomains(technologyFocus),
|
|
1212
|
+
depth: analysisDepth === 'basic' ? 'basic' : 'intermediate',
|
|
1213
|
+
cacheEnabled: true,
|
|
1214
|
+
});
|
|
1215
|
+
knowledgeContext = `
|
|
1216
|
+
## Technology-Specific Knowledge Enhancement
|
|
1217
|
+
|
|
1218
|
+
The following architectural knowledge has been generated to enhance ecosystem analysis:
|
|
1219
|
+
|
|
1220
|
+
${knowledgeResult.prompt}
|
|
1221
|
+
|
|
1222
|
+
---
|
|
1223
|
+
`;
|
|
1224
|
+
}
|
|
1225
|
+
catch (error) {
|
|
1226
|
+
this.logger.warn('Knowledge generation failed:', error);
|
|
1227
|
+
knowledgeContext = '<!-- Knowledge generation unavailable -->\n';
|
|
1228
|
+
}
|
|
1229
|
+
}
|
|
1230
|
+
// Step 2: Retrieve relevant memories if learning is enabled
|
|
1231
|
+
let reflexionContext = '';
|
|
1232
|
+
if (enhancedMode && learningEnabled && retrieveRelevantMemories) {
|
|
1233
|
+
try {
|
|
1234
|
+
const memoryResult = await retrieveRelevantMemories('ecosystem-analysis', { projectPath, analysisDepth, technologyFocus }, { maxResults: 5, relevanceThreshold: 0.6 });
|
|
1235
|
+
reflexionContext = `
|
|
1236
|
+
## Learning from Past Analyses
|
|
1237
|
+
|
|
1238
|
+
The following insights from past ecosystem analysis tasks will inform this analysis:
|
|
1239
|
+
|
|
1240
|
+
${memoryResult.prompt}
|
|
1241
|
+
|
|
1242
|
+
---
|
|
1243
|
+
`;
|
|
1244
|
+
}
|
|
1245
|
+
catch (error) {
|
|
1246
|
+
this.logger.warn('Reflexion memory retrieval failed:', error);
|
|
1247
|
+
reflexionContext = '<!-- Learning context unavailable -->\n';
|
|
1248
|
+
}
|
|
1249
|
+
}
|
|
1250
|
+
// Step 3: Generate base project analysis prompt with recursive depth
|
|
1251
|
+
ctx.info('📁 Phase 3: Scanning project files and structure');
|
|
1252
|
+
ctx.report_progress(40, 100);
|
|
1253
|
+
const baseProjectAnalysisPrompt = await analyzeProjectStructure(projectPath);
|
|
1254
|
+
// Step 4: Generate environment analysis if enabled
|
|
1255
|
+
ctx.info('🔧 Phase 4: Analyzing environment and infrastructure');
|
|
1256
|
+
ctx.report_progress(55, 100);
|
|
1257
|
+
let environmentAnalysisContext = '';
|
|
1258
|
+
if (includeEnvironment) {
|
|
1259
|
+
try {
|
|
1260
|
+
this.logger.info('Including comprehensive environment analysis in ecosystem analysis');
|
|
1261
|
+
const { analyzeEnvironment } = await import('./tools/environment-analysis-tool.js');
|
|
1262
|
+
// Call environment analysis with comprehensive scope
|
|
1263
|
+
const environmentResult = await analyzeEnvironment({
|
|
1264
|
+
projectPath,
|
|
1265
|
+
adrDirectory: this.config.adrDirectory,
|
|
1266
|
+
analysisType: 'comprehensive',
|
|
1267
|
+
});
|
|
1268
|
+
// Extract environment analysis content
|
|
1269
|
+
if (environmentResult.content && environmentResult.content[0]) {
|
|
1270
|
+
environmentAnalysisContext = `
|
|
1271
|
+
## Integrated Environment Analysis
|
|
1272
|
+
|
|
1273
|
+
${environmentResult.content[0].text}
|
|
1274
|
+
|
|
1275
|
+
---
|
|
1276
|
+
`;
|
|
1277
|
+
}
|
|
1278
|
+
}
|
|
1279
|
+
catch (error) {
|
|
1280
|
+
this.logger.warn('Environment analysis integration failed:', error);
|
|
1281
|
+
environmentAnalysisContext = `
|
|
1282
|
+
## Environment Analysis
|
|
1283
|
+
<!-- Environment analysis unavailable: ${error instanceof Error ? error.message : 'Unknown error'} -->
|
|
1284
|
+
|
|
1285
|
+
---
|
|
1286
|
+
`;
|
|
1287
|
+
}
|
|
1288
|
+
}
|
|
1289
|
+
// Step 5: Apply Reflexion execution if learning is enabled
|
|
1290
|
+
ctx.info('🧪 Phase 5: Applying learning and reflexion');
|
|
1291
|
+
ctx.report_progress(70, 100);
|
|
1292
|
+
let enhancedAnalysisPrompt = baseProjectAnalysisPrompt.prompt + environmentAnalysisContext;
|
|
1293
|
+
if (enhancedMode && learningEnabled && executeWithReflexion && createToolReflexionConfig) {
|
|
1294
|
+
try {
|
|
1295
|
+
const reflexionConfig = createToolReflexionConfig('analyze_project_ecosystem', {
|
|
1296
|
+
reflectionDepth: analysisDepth === 'basic' ? 'basic' : 'detailed',
|
|
1297
|
+
evaluationCriteria: ['task-success', 'accuracy', 'completeness'],
|
|
1298
|
+
learningRate: 0.7,
|
|
1299
|
+
});
|
|
1300
|
+
const reflexionResult = await executeWithReflexion({
|
|
1301
|
+
prompt: baseProjectAnalysisPrompt.prompt + knowledgeContext + environmentAnalysisContext,
|
|
1302
|
+
instructions: baseProjectAnalysisPrompt.instructions,
|
|
1303
|
+
context: {
|
|
1304
|
+
projectPath,
|
|
1305
|
+
analysisDepth,
|
|
1306
|
+
recursiveDepth,
|
|
1307
|
+
technologyFocus,
|
|
1308
|
+
includePatterns,
|
|
1309
|
+
includeEnvironment,
|
|
1310
|
+
analysisScope,
|
|
1311
|
+
knowledgeEnhanced: knowledgeEnhancement,
|
|
1312
|
+
learningEnabled: true,
|
|
1313
|
+
},
|
|
1314
|
+
}, reflexionConfig);
|
|
1315
|
+
enhancedAnalysisPrompt = reflexionResult.prompt;
|
|
1316
|
+
}
|
|
1317
|
+
catch (error) {
|
|
1318
|
+
this.logger.warn('Reflexion execution failed:', error);
|
|
1319
|
+
enhancedAnalysisPrompt =
|
|
1320
|
+
baseProjectAnalysisPrompt.prompt + knowledgeContext + environmentAnalysisContext;
|
|
1321
|
+
}
|
|
1322
|
+
}
|
|
1323
|
+
else {
|
|
1324
|
+
enhancedAnalysisPrompt =
|
|
1325
|
+
baseProjectAnalysisPrompt.prompt + knowledgeContext + environmentAnalysisContext;
|
|
1326
|
+
}
|
|
1327
|
+
// Execute the analysis with AI if enabled, otherwise return prompt
|
|
1328
|
+
ctx.info('🤖 Phase 6: Executing AI-powered ecosystem analysis');
|
|
1329
|
+
ctx.report_progress(85, 100);
|
|
1330
|
+
const { executeEcosystemAnalysisPrompt, formatMCPResponse } = await import('./utils/prompt-execution.js');
|
|
1331
|
+
const executionResult = await executeEcosystemAnalysisPrompt(enhancedAnalysisPrompt, baseProjectAnalysisPrompt.instructions, {
|
|
1332
|
+
temperature: 0.1,
|
|
1333
|
+
maxTokens: 6000,
|
|
1334
|
+
});
|
|
1335
|
+
// Step 6: Record project structure to knowledge graph
|
|
1336
|
+
try {
|
|
1337
|
+
this.logger.info('Recording project structure to knowledge graph');
|
|
1338
|
+
const projectStructureSnapshot = {
|
|
1339
|
+
projectPath,
|
|
1340
|
+
analysisDepth,
|
|
1341
|
+
recursiveDepth,
|
|
1342
|
+
technologyFocus,
|
|
1343
|
+
analysisScope,
|
|
1344
|
+
includeEnvironment,
|
|
1345
|
+
timestamp: new Date().toISOString(),
|
|
1346
|
+
structureData: baseProjectAnalysisPrompt.context || {},
|
|
1347
|
+
};
|
|
1348
|
+
await this.kgManager.recordProjectStructure(projectStructureSnapshot);
|
|
1349
|
+
this.logger.info('✅ Project structure recorded to knowledge graph');
|
|
1350
|
+
}
|
|
1351
|
+
catch (kgError) {
|
|
1352
|
+
this.logger.warn('Failed to record project structure to knowledge graph:', kgError);
|
|
1353
|
+
// Don't fail the entire analysis if KG recording fails
|
|
1354
|
+
}
|
|
1355
|
+
ctx.info('✅ Ecosystem analysis completed successfully');
|
|
1356
|
+
ctx.report_progress(100, 100);
|
|
1357
|
+
// Return appropriate response based on execution result
|
|
1358
|
+
if (executionResult.isAIGenerated) {
|
|
1359
|
+
// AI execution successful - return actual analysis results
|
|
1360
|
+
return formatMCPResponse({
|
|
1361
|
+
...executionResult,
|
|
1362
|
+
content: `# Comprehensive Project Ecosystem Analysis Results
|
|
1363
|
+
|
|
1364
|
+
## Analysis Configuration
|
|
1365
|
+
- **Project Path**: ${projectPath}
|
|
1366
|
+
- **Analysis Depth**: ${analysisDepth}
|
|
1367
|
+
- **Recursive Depth**: ${recursiveDepth}
|
|
1368
|
+
- **Environment Analysis**: ${includeEnvironment ? '✅ Included' : '❌ Excluded'}
|
|
1369
|
+
- **Analysis Scope**: ${analysisScope.length > 0 ? analysisScope.join(', ') : 'Full ecosystem analysis'}
|
|
1370
|
+
|
|
1371
|
+
## Enhancement Features
|
|
1372
|
+
- **Knowledge Generation**: ${enhancedMode && knowledgeEnhancement ? '✅ Enabled' : '❌ Disabled'}
|
|
1373
|
+
- **Reflexion Learning**: ${enhancedMode && learningEnabled ? '✅ Enabled' : '❌ Disabled'}
|
|
1374
|
+
- **Enhanced Mode**: ${enhancedMode ? '✅ Enabled' : '❌ Disabled'}
|
|
1375
|
+
- **Technology Focus**: ${technologyFocus.length > 0 ? technologyFocus.join(', ') : 'Auto-detect'}
|
|
1376
|
+
- **Knowledge Graph**: ✅ Project structure recorded
|
|
1377
|
+
|
|
1378
|
+
${knowledgeContext}
|
|
1379
|
+
|
|
1380
|
+
${reflexionContext}
|
|
1381
|
+
|
|
1382
|
+
## Comprehensive Ecosystem Analysis Results
|
|
1383
|
+
|
|
1384
|
+
${executionResult.content}
|
|
1385
|
+
|
|
1386
|
+
${includeEnvironment
|
|
1387
|
+
? `
|
|
1388
|
+
|
|
1389
|
+
## Environment Integration Summary
|
|
1390
|
+
|
|
1391
|
+
The analysis above includes comprehensive environment analysis covering:
|
|
1392
|
+
- **Infrastructure Specifications**: Deployment and runtime environment details
|
|
1393
|
+
- **Containerization**: Docker, Kubernetes, and container orchestration analysis
|
|
1394
|
+
- **Environment Requirements**: Configuration and dependency requirements
|
|
1395
|
+
- **Compliance Assessment**: Security and regulatory compliance evaluation
|
|
1396
|
+
|
|
1397
|
+
This integrated approach provides complete understanding of both codebase patterns AND operational environment.
|
|
1398
|
+
`
|
|
1399
|
+
: ''}
|
|
1400
|
+
|
|
1401
|
+
## Next Steps: Complete Ecosystem Understanding
|
|
1402
|
+
|
|
1403
|
+
Based on the comprehensive analysis above:
|
|
1404
|
+
|
|
1405
|
+
### **Immediate Actions**
|
|
1406
|
+
1. **Review Ecosystem Overview**: Examine the complete technology stack and environment context
|
|
1407
|
+
2. **Assess Integration Points**: Understand how code patterns relate to operational environment
|
|
1408
|
+
3. **Identify Critical Dependencies**: Focus on key dependencies between code and infrastructure
|
|
1409
|
+
|
|
1410
|
+
### **Strategic Planning**
|
|
1411
|
+
4. **Address Architectural Issues**: Prioritize improvements based on both code and environment analysis
|
|
1412
|
+
5. **Plan Environment Optimization**: Optimize deployment and operational configurations
|
|
1413
|
+
6. **Update Documentation**: Document both architectural decisions and environment specifications
|
|
1414
|
+
|
|
1415
|
+
### **Implementation Roadmap**
|
|
1416
|
+
7. **Implement Code Improvements**: Execute code-level architectural enhancements
|
|
1417
|
+
8. **Optimize Environment**: Improve infrastructure and deployment configurations
|
|
1418
|
+
9. **Monitor Integration**: Ensure code and environment changes work together effectively
|
|
1419
|
+
|
|
1420
|
+
This comprehensive ecosystem analysis provides the foundation for informed architectural and operational decisions.
|
|
1421
|
+
`,
|
|
1422
|
+
});
|
|
1423
|
+
}
|
|
1424
|
+
else {
|
|
1425
|
+
// Fallback to prompt-only mode
|
|
1426
|
+
return {
|
|
1427
|
+
content: [
|
|
1428
|
+
{
|
|
1429
|
+
type: 'text',
|
|
1430
|
+
text: `# Comprehensive Project Ecosystem Analysis
|
|
1431
|
+
|
|
1432
|
+
This comprehensive analysis provides deep recursive project understanding with integrated environment analysis.
|
|
1433
|
+
|
|
1434
|
+
## Analysis Configuration
|
|
1435
|
+
- **Project Path**: ${projectPath}
|
|
1436
|
+
- **Analysis Depth**: ${analysisDepth}
|
|
1437
|
+
- **Recursive Depth**: ${recursiveDepth}
|
|
1438
|
+
- **Environment Analysis**: ${includeEnvironment ? '✅ Included' : '❌ Excluded'}
|
|
1439
|
+
- **Analysis Scope**: ${analysisScope.length > 0 ? analysisScope.join(', ') : 'Full ecosystem analysis'}
|
|
1440
|
+
|
|
1441
|
+
## Enhancement Features
|
|
1442
|
+
- **Knowledge Generation**: ${enhancedMode && knowledgeEnhancement ? '✅ Enabled' : '❌ Disabled'}
|
|
1443
|
+
- **Reflexion Learning**: ${enhancedMode && learningEnabled ? '✅ Enabled' : '❌ Disabled'}
|
|
1444
|
+
- **Enhanced Mode**: ${enhancedMode ? '✅ Enabled' : '❌ Disabled'}
|
|
1445
|
+
- **Technology Focus**: ${technologyFocus.length > 0 ? technologyFocus.join(', ') : 'Auto-detect'}
|
|
1446
|
+
- **Include Patterns**: ${includePatterns?.length ? includePatterns.join(', ') : 'Default patterns'}
|
|
1447
|
+
- **Knowledge Graph**: ✅ Project structure recorded
|
|
1448
|
+
|
|
1449
|
+
${knowledgeContext}
|
|
1450
|
+
|
|
1451
|
+
${reflexionContext}
|
|
1452
|
+
|
|
1453
|
+
## Enhanced Analysis Prompt
|
|
1454
|
+
|
|
1455
|
+
${enhancedAnalysisPrompt}
|
|
1456
|
+
|
|
1457
|
+
## Enhanced Implementation Instructions
|
|
1458
|
+
|
|
1459
|
+
${baseProjectAnalysisPrompt.instructions}
|
|
1460
|
+
|
|
1461
|
+
### Enhancement-Specific Instructions
|
|
1462
|
+
|
|
1463
|
+
${enhancedMode && knowledgeEnhancement
|
|
1464
|
+
? `
|
|
1465
|
+
#### Knowledge Enhancement
|
|
1466
|
+
- Apply technology-specific knowledge to ecosystem analysis
|
|
1467
|
+
- Use domain expertise to identify patterns and anti-patterns
|
|
1468
|
+
- Leverage architectural best practices for technology stack evaluation
|
|
1469
|
+
`
|
|
1470
|
+
: ''}
|
|
1471
|
+
|
|
1472
|
+
${enhancedMode && learningEnabled
|
|
1473
|
+
? `
|
|
1474
|
+
#### Learning Integration
|
|
1475
|
+
- Apply lessons learned from past ecosystem analyses
|
|
1476
|
+
- Use memory insights to improve pattern recognition accuracy
|
|
1477
|
+
- Incorporate feedback from previous analysis outcomes
|
|
1478
|
+
`
|
|
1479
|
+
: ''}
|
|
1480
|
+
|
|
1481
|
+
## Expected Enhanced Output
|
|
1482
|
+
|
|
1483
|
+
The enhanced analysis should provide:
|
|
1484
|
+
1. **Technology Stack Analysis** with domain knowledge context
|
|
1485
|
+
2. **Architectural Pattern Detection** informed by past experiences
|
|
1486
|
+
3. **Ecosystem Health Assessment** using learned evaluation criteria
|
|
1487
|
+
4. **Improvement Recommendations** based on domain best practices
|
|
1488
|
+
5. **Learning Insights** for future analysis improvement
|
|
1489
|
+
|
|
1490
|
+
## Quality Assurance
|
|
1491
|
+
|
|
1492
|
+
- Ensure analysis leverages all available enhancement features
|
|
1493
|
+
- Verify technology-specific knowledge is properly applied
|
|
1494
|
+
- Confirm learning insights improve analysis accuracy
|
|
1495
|
+
- Validate recommendations align with domain best practices`,
|
|
1496
|
+
},
|
|
1497
|
+
],
|
|
1498
|
+
};
|
|
1499
|
+
}
|
|
1500
|
+
}
|
|
1501
|
+
catch (error) {
|
|
1502
|
+
throw new McpAdrError(`Failed to analyze project ecosystem: ${error instanceof Error ? error.message : String(error)}`, 'ANALYSIS_ERROR');
|
|
1503
|
+
}
|
|
1504
|
+
}
|
|
1505
|
+
async getArchitecturalContext(args) {
|
|
1506
|
+
const { filePath, includeCompliance = true } = args;
|
|
1507
|
+
try {
|
|
1508
|
+
const { analyzeProjectStructureCompat: analyzeProjectStructure, fileExistsCompat: fileExists, ensureDirectoryCompat: ensureDirectory, } = await import('./utils/file-system.js');
|
|
1509
|
+
const path = await import('path');
|
|
1510
|
+
// Determine project path
|
|
1511
|
+
const projectPath = filePath
|
|
1512
|
+
? filePath.split('/').slice(0, -1).join('/')
|
|
1513
|
+
: this.config.projectPath;
|
|
1514
|
+
const adrDirectory = path.join(projectPath, this.config.adrDirectory);
|
|
1515
|
+
// Generate prompts for ADR directory setup
|
|
1516
|
+
const adrDirectoryCheckPrompt = await fileExists(adrDirectory);
|
|
1517
|
+
const adrDirectorySetupPrompt = await ensureDirectory(adrDirectory);
|
|
1518
|
+
// Generate architectural analysis prompt
|
|
1519
|
+
const projectAnalysisPrompt = await analyzeProjectStructure(projectPath);
|
|
1520
|
+
const architecturalPrompt = `
|
|
1521
|
+
# Architectural Context Analysis & Project Setup
|
|
1522
|
+
|
|
1523
|
+
## Project Overview
|
|
1524
|
+
**Project Path**: ${projectPath}
|
|
1525
|
+
**Analysis Scope**: ${filePath ? `Specific file: ${filePath}` : 'Entire project'}
|
|
1526
|
+
**ADR Directory**: ${this.config.adrDirectory}
|
|
1527
|
+
**Include Compliance**: ${includeCompliance ? 'Yes' : 'No'}
|
|
1528
|
+
|
|
1529
|
+
## 🚀 ADR Infrastructure Setup
|
|
1530
|
+
|
|
1531
|
+
This analysis will include setting up ADR infrastructure if needed:
|
|
1532
|
+
|
|
1533
|
+
### ADR Directory Check
|
|
1534
|
+
${adrDirectoryCheckPrompt.prompt}
|
|
1535
|
+
|
|
1536
|
+
### ADR Directory Setup (if needed)
|
|
1537
|
+
${adrDirectorySetupPrompt.prompt}
|
|
1538
|
+
|
|
1539
|
+
## Comprehensive Project Analysis
|
|
1540
|
+
|
|
1541
|
+
${projectAnalysisPrompt.prompt}
|
|
1542
|
+
|
|
1543
|
+
## Enhanced Architectural Focus
|
|
1544
|
+
|
|
1545
|
+
Please provide a **comprehensive, outcome-focused analysis** including:
|
|
1546
|
+
|
|
1547
|
+
### 1. Technology Stack & Infrastructure Analysis
|
|
1548
|
+
- **Core Technologies**: Programming languages, frameworks, runtime environments
|
|
1549
|
+
- **Dependencies**: Package managers, third-party libraries, version constraints
|
|
1550
|
+
- **Build & Deployment**: CI/CD pipelines, build tools, deployment strategies
|
|
1551
|
+
- **Data Layer**: Databases, caching, data storage and retrieval patterns
|
|
1552
|
+
|
|
1553
|
+
### 2. Architectural Pattern & Design Analysis
|
|
1554
|
+
- **System Architecture**: Monolith, microservices, serverless, hybrid patterns
|
|
1555
|
+
- **Code Organization**: Module structure, separation of concerns, layering
|
|
1556
|
+
- **API Design**: REST, GraphQL, RPC patterns and conventions
|
|
1557
|
+
- **Data Flow**: Request/response cycles, event handling, state management
|
|
1558
|
+
${filePath ? `- **File-specific Context**: How ${filePath} fits into the overall architecture` : ''}
|
|
1559
|
+
|
|
1560
|
+
### 3. Quality, Security & Performance Assessment
|
|
1561
|
+
- **Code Quality**: Structure, naming, documentation, testing strategies
|
|
1562
|
+
- **Security Implementation**: Authentication, authorization, data protection
|
|
1563
|
+
- **Performance Patterns**: Caching, optimization, scalability considerations
|
|
1564
|
+
- **Monitoring & Observability**: Logging, metrics, error tracking
|
|
1565
|
+
|
|
1566
|
+
### 4. Architectural Decision Discovery & Documentation
|
|
1567
|
+
- **Explicit Decisions**: Find existing documentation and decision records
|
|
1568
|
+
- **Implicit Decisions**: Identify significant undocumented architectural choices
|
|
1569
|
+
- **Technology Rationale**: Understand selection criteria and trade-offs
|
|
1570
|
+
- **Evolution Path**: How the architecture has changed over time
|
|
1571
|
+
|
|
1572
|
+
${includeCompliance
|
|
1573
|
+
? `### 5. Compliance & Standards Assessment
|
|
1574
|
+
- **Industry Standards**: Adherence to relevant industry standards and best practices
|
|
1575
|
+
- **Security Compliance**: Security standards compliance (OWASP, SOC2, etc.)
|
|
1576
|
+
- **Code Standards**: Coding standards and style guide compliance
|
|
1577
|
+
- **Architectural Compliance**: Adherence to established architectural principles
|
|
1578
|
+
- **Regulatory Requirements**: Any regulatory compliance requirements (GDPR, HIPAA, etc.)`
|
|
1579
|
+
: ''}
|
|
1580
|
+
|
|
1581
|
+
## Expected Output: Outcome-Focused Architectural Context
|
|
1582
|
+
|
|
1583
|
+
Provide a **comprehensive architectural context** with **clear project outcomes**:
|
|
1584
|
+
|
|
1585
|
+
### 📋 **1. Executive Summary & Project Outcomes**
|
|
1586
|
+
- **Current State**: What the project is and what it does
|
|
1587
|
+
- **Architectural Maturity**: Assessment of current architectural practices
|
|
1588
|
+
- **Key Strengths**: What's working well architecturally
|
|
1589
|
+
- **Critical Gaps**: What needs immediate attention
|
|
1590
|
+
- **Success Metrics**: How to measure architectural improvements
|
|
1591
|
+
|
|
1592
|
+
### 🔧 **2. Technology & Infrastructure Inventory**
|
|
1593
|
+
- **Technology Stack**: Complete inventory with versions and purposes
|
|
1594
|
+
- **Infrastructure Components**: Deployment, monitoring, data storage
|
|
1595
|
+
- **Dependencies**: Critical dependencies and potential risks
|
|
1596
|
+
- **Tool Chain**: Development, testing, and deployment tools
|
|
1597
|
+
|
|
1598
|
+
### 🏗️ **3. Architectural Patterns & Design Decisions**
|
|
1599
|
+
- **System Design**: Overall architectural approach and patterns
|
|
1600
|
+
- **Component Architecture**: How major components interact
|
|
1601
|
+
- **Data Architecture**: How data flows and is managed
|
|
1602
|
+
- **Integration Patterns**: How external systems are integrated
|
|
1603
|
+
|
|
1604
|
+
### 📊 **4. Quality & Compliance Assessment**
|
|
1605
|
+
- **Code Quality Score**: Assessment of current code quality
|
|
1606
|
+
- **Security Posture**: Security implementation and gaps
|
|
1607
|
+
- **Performance Profile**: Current performance characteristics
|
|
1608
|
+
- **Maintainability Index**: How easy the system is to maintain and evolve
|
|
1609
|
+
|
|
1610
|
+
### 🎯 **5. Outcome-Focused Action Plan**
|
|
1611
|
+
Based on the analysis, provide a **clear workflow** with **projected outcomes**:
|
|
1612
|
+
|
|
1613
|
+
#### **Immediate Actions (Next 1-2 weeks)**
|
|
1614
|
+
- **Priority 1**: Most critical architectural issues to address
|
|
1615
|
+
- **Quick Wins**: Low-effort, high-impact improvements
|
|
1616
|
+
- **Documentation**: Essential decisions that need immediate documentation
|
|
1617
|
+
|
|
1618
|
+
#### **Short-term Goals (Next 1-3 months)**
|
|
1619
|
+
- **Architectural Improvements**: Planned enhancements with expected outcomes
|
|
1620
|
+
- **Technical Debt**: Priority technical debt to address
|
|
1621
|
+
- **Process Improvements**: Development workflow enhancements
|
|
1622
|
+
|
|
1623
|
+
#### **Long-term Vision (3-12 months)**
|
|
1624
|
+
- **Strategic Architecture**: Long-term architectural evolution
|
|
1625
|
+
- **Scalability Roadmap**: How to scale the system effectively
|
|
1626
|
+
- **Innovation Opportunities**: Areas for architectural innovation
|
|
1627
|
+
|
|
1628
|
+
### 📈 **6. Success Metrics & Outcomes**
|
|
1629
|
+
Define **measurable outcomes** for architectural improvements:
|
|
1630
|
+
|
|
1631
|
+
- **Performance Metrics**: Response times, throughput, resource utilization
|
|
1632
|
+
- **Quality Metrics**: Code coverage, bug rates, maintainability scores
|
|
1633
|
+
- **Developer Experience**: Build times, deployment frequency, developer satisfaction
|
|
1634
|
+
- **Business Impact**: Feature delivery speed, system reliability, cost efficiency
|
|
1635
|
+
|
|
1636
|
+
### 🏗️ **7. ADR Infrastructure & Documentation Plan**
|
|
1637
|
+
|
|
1638
|
+
If ADR directory doesn't exist, also provide:
|
|
1639
|
+
|
|
1640
|
+
1. **Create Directory Structure**:
|
|
1641
|
+
\`\`\`
|
|
1642
|
+
${this.config.adrDirectory}/
|
|
1643
|
+
├── 0001-record-architecture-decisions.md (template)
|
|
1644
|
+
├── README.md (ADR process guide)
|
|
1645
|
+
└── template.md (ADR template)
|
|
1646
|
+
\`\`\`
|
|
1647
|
+
|
|
1648
|
+
2. **Generate Initial ADRs** for discovered architectural decisions
|
|
1649
|
+
3. **Create ADR Process Guide** for the team
|
|
1650
|
+
4. **Establish ADR Workflow** for future decisions
|
|
1651
|
+
|
|
1652
|
+
### 🔄 **8. Continuous Improvement Workflow**
|
|
1653
|
+
Establish ongoing architectural governance:
|
|
1654
|
+
|
|
1655
|
+
- **Regular Reviews**: Monthly architectural health checks
|
|
1656
|
+
- **Decision Documentation**: Process for documenting new architectural decisions
|
|
1657
|
+
- **Compliance Monitoring**: Ongoing adherence to architectural standards
|
|
1658
|
+
- **Evolution Planning**: Quarterly architectural roadmap updates
|
|
1659
|
+
|
|
1660
|
+
## Next Steps: Grounded Project Workflow
|
|
1661
|
+
|
|
1662
|
+
After this analysis, follow this **outcome-focused workflow**:
|
|
1663
|
+
|
|
1664
|
+
1. **📋 Review Analysis**: Examine the architectural context and recommendations
|
|
1665
|
+
2. **🎯 Set Priorities**: Choose 3-5 most impactful improvements based on outcomes
|
|
1666
|
+
3. **📝 Document Decisions**: Create ADRs for significant architectural choices
|
|
1667
|
+
4. **🔧 Implement Changes**: Execute improvements in priority order
|
|
1668
|
+
5. **📊 Measure Progress**: Track success metrics and outcomes
|
|
1669
|
+
6. **🔄 Iterate**: Regular reviews and continuous improvement
|
|
1670
|
+
|
|
1671
|
+
This approach ensures that architectural work is **grounded in measurable outcomes** and **aligned with project success**.
|
|
1672
|
+
`;
|
|
1673
|
+
// Execute the analysis with AI if enabled, otherwise return prompt
|
|
1674
|
+
const { executeEcosystemAnalysisPrompt, formatMCPResponse } = await import('./utils/prompt-execution.js');
|
|
1675
|
+
const executionResult = await executeEcosystemAnalysisPrompt(architecturalPrompt, projectAnalysisPrompt.instructions, {
|
|
1676
|
+
temperature: 0.1,
|
|
1677
|
+
maxTokens: 5000,
|
|
1678
|
+
systemPrompt: `You are a senior software architect specializing in architectural context analysis.
|
|
1679
|
+
Analyze the provided project to understand its architectural patterns, design decisions, and structural organization.
|
|
1680
|
+
Focus on providing actionable insights about the architecture that can guide development decisions.`,
|
|
1681
|
+
});
|
|
1682
|
+
if (executionResult.isAIGenerated) {
|
|
1683
|
+
// AI execution successful - return actual analysis results
|
|
1684
|
+
return formatMCPResponse({
|
|
1685
|
+
...executionResult,
|
|
1686
|
+
content: `# Architectural Context Analysis Results
|
|
1687
|
+
|
|
1688
|
+
${filePath ? `## Target File: ${filePath}` : '## Project-wide Analysis'}
|
|
1689
|
+
|
|
1690
|
+
## Project Information
|
|
1691
|
+
- **Project Path**: ${projectPath}
|
|
1692
|
+
- **Analysis Scope**: ${filePath ? 'File-specific' : 'Project-wide'}
|
|
1693
|
+
- **ADR Directory**: ${this.config.adrDirectory}
|
|
1694
|
+
|
|
1695
|
+
## ADR Infrastructure Setup
|
|
1696
|
+
|
|
1697
|
+
The analysis includes automatic ADR infrastructure setup:
|
|
1698
|
+
|
|
1699
|
+
${adrDirectoryCheckPrompt.instructions}
|
|
1700
|
+
|
|
1701
|
+
${adrDirectorySetupPrompt.instructions}
|
|
1702
|
+
|
|
1703
|
+
## AI Analysis Results
|
|
1704
|
+
|
|
1705
|
+
${executionResult.content}
|
|
1706
|
+
|
|
1707
|
+
## Outcome-Focused Next Steps
|
|
1708
|
+
|
|
1709
|
+
Based on the architectural analysis, follow this **grounded workflow**:
|
|
1710
|
+
|
|
1711
|
+
### **Immediate Actions (This Week)**
|
|
1712
|
+
1. **Review Analysis**: Examine the architectural context and recommendations above
|
|
1713
|
+
2. **Set Up ADRs**: Ensure ADR directory structure is created and ready
|
|
1714
|
+
3. **Identify Quick Wins**: Focus on low-effort, high-impact improvements
|
|
1715
|
+
|
|
1716
|
+
### **Short-term Goals (Next Month)**
|
|
1717
|
+
4. **Document Key Decisions**: Create ADRs for the most significant architectural choices
|
|
1718
|
+
5. **Address Critical Issues**: Tackle the highest-priority architectural concerns
|
|
1719
|
+
6. **Establish Metrics**: Set up measurement for the success metrics identified
|
|
1720
|
+
|
|
1721
|
+
### **Long-term Vision (Next Quarter)**
|
|
1722
|
+
7. **Implement Roadmap**: Execute the architectural improvement plan
|
|
1723
|
+
8. **Monitor Progress**: Track success metrics and adjust approach as needed
|
|
1724
|
+
9. **Continuous Improvement**: Establish regular architectural reviews
|
|
1725
|
+
|
|
1726
|
+
This **outcome-focused approach** ensures architectural work delivers **measurable value** and keeps the project **grounded in clear objectives**.
|
|
1727
|
+
`,
|
|
1728
|
+
});
|
|
1729
|
+
}
|
|
1730
|
+
else {
|
|
1731
|
+
// Fallback to prompt-only mode
|
|
1732
|
+
return {
|
|
1733
|
+
content: [
|
|
1734
|
+
{
|
|
1735
|
+
type: 'text',
|
|
1736
|
+
text: architecturalPrompt,
|
|
1737
|
+
},
|
|
1738
|
+
],
|
|
1739
|
+
};
|
|
1740
|
+
}
|
|
1741
|
+
}
|
|
1742
|
+
catch (error) {
|
|
1743
|
+
throw new McpAdrError(`Failed to get architectural context: ${error instanceof Error ? error.message : String(error)}`, 'ANALYSIS_ERROR');
|
|
1744
|
+
}
|
|
1745
|
+
}
|
|
1746
|
+
async generateAdrsFromPrd(args, context) {
|
|
1747
|
+
const ctx = context || createNoOpContext();
|
|
1748
|
+
const { prdPath, enhancedMode = getEnhancedModeDefault(), // Environment-aware default
|
|
1749
|
+
promptOptimization = true, knowledgeEnhancement = getKnowledgeEnhancementDefault(), // Environment-aware default
|
|
1750
|
+
prdType = 'general', } = args;
|
|
1751
|
+
const outputDirectory = args['outputDirectory'] || this.config.adrDirectory;
|
|
1752
|
+
this.logger.info(`Generating enhanced ADRs from PRD: ${prdPath} to ${outputDirectory}`);
|
|
1753
|
+
this.logger.info(`Enhancement features - APE: ${promptOptimization}, Knowledge: ${knowledgeEnhancement}, Type: ${prdType}`);
|
|
1754
|
+
ctx.info(`📝 Starting ADR generation from PRD: ${prdPath}`);
|
|
1755
|
+
ctx.report_progress(0, 100);
|
|
1756
|
+
try {
|
|
1757
|
+
ctx.info('📂 Phase 1: Validating PRD file');
|
|
1758
|
+
ctx.report_progress(10, 100);
|
|
1759
|
+
const { readFileContentCompat: readFileContent, fileExistsCompat: fileExists } = await import('./utils/file-system.js');
|
|
1760
|
+
// Import advanced prompting utilities if enhanced mode is enabled
|
|
1761
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
1762
|
+
let generateArchitecturalKnowledge = null;
|
|
1763
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
1764
|
+
let optimizePromptWithAPE = null;
|
|
1765
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
1766
|
+
let createToolAPEConfig = null;
|
|
1767
|
+
if (enhancedMode) {
|
|
1768
|
+
if (knowledgeEnhancement) {
|
|
1769
|
+
const knowledgeModule = await import('./utils/knowledge-generation.js');
|
|
1770
|
+
generateArchitecturalKnowledge = knowledgeModule.generateArchitecturalKnowledge;
|
|
1771
|
+
}
|
|
1772
|
+
if (promptOptimization) {
|
|
1773
|
+
const apeModule = await import('./utils/automatic-prompt-engineering.js');
|
|
1774
|
+
optimizePromptWithAPE = apeModule.optimizePromptWithAPE;
|
|
1775
|
+
createToolAPEConfig = apeModule.createToolAPEConfig;
|
|
1776
|
+
}
|
|
1777
|
+
}
|
|
1778
|
+
// Generate file existence check prompt
|
|
1779
|
+
const fileExistsPrompt = await fileExists(prdPath);
|
|
1780
|
+
// Generate file content reading prompt
|
|
1781
|
+
const fileContentPrompt = await readFileContent(prdPath);
|
|
1782
|
+
ctx.info('📚 Phase 2: Reading PRD content');
|
|
1783
|
+
ctx.report_progress(25, 100);
|
|
1784
|
+
// Step 1: Generate domain-specific knowledge if enabled
|
|
1785
|
+
ctx.info('🧠 Phase 3: Generating domain knowledge');
|
|
1786
|
+
ctx.report_progress(40, 100);
|
|
1787
|
+
let knowledgeContext = '';
|
|
1788
|
+
if (enhancedMode && knowledgeEnhancement && generateArchitecturalKnowledge) {
|
|
1789
|
+
try {
|
|
1790
|
+
const knowledgeResult = await generateArchitecturalKnowledge({
|
|
1791
|
+
projectPath: outputDirectory,
|
|
1792
|
+
technologies: [],
|
|
1793
|
+
patterns: [],
|
|
1794
|
+
projectType: prdType,
|
|
1795
|
+
existingAdrs: [],
|
|
1796
|
+
}, {
|
|
1797
|
+
domains: this.getPrdTypeDomains(prdType),
|
|
1798
|
+
depth: 'intermediate',
|
|
1799
|
+
cacheEnabled: true,
|
|
1800
|
+
});
|
|
1801
|
+
knowledgeContext = `
|
|
1802
|
+
## Domain-Specific Knowledge Enhancement
|
|
1803
|
+
|
|
1804
|
+
The following architectural knowledge has been generated to enhance PRD analysis and ADR creation:
|
|
1805
|
+
|
|
1806
|
+
${knowledgeResult.prompt}
|
|
1807
|
+
|
|
1808
|
+
---
|
|
1809
|
+
`;
|
|
1810
|
+
}
|
|
1811
|
+
catch (error) {
|
|
1812
|
+
this.logger.warn('Knowledge generation failed:', error);
|
|
1813
|
+
knowledgeContext = '<!-- Knowledge generation unavailable -->\n';
|
|
1814
|
+
}
|
|
1815
|
+
}
|
|
1816
|
+
// Step 2: Create base ADR generation prompt
|
|
1817
|
+
ctx.info('📋 Phase 4: Creating base ADR prompts');
|
|
1818
|
+
ctx.report_progress(60, 100);
|
|
1819
|
+
const baseAdrPrompt = this.createBaseAdrPrompt(prdPath, outputDirectory, knowledgeContext);
|
|
1820
|
+
// Step 3: Apply APE optimization if enabled
|
|
1821
|
+
ctx.info('⚡ Phase 5: Optimizing prompts with APE');
|
|
1822
|
+
ctx.report_progress(75, 100);
|
|
1823
|
+
let finalAdrPrompt = baseAdrPrompt;
|
|
1824
|
+
if (enhancedMode && promptOptimization && optimizePromptWithAPE && createToolAPEConfig) {
|
|
1825
|
+
try {
|
|
1826
|
+
const apeConfig = createToolAPEConfig('generate_adrs_from_prd', {
|
|
1827
|
+
candidateCount: 5,
|
|
1828
|
+
evaluationCriteria: ['task-completion', 'clarity', 'specificity'],
|
|
1829
|
+
optimizationRounds: 2,
|
|
1830
|
+
qualityThreshold: 0.75,
|
|
1831
|
+
});
|
|
1832
|
+
const apeResult = await optimizePromptWithAPE({
|
|
1833
|
+
prompt: baseAdrPrompt,
|
|
1834
|
+
instructions: 'Generate comprehensive ADRs from PRD analysis',
|
|
1835
|
+
context: {
|
|
1836
|
+
prdPath,
|
|
1837
|
+
outputDirectory,
|
|
1838
|
+
prdType,
|
|
1839
|
+
knowledgeEnhanced: knowledgeEnhancement,
|
|
1840
|
+
},
|
|
1841
|
+
}, apeConfig);
|
|
1842
|
+
finalAdrPrompt = apeResult.prompt;
|
|
1843
|
+
}
|
|
1844
|
+
catch (error) {
|
|
1845
|
+
this.logger.warn('APE optimization failed:', error);
|
|
1846
|
+
finalAdrPrompt = baseAdrPrompt;
|
|
1847
|
+
}
|
|
1848
|
+
}
|
|
1849
|
+
// Generate comprehensive ADR creation prompt that includes file operations
|
|
1850
|
+
const adrPrompt = `
|
|
1851
|
+
# Enhanced ADR Generation from PRD Request
|
|
1852
|
+
|
|
1853
|
+
This is a comprehensive prompt-driven ADR generation process enhanced with advanced prompting techniques.
|
|
1854
|
+
|
|
1855
|
+
## Enhancement Status
|
|
1856
|
+
- **APE Optimization**: ${enhancedMode && promptOptimization ? '✅ Enabled' : '❌ Disabled'}
|
|
1857
|
+
- **Knowledge Generation**: ${enhancedMode && knowledgeEnhancement ? '✅ Enabled' : '❌ Disabled'}
|
|
1858
|
+
- **PRD Type**: ${prdType}
|
|
1859
|
+
- **Enhanced Mode**: ${enhancedMode ? '✅ Enabled' : '❌ Disabled'}
|
|
1860
|
+
|
|
1861
|
+
## Step 1: File Validation
|
|
1862
|
+
${fileExistsPrompt.prompt}
|
|
1863
|
+
|
|
1864
|
+
**Instructions**: First, execute the file existence check above. If the file does not exist, stop the process and report the error. Only proceed to Step 2 if the file exists.
|
|
1865
|
+
|
|
1866
|
+
## Step 2: PRD Content Reading
|
|
1867
|
+
${fileContentPrompt.prompt}
|
|
1868
|
+
|
|
1869
|
+
**Instructions**: Execute the file reading operation above to obtain the PRD content. Use the content from this step for the enhanced ADR generation in Step 3.
|
|
1870
|
+
|
|
1871
|
+
## Step 3: Enhanced ADR Generation
|
|
1872
|
+
|
|
1873
|
+
${enhancedMode && promptOptimization
|
|
1874
|
+
? `
|
|
1875
|
+
### APE-Optimized Analysis
|
|
1876
|
+
This prompt has been optimized using Automatic Prompt Engineering for superior ADR generation quality.
|
|
1877
|
+
The optimization focused on task completion, clarity, and specificity for PRD analysis.
|
|
1878
|
+
|
|
1879
|
+
`
|
|
1880
|
+
: ''}
|
|
1881
|
+
|
|
1882
|
+
${finalAdrPrompt}
|
|
1883
|
+
|
|
1884
|
+
### File Creation Instructions
|
|
1885
|
+
|
|
1886
|
+
For each generated ADR, create a file creation prompt using the following pattern:
|
|
1887
|
+
- **File Path**: ${outputDirectory}/[number]-[decision-title].md
|
|
1888
|
+
- **Content**: The complete enhanced ADR markdown content
|
|
1889
|
+
- **Action Confirmation**: Require user confirmation before creating files
|
|
1890
|
+
- **Security Validation**: Ensure output directory is safe and authorized
|
|
1891
|
+
|
|
1892
|
+
### Enhanced Quality Assurance
|
|
1893
|
+
|
|
1894
|
+
- Ensure each ADR leverages domain knowledge when available
|
|
1895
|
+
- Verify decisions align with PRD type best practices
|
|
1896
|
+
- Check that enhancement features are properly utilized
|
|
1897
|
+
- Validate that ADR content exceeds baseline quality expectations
|
|
1898
|
+
- Confirm all decisions are traceable back to PRD requirements with domain context
|
|
1899
|
+
`;
|
|
1900
|
+
// Execute the ADR generation with AI if enabled, otherwise return prompt
|
|
1901
|
+
ctx.info('🤖 Phase 6: Executing AI-powered ADR generation');
|
|
1902
|
+
ctx.report_progress(90, 100);
|
|
1903
|
+
const { executeADRGenerationPrompt, formatMCPResponse } = await import('./utils/prompt-execution.js');
|
|
1904
|
+
const executionResult = await executeADRGenerationPrompt(adrPrompt, 'Generate comprehensive ADRs from PRD analysis with enhanced domain knowledge and optimization', {
|
|
1905
|
+
temperature: 0.1,
|
|
1906
|
+
maxTokens: 8000,
|
|
1907
|
+
systemPrompt: `You are an expert software architect who creates comprehensive Architectural Decision Records (ADRs) from Product Requirements Documents (PRDs).
|
|
1908
|
+
Generate well-structured ADRs that follow best practices and include all necessary sections.
|
|
1909
|
+
Focus on extracting architectural decisions from the PRD and creating actionable ADRs with clear reasoning.`,
|
|
1910
|
+
});
|
|
1911
|
+
ctx.info('✅ ADR generation completed successfully');
|
|
1912
|
+
ctx.report_progress(100, 100);
|
|
1913
|
+
if (executionResult.isAIGenerated) {
|
|
1914
|
+
// AI execution successful - return actual ADR generation results
|
|
1915
|
+
return formatMCPResponse({
|
|
1916
|
+
...executionResult,
|
|
1917
|
+
content: `# ADR Generation from PRD Results
|
|
1918
|
+
|
|
1919
|
+
## Enhancement Features
|
|
1920
|
+
- **APE Optimization**: ${enhancedMode && promptOptimization ? '✅ Enabled' : '❌ Disabled'}
|
|
1921
|
+
- **Knowledge Generation**: ${enhancedMode && knowledgeEnhancement ? '✅ Enabled' : '❌ Disabled'}
|
|
1922
|
+
- **PRD Type Optimization**: ${prdType}
|
|
1923
|
+
- **Enhanced Mode**: ${enhancedMode ? '✅ Enabled' : '❌ Disabled'}
|
|
1924
|
+
|
|
1925
|
+
## Source Information
|
|
1926
|
+
- **PRD Path**: ${prdPath}
|
|
1927
|
+
- **Output Directory**: ${outputDirectory}
|
|
1928
|
+
|
|
1929
|
+
## Generated ADRs
|
|
1930
|
+
|
|
1931
|
+
${executionResult.content}
|
|
1932
|
+
|
|
1933
|
+
## Next Steps
|
|
1934
|
+
|
|
1935
|
+
1. **Review Generated ADRs**: Examine each ADR for completeness and accuracy
|
|
1936
|
+
2. **Save ADR Files**: Create individual .md files for each ADR in ${outputDirectory}
|
|
1937
|
+
3. **Update ADR Index**: Add new ADRs to your project's ADR catalog
|
|
1938
|
+
4. **Stakeholder Review**: Share ADRs with team for feedback and approval
|
|
1939
|
+
5. **Implementation Planning**: Create tasks for implementing the architectural decisions
|
|
1940
|
+
|
|
1941
|
+
## File Creation Commands
|
|
1942
|
+
|
|
1943
|
+
To save the generated ADRs, create individual files in ${outputDirectory}:
|
|
1944
|
+
|
|
1945
|
+
\`\`\`bash
|
|
1946
|
+
# Create ADR directory if it doesn't exist
|
|
1947
|
+
mkdir -p ${outputDirectory}
|
|
1948
|
+
|
|
1949
|
+
# Save each ADR as a separate file (example)
|
|
1950
|
+
# Replace [NUMBER] and [TITLE] with actual values from generated ADRs
|
|
1951
|
+
# cat > "${outputDirectory}/001-example-decision.md" << 'EOF'
|
|
1952
|
+
# [ADR content here]
|
|
1953
|
+
# EOF
|
|
1954
|
+
\`\`\`
|
|
1955
|
+
`,
|
|
1956
|
+
});
|
|
1957
|
+
}
|
|
1958
|
+
else {
|
|
1959
|
+
// Fallback to prompt-only mode
|
|
1960
|
+
return {
|
|
1961
|
+
content: [
|
|
1962
|
+
{
|
|
1963
|
+
type: 'text',
|
|
1964
|
+
text: `# Enhanced ADR Generation from PRD: ${prdPath}
|
|
1965
|
+
|
|
1966
|
+
## Advanced Prompt-Driven ADR Generation Process
|
|
1967
|
+
|
|
1968
|
+
This tool uses a 100% prompt-driven architecture enhanced with advanced prompting techniques:
|
|
1969
|
+
|
|
1970
|
+
### Enhancement Features
|
|
1971
|
+
- **APE Optimization**: ${enhancedMode && promptOptimization ? '✅ Enabled - Prompts optimized for superior quality' : '❌ Disabled'}
|
|
1972
|
+
- **Knowledge Generation**: ${enhancedMode && knowledgeEnhancement ? '✅ Enabled - Domain knowledge enhanced analysis' : '❌ Disabled'}
|
|
1973
|
+
- **PRD Type Optimization**: ${prdType} - Tailored for specific domain requirements
|
|
1974
|
+
- **Enhanced Mode**: ${enhancedMode ? '✅ Enabled - All advanced features active' : '❌ Disabled - Basic mode'}
|
|
1975
|
+
|
|
1976
|
+
### Enhanced AI Agent Workflow
|
|
1977
|
+
|
|
1978
|
+
1. **Validate PRD file existence** using secure file system operations
|
|
1979
|
+
2. **Read PRD content** safely with proper security validation
|
|
1980
|
+
3. **Apply domain knowledge** to enhance understanding (if enabled)
|
|
1981
|
+
4. **Generate optimized ADRs** using APE-enhanced prompts (if enabled)
|
|
1982
|
+
5. **Create enhanced ADR files** in the specified output directory: ${outputDirectory}
|
|
1983
|
+
|
|
1984
|
+
## Execution Instructions
|
|
1985
|
+
|
|
1986
|
+
Please execute the following enhanced comprehensive prompt:
|
|
1987
|
+
|
|
1988
|
+
${adrPrompt}
|
|
1989
|
+
|
|
1990
|
+
## Advanced Features
|
|
1991
|
+
|
|
1992
|
+
${enhancedMode && knowledgeEnhancement
|
|
1993
|
+
? `
|
|
1994
|
+
### Knowledge Enhancement
|
|
1995
|
+
- Domain-specific architectural knowledge has been generated
|
|
1996
|
+
- PRD analysis is enhanced with ${prdType} domain expertise
|
|
1997
|
+
- ADR decisions leverage domain best practices and patterns
|
|
1998
|
+
`
|
|
1999
|
+
: ''}
|
|
2000
|
+
|
|
2001
|
+
${enhancedMode && promptOptimization
|
|
2002
|
+
? `
|
|
2003
|
+
### APE Optimization
|
|
2004
|
+
- Prompts have been automatically optimized for quality
|
|
2005
|
+
- Enhanced evaluation criteria ensure superior ADR generation
|
|
2006
|
+
- Optimization focused on task completion, clarity, and specificity
|
|
2007
|
+
`
|
|
2008
|
+
: ''}
|
|
2009
|
+
|
|
2010
|
+
## Security and Validation
|
|
2011
|
+
|
|
2012
|
+
- All file operations include security validation
|
|
2013
|
+
- Path traversal protection is enabled
|
|
2014
|
+
- System directory access is prevented
|
|
2015
|
+
- User confirmation is required for file creation
|
|
2016
|
+
- Content validation ensures safe enhanced ADR generation
|
|
2017
|
+
|
|
2018
|
+
## Expected Enhanced Workflow
|
|
2019
|
+
|
|
2020
|
+
1. Execute file existence check for: ${prdPath}
|
|
2021
|
+
2. If file exists, read PRD content securely
|
|
2022
|
+
3. Apply domain knowledge to enhance PRD understanding
|
|
2023
|
+
4. Analyze PRD content using optimized prompts
|
|
2024
|
+
5. Generate domain-enhanced individual ADRs for each decision
|
|
2025
|
+
6. Create file creation prompts for each enhanced ADR
|
|
2026
|
+
7. Confirm with user before writing files to: ${outputDirectory}
|
|
2027
|
+
|
|
2028
|
+
The enhanced process maintains full traceability from PRD requirements to generated ADRs while providing superior quality through advanced prompting techniques and ensuring security and user control over file operations.`,
|
|
2029
|
+
},
|
|
2030
|
+
],
|
|
2031
|
+
};
|
|
2032
|
+
}
|
|
2033
|
+
}
|
|
2034
|
+
catch (error) {
|
|
2035
|
+
throw new McpAdrError(`Failed to generate ADR prompts from PRD: ${error instanceof Error ? error.message : String(error)}`, 'PROMPT_GENERATION_ERROR');
|
|
2036
|
+
}
|
|
2037
|
+
}
|
|
2038
|
+
async compareAdrProgress(args) {
|
|
2039
|
+
const { todoPath = 'TODO.md', adrDirectory = this.config.adrDirectory, projectPath = this.config.projectPath, environment = 'auto-detect', environmentConfig = {}, validationType = 'full', includeFileChecks = true, includeRuleValidation = true, deepCodeAnalysis = true, functionalValidation = true, strictMode = true, environmentValidation = true, } = args;
|
|
2040
|
+
const { getAdrDirectoryPath } = await import('./utils/config.js');
|
|
2041
|
+
const path = await import('path');
|
|
2042
|
+
// Resolve paths
|
|
2043
|
+
const absoluteTodoPath = path.resolve(projectPath, todoPath);
|
|
2044
|
+
const absoluteAdrPath = adrDirectory
|
|
2045
|
+
? path.resolve(projectPath, adrDirectory)
|
|
2046
|
+
: getAdrDirectoryPath(this.config);
|
|
2047
|
+
this.logger.info(`Comparing ADR progress: TODO(${absoluteTodoPath}) vs ADRs(${absoluteAdrPath}) vs Environment(${projectPath}) [env: ${environment}]`);
|
|
2048
|
+
// Environment validation and auto-detection
|
|
2049
|
+
let detectedEnvironment = environment;
|
|
2050
|
+
let finalEnvironmentConfig = { ...environmentConfig };
|
|
2051
|
+
if (environmentValidation &&
|
|
2052
|
+
(validationType === 'full' || validationType === 'environment-only')) {
|
|
2053
|
+
try {
|
|
2054
|
+
const envResult = await this.detectAndValidateEnvironment(projectPath, environment, environmentConfig);
|
|
2055
|
+
detectedEnvironment = envResult.detectedEnvironment;
|
|
2056
|
+
finalEnvironmentConfig = { ...finalEnvironmentConfig, ...envResult.environmentConfig };
|
|
2057
|
+
this.logger.info(`Environment detection result: ${detectedEnvironment}`);
|
|
2058
|
+
}
|
|
2059
|
+
catch (error) {
|
|
2060
|
+
this.logger.warn(`Environment detection failed: ${error instanceof Error ? error.message : String(error)}`);
|
|
2061
|
+
}
|
|
2062
|
+
}
|
|
2063
|
+
try {
|
|
2064
|
+
// Step 1: Read TODO.md file directly
|
|
2065
|
+
let todoContent = '';
|
|
2066
|
+
if (validationType === 'full' || validationType === 'todo-only') {
|
|
2067
|
+
try {
|
|
2068
|
+
const fs = await import('fs/promises');
|
|
2069
|
+
todoContent = await fs.readFile(absoluteTodoPath, 'utf-8');
|
|
2070
|
+
}
|
|
2071
|
+
catch (error) {
|
|
2072
|
+
this.logger.warn(`Could not read TODO.md file: ${error instanceof Error ? error.message : String(error)}`);
|
|
2073
|
+
}
|
|
2074
|
+
}
|
|
2075
|
+
// Step 2: Use actual project structure scanning
|
|
2076
|
+
let projectStructure = null;
|
|
2077
|
+
if (validationType === 'full' || validationType === 'environment-only') {
|
|
2078
|
+
try {
|
|
2079
|
+
const { scanProjectStructure } = await import('./utils/actual-file-operations.js');
|
|
2080
|
+
const includeContent = deepCodeAnalysis || functionalValidation;
|
|
2081
|
+
projectStructure = await scanProjectStructure(projectPath, {
|
|
2082
|
+
readContent: includeContent,
|
|
2083
|
+
maxFileSize: includeContent ? 10000 : 0,
|
|
2084
|
+
});
|
|
2085
|
+
}
|
|
2086
|
+
catch (error) {
|
|
2087
|
+
this.logger.warn(`Could not scan project structure: ${error instanceof Error ? error.message : String(error)}`);
|
|
2088
|
+
}
|
|
2089
|
+
}
|
|
2090
|
+
// Perform actual analysis locally instead of relying on AI execution
|
|
2091
|
+
let discoveryResult = null;
|
|
2092
|
+
if (validationType === 'full' || validationType === 'adr-only') {
|
|
2093
|
+
const { discoverAdrsInDirectory } = await import('./utils/adr-discovery.js');
|
|
2094
|
+
discoveryResult = await discoverAdrsInDirectory(absoluteAdrPath, projectPath, {
|
|
2095
|
+
includeContent: true,
|
|
2096
|
+
includeTimeline: false,
|
|
2097
|
+
});
|
|
2098
|
+
}
|
|
2099
|
+
const analysis = await this.performLocalAdrProgressAnalysis({
|
|
2100
|
+
todoContent,
|
|
2101
|
+
todoPath: absoluteTodoPath,
|
|
2102
|
+
discoveredAdrs: discoveryResult?.adrs || [],
|
|
2103
|
+
adrDirectory: absoluteAdrPath,
|
|
2104
|
+
projectStructure: projectStructure || null,
|
|
2105
|
+
projectPath: projectPath,
|
|
2106
|
+
validationType: validationType,
|
|
2107
|
+
includeFileChecks: includeFileChecks,
|
|
2108
|
+
includeRuleValidation: includeRuleValidation,
|
|
2109
|
+
deepCodeAnalysis: deepCodeAnalysis,
|
|
2110
|
+
functionalValidation: functionalValidation,
|
|
2111
|
+
strictMode: strictMode,
|
|
2112
|
+
environment: detectedEnvironment,
|
|
2113
|
+
environmentConfig: finalEnvironmentConfig,
|
|
2114
|
+
environmentValidation: environmentValidation,
|
|
2115
|
+
});
|
|
2116
|
+
return {
|
|
2117
|
+
content: [
|
|
2118
|
+
{
|
|
2119
|
+
type: 'text',
|
|
2120
|
+
text: analysis,
|
|
2121
|
+
},
|
|
2122
|
+
],
|
|
2123
|
+
};
|
|
2124
|
+
}
|
|
2125
|
+
catch (error) {
|
|
2126
|
+
throw new McpAdrError(`Failed to compare ADR progress: ${error instanceof Error ? error.message : String(error)}`, 'VALIDATION_ERROR');
|
|
2127
|
+
}
|
|
2128
|
+
}
|
|
2129
|
+
/**
|
|
2130
|
+
* Detect and validate environment context
|
|
2131
|
+
*/
|
|
2132
|
+
async detectAndValidateEnvironment(projectPath, environment, environmentConfig) {
|
|
2133
|
+
const path = await import('path');
|
|
2134
|
+
const fs = await import('fs/promises');
|
|
2135
|
+
let detectedEnvironment = environment;
|
|
2136
|
+
let finalConfig = { ...environmentConfig };
|
|
2137
|
+
if (environment === 'auto-detect') {
|
|
2138
|
+
// Auto-detect environment based on project structure
|
|
2139
|
+
try {
|
|
2140
|
+
// Check for environment indicator files
|
|
2141
|
+
const envFiles = [
|
|
2142
|
+
'.env.development',
|
|
2143
|
+
'.env.staging',
|
|
2144
|
+
'.env.production',
|
|
2145
|
+
'.env.test',
|
|
2146
|
+
'package.json',
|
|
2147
|
+
'docker-compose.yml',
|
|
2148
|
+
'Dockerfile',
|
|
2149
|
+
];
|
|
2150
|
+
const existingFiles = [];
|
|
2151
|
+
for (const file of envFiles) {
|
|
2152
|
+
try {
|
|
2153
|
+
await fs.access(path.join(projectPath, file));
|
|
2154
|
+
existingFiles.push(file);
|
|
2155
|
+
}
|
|
2156
|
+
catch {
|
|
2157
|
+
// File doesn't exist, continue
|
|
2158
|
+
}
|
|
2159
|
+
}
|
|
2160
|
+
// Environment detection logic
|
|
2161
|
+
if (existingFiles.includes('.env.production') || existingFiles.includes('Dockerfile')) {
|
|
2162
|
+
detectedEnvironment = 'production';
|
|
2163
|
+
}
|
|
2164
|
+
else if (existingFiles.includes('.env.staging')) {
|
|
2165
|
+
detectedEnvironment = 'staging';
|
|
2166
|
+
}
|
|
2167
|
+
else if (existingFiles.includes('.env.test')) {
|
|
2168
|
+
detectedEnvironment = 'testing';
|
|
2169
|
+
}
|
|
2170
|
+
else {
|
|
2171
|
+
detectedEnvironment = 'development';
|
|
2172
|
+
}
|
|
2173
|
+
// Set environment-specific default configurations
|
|
2174
|
+
switch (detectedEnvironment) {
|
|
2175
|
+
case 'production':
|
|
2176
|
+
finalConfig = {
|
|
2177
|
+
securityLevel: 'critical',
|
|
2178
|
+
requiredFiles: ['package.json', 'README.md'],
|
|
2179
|
+
requiredServices: ['monitoring', 'logging'],
|
|
2180
|
+
performanceRequirements: { minUptime: 99.9 },
|
|
2181
|
+
...finalConfig,
|
|
2182
|
+
};
|
|
2183
|
+
break;
|
|
2184
|
+
case 'staging':
|
|
2185
|
+
finalConfig = {
|
|
2186
|
+
securityLevel: 'high',
|
|
2187
|
+
requiredFiles: ['package.json'],
|
|
2188
|
+
requiredServices: ['testing', 'monitoring'],
|
|
2189
|
+
performanceRequirements: { minUptime: 95 },
|
|
2190
|
+
...finalConfig,
|
|
2191
|
+
};
|
|
2192
|
+
break;
|
|
2193
|
+
case 'testing':
|
|
2194
|
+
finalConfig = {
|
|
2195
|
+
securityLevel: 'medium',
|
|
2196
|
+
requiredFiles: ['package.json'],
|
|
2197
|
+
requiredServices: ['testing'],
|
|
2198
|
+
performanceRequirements: {},
|
|
2199
|
+
...finalConfig,
|
|
2200
|
+
};
|
|
2201
|
+
break;
|
|
2202
|
+
default: // development
|
|
2203
|
+
finalConfig = {
|
|
2204
|
+
securityLevel: 'medium',
|
|
2205
|
+
requiredFiles: ['package.json'],
|
|
2206
|
+
requiredServices: [],
|
|
2207
|
+
performanceRequirements: {},
|
|
2208
|
+
...finalConfig,
|
|
2209
|
+
};
|
|
2210
|
+
}
|
|
2211
|
+
}
|
|
2212
|
+
catch (error) {
|
|
2213
|
+
this.logger.warn(`Environment auto-detection failed: ${error instanceof Error ? error.message : String(error)}`);
|
|
2214
|
+
detectedEnvironment = 'development'; // fallback
|
|
2215
|
+
}
|
|
2216
|
+
}
|
|
2217
|
+
return { detectedEnvironment, environmentConfig: finalConfig };
|
|
2218
|
+
}
|
|
2219
|
+
/**
|
|
2220
|
+
* Perform local ADR progress analysis without relying on AI execution
|
|
2221
|
+
*/
|
|
2222
|
+
async performLocalAdrProgressAnalysis(params) {
|
|
2223
|
+
const { todoContent, todoPath, discoveredAdrs, adrDirectory, projectStructure, projectPath, validationType, includeFileChecks, includeRuleValidation, deepCodeAnalysis, functionalValidation, strictMode, environment, environmentConfig, environmentValidation, } = params;
|
|
2224
|
+
const currentDate = new Date().toISOString().split('T')[0];
|
|
2225
|
+
// Parse TODO content to extract tasks
|
|
2226
|
+
const todoTasks = this.parseTodoTasks(todoContent);
|
|
2227
|
+
// Basic analysis
|
|
2228
|
+
const totalAdrs = discoveredAdrs.length;
|
|
2229
|
+
const totalTasks = todoTasks.length;
|
|
2230
|
+
const completedTasks = todoTasks.filter(task => task.completed).length;
|
|
2231
|
+
// Calculate alignment score (simplified, now environment-aware)
|
|
2232
|
+
const adrTaskMapping = this.mapTasksToAdrs(todoTasks, discoveredAdrs, environment, environmentConfig);
|
|
2233
|
+
const alignedTasks = adrTaskMapping.aligned.length;
|
|
2234
|
+
let alignmentScore = totalTasks > 0 ? Math.round((alignedTasks / totalTasks) * 100) : 0;
|
|
2235
|
+
// Environment-aware scoring adjustments
|
|
2236
|
+
if (environmentValidation && environmentConfig) {
|
|
2237
|
+
const envScore = this.calculateEnvironmentScore(projectStructure, environment, environmentConfig);
|
|
2238
|
+
alignmentScore = Math.round((alignmentScore + envScore) / 2); // Blend scores
|
|
2239
|
+
}
|
|
2240
|
+
// File existence checks
|
|
2241
|
+
let fileCheckResults = '';
|
|
2242
|
+
if (includeFileChecks && projectStructure) {
|
|
2243
|
+
fileCheckResults = this.performFileExistenceChecks(todoTasks, projectStructure);
|
|
2244
|
+
}
|
|
2245
|
+
// Environment compliance checks
|
|
2246
|
+
let environmentAnalysisResults = '';
|
|
2247
|
+
if (environmentValidation && environmentConfig) {
|
|
2248
|
+
environmentAnalysisResults = this.performEnvironmentComplianceAnalysis(projectStructure, environment, environmentConfig, strictMode);
|
|
2249
|
+
}
|
|
2250
|
+
// Mock vs Production analysis
|
|
2251
|
+
let mockAnalysisResults = '';
|
|
2252
|
+
if (deepCodeAnalysis && projectStructure) {
|
|
2253
|
+
mockAnalysisResults = this.performMockVsProductionAnalysis(projectStructure, strictMode);
|
|
2254
|
+
}
|
|
2255
|
+
return `# ADR Progress Validation Report
|
|
2256
|
+
|
|
2257
|
+
**Validation Date**: ${currentDate}
|
|
2258
|
+
**Validation Type**: ${validationType}
|
|
2259
|
+
**Project Path**: ${projectPath}
|
|
2260
|
+
**TODO Path**: ${todoPath}
|
|
2261
|
+
**ADR Directory**: ${adrDirectory}
|
|
2262
|
+
**Environment**: ${environment}${environmentValidation ? ` (validation enabled)` : ''}
|
|
2263
|
+
|
|
2264
|
+
## Summary
|
|
2265
|
+
- **Total ADRs**: ${totalAdrs}
|
|
2266
|
+
- **Total TODO Tasks**: ${totalTasks}
|
|
2267
|
+
- **Completed Tasks**: ${completedTasks}
|
|
2268
|
+
- **Alignment Score**: ${alignmentScore}%
|
|
2269
|
+
- **Compliance Score**: ${Math.max(alignmentScore - 10, 0)}%
|
|
2270
|
+
- **Environment**: ${environment}
|
|
2271
|
+
|
|
2272
|
+
## Configuration
|
|
2273
|
+
- **File Checks**: ${includeFileChecks ? 'Enabled' : 'Disabled'}
|
|
2274
|
+
- **Rule Validation**: ${includeRuleValidation ? 'Enabled' : 'Disabled'}
|
|
2275
|
+
- **Deep Code Analysis**: ${deepCodeAnalysis ? 'Enabled' : 'Disabled'}
|
|
2276
|
+
- **Functional Validation**: ${functionalValidation ? 'Enabled' : 'Disabled'}
|
|
2277
|
+
- **Strict Mode**: ${strictMode ? 'Enabled - High scrutiny for mock vs production' : 'Disabled'}
|
|
2278
|
+
- **Environment Validation**: ${environmentValidation ? 'Enabled' : 'Disabled'}
|
|
2279
|
+
|
|
2280
|
+
## Environment Context
|
|
2281
|
+
- **Target Environment**: ${environment}
|
|
2282
|
+
- **Security Level**: ${environmentConfig?.['securityLevel'] || 'Not specified'}
|
|
2283
|
+
- **Required Files**: ${environmentConfig?.['requiredFiles']?.length || 0} files
|
|
2284
|
+
- **Required Services**: ${environmentConfig?.['requiredServices']?.length || 0} services
|
|
2285
|
+
|
|
2286
|
+
## ADR Discovery Results
|
|
2287
|
+
${totalAdrs > 0
|
|
2288
|
+
? `Found ${totalAdrs} ADRs:\n${discoveredAdrs
|
|
2289
|
+
.map((adr, i) => {
|
|
2290
|
+
const adrRecord = adr;
|
|
2291
|
+
return `${i + 1}. **${adrRecord['title']}** (${adrRecord['status']}) - ${adrRecord['filename']}`;
|
|
2292
|
+
})
|
|
2293
|
+
.join('\n')}`
|
|
2294
|
+
: 'No ADRs found in the specified directory.'}
|
|
2295
|
+
|
|
2296
|
+
## TODO Task Analysis
|
|
2297
|
+
${totalTasks > 0
|
|
2298
|
+
? `Found ${totalTasks} tasks:\n${todoTasks
|
|
2299
|
+
.map((task, i) => `${i + 1}. ${task.completed ? '✅' : '⏳'} ${task.title}`)
|
|
2300
|
+
.join('\n')}`
|
|
2301
|
+
: 'No tasks found in TODO.md file.'}
|
|
2302
|
+
|
|
2303
|
+
## Alignment Analysis
|
|
2304
|
+
|
|
2305
|
+
### ✅ Properly Aligned Tasks
|
|
2306
|
+
${adrTaskMapping.aligned.length > 0
|
|
2307
|
+
? adrTaskMapping.aligned
|
|
2308
|
+
.map(task => `- ${task.title}: Corresponds to ADR requirements`)
|
|
2309
|
+
.join('\n')
|
|
2310
|
+
: '- No aligned tasks identified'}
|
|
2311
|
+
|
|
2312
|
+
### ⚠️ Misaligned Tasks
|
|
2313
|
+
${adrTaskMapping.misaligned.length > 0
|
|
2314
|
+
? adrTaskMapping.misaligned
|
|
2315
|
+
.map(task => `- ${task.title}: May not fully align with ADR specifications`)
|
|
2316
|
+
.join('\n')
|
|
2317
|
+
: '- No misaligned tasks identified'}
|
|
2318
|
+
|
|
2319
|
+
### ❌ Missing Tasks
|
|
2320
|
+
${adrTaskMapping.missing.length > 0
|
|
2321
|
+
? adrTaskMapping.missing.map(gap => `- ${gap}: Required by ADRs but not in TODO`).join('\n')
|
|
2322
|
+
: '- No obvious missing tasks identified'}
|
|
2323
|
+
|
|
2324
|
+
## Implementation Status
|
|
2325
|
+
|
|
2326
|
+
${fileCheckResults || '### File Existence Validation\n- File checks disabled or no project structure available'}
|
|
2327
|
+
|
|
2328
|
+
${environmentAnalysisResults || ''}
|
|
2329
|
+
|
|
2330
|
+
${mockAnalysisResults || ''}
|
|
2331
|
+
|
|
2332
|
+
## Recommendations
|
|
2333
|
+
|
|
2334
|
+
### High Priority Actions
|
|
2335
|
+
${alignmentScore < 70
|
|
2336
|
+
? '1. **Improve ADR-TODO Alignment**: Review TODO tasks against ADR requirements\n2. **Add Missing Tasks**: Identify and add tasks required by ADRs'
|
|
2337
|
+
: '1. **Maintain Current Alignment**: Continue following ADR specifications'}
|
|
2338
|
+
${completedTasks < totalTasks * 0.5
|
|
2339
|
+
? '\n3. **Accelerate Implementation**: Focus on completing pending tasks'
|
|
2340
|
+
: ''}
|
|
2341
|
+
${environmentValidation && environment === 'production' && alignmentScore < 90
|
|
2342
|
+
? '\n4. **⚠️ Production Environment Warning**: Current alignment may not meet production requirements'
|
|
2343
|
+
: ''}
|
|
2344
|
+
|
|
2345
|
+
### Medium Priority Actions
|
|
2346
|
+
1. **Review Implementation Quality**: ${strictMode ? 'Strict mode analysis above shows' : 'Consider enabling strict mode for'} detailed quality assessment
|
|
2347
|
+
2. **Update Documentation**: Ensure TODO.md reflects current project state
|
|
2348
|
+
${environmentValidation
|
|
2349
|
+
? `3. **Environment Compliance**: Ensure ${environment} environment requirements are met`
|
|
2350
|
+
: ''}
|
|
2351
|
+
|
|
2352
|
+
### Low Priority Actions
|
|
2353
|
+
1. **Optimize Workflow**: Consider tools for automated ADR-TODO synchronization
|
|
2354
|
+
2. **Regular Validation**: Schedule periodic ADR progress reviews
|
|
2355
|
+
|
|
2356
|
+
## Next Steps
|
|
2357
|
+
1. Address high-priority alignment issues identified above
|
|
2358
|
+
2. ${totalTasks === 0 ? 'Create initial TODO.md from ADR requirements' : 'Update TODO.md with missing tasks'}
|
|
2359
|
+
3. ${includeFileChecks ? 'Verify implementation of completed tasks' : 'Enable file checks for detailed implementation verification'}
|
|
2360
|
+
4. ${includeRuleValidation ? 'Resolve architectural rule compliance violations' : 'Enable rule validation for compliance checking'}
|
|
2361
|
+
\`\`\`
|
|
2362
|
+
|
|
2363
|
+
To re-run this validation with strict mode:
|
|
2364
|
+
\`\`\`json
|
|
2365
|
+
{
|
|
2366
|
+
"tool": "compare_adr_progress",
|
|
2367
|
+
"args": {
|
|
2368
|
+
"todoPath": "${todoPath}",
|
|
2369
|
+
"adrDirectory": "${adrDirectory}",
|
|
2370
|
+
"validationType": "full",
|
|
2371
|
+
"deepCodeAnalysis": true,
|
|
2372
|
+
"functionalValidation": true,
|
|
2373
|
+
"strictMode": true
|
|
2374
|
+
}
|
|
2375
|
+
}
|
|
2376
|
+
\`\`\`
|
|
2377
|
+
`;
|
|
2378
|
+
}
|
|
2379
|
+
/**
|
|
2380
|
+
* Parse TODO.md content to extract tasks
|
|
2381
|
+
*/
|
|
2382
|
+
parseTodoTasks(todoContent) {
|
|
2383
|
+
if (!todoContent)
|
|
2384
|
+
return [];
|
|
2385
|
+
const lines = todoContent.split('\n');
|
|
2386
|
+
const tasks = [];
|
|
2387
|
+
for (const line of lines) {
|
|
2388
|
+
let pos = 0;
|
|
2389
|
+
while (pos < line.length && (line[pos] === ' ' || line[pos] === '\t'))
|
|
2390
|
+
pos++;
|
|
2391
|
+
if (pos >= line.length || (line[pos] !== '-' && line[pos] !== '*'))
|
|
2392
|
+
continue;
|
|
2393
|
+
pos++;
|
|
2394
|
+
while (pos < line.length && (line[pos] === ' ' || line[pos] === '\t'))
|
|
2395
|
+
pos++;
|
|
2396
|
+
if (pos < line.length && line[pos] === '[') {
|
|
2397
|
+
const checkbox = line[pos + 1];
|
|
2398
|
+
if (checkbox &&
|
|
2399
|
+
(checkbox === 'x' || checkbox === 'X' || checkbox === ' ' || checkbox === '\t') &&
|
|
2400
|
+
line[pos + 2] === ']') {
|
|
2401
|
+
pos += 3;
|
|
2402
|
+
while (pos < line.length && (line[pos] === ' ' || line[pos] === '\t'))
|
|
2403
|
+
pos++;
|
|
2404
|
+
const title = line.slice(pos).trim();
|
|
2405
|
+
if (title.length > 0) {
|
|
2406
|
+
tasks.push({ title, completed: checkbox.toLowerCase() === 'x' });
|
|
2407
|
+
}
|
|
2408
|
+
continue;
|
|
2409
|
+
}
|
|
2410
|
+
}
|
|
2411
|
+
const title = line.slice(pos).trim();
|
|
2412
|
+
if (title.length > 3) {
|
|
2413
|
+
tasks.push({ title, completed: false });
|
|
2414
|
+
}
|
|
2415
|
+
}
|
|
2416
|
+
return tasks;
|
|
2417
|
+
}
|
|
2418
|
+
/**
|
|
2419
|
+
* Map TODO tasks to ADRs to identify alignment (now environment-aware)
|
|
2420
|
+
*/
|
|
2421
|
+
mapTasksToAdrs(tasks, adrs, environment, environmentConfig) {
|
|
2422
|
+
const aligned = [];
|
|
2423
|
+
const misaligned = [];
|
|
2424
|
+
const missing = [];
|
|
2425
|
+
// Simple keyword matching for alignment detection
|
|
2426
|
+
const adrKeywords = adrs.flatMap(adr => {
|
|
2427
|
+
const adrRecord = adr;
|
|
2428
|
+
return [
|
|
2429
|
+
String(adrRecord['title'] || '').toLowerCase(),
|
|
2430
|
+
...String(adrRecord['decision'] || '')
|
|
2431
|
+
.toLowerCase()
|
|
2432
|
+
.split(/\s+/)
|
|
2433
|
+
.filter((w) => w.length > 4),
|
|
2434
|
+
...String(adrRecord['context'] || '')
|
|
2435
|
+
.toLowerCase()
|
|
2436
|
+
.split(/\s+/)
|
|
2437
|
+
.filter((w) => w.length > 4),
|
|
2438
|
+
];
|
|
2439
|
+
});
|
|
2440
|
+
// Environment-specific keywords that should be prioritized
|
|
2441
|
+
const envKeywords = [];
|
|
2442
|
+
if (environment && environmentConfig) {
|
|
2443
|
+
if (environment === 'production') {
|
|
2444
|
+
envKeywords.push('deploy', 'production', 'monitoring', 'security', 'performance');
|
|
2445
|
+
}
|
|
2446
|
+
else if (environment === 'staging') {
|
|
2447
|
+
envKeywords.push('test', 'staging', 'integration', 'validation');
|
|
2448
|
+
}
|
|
2449
|
+
else if (environment === 'development') {
|
|
2450
|
+
envKeywords.push('setup', 'development', 'local', 'debug');
|
|
2451
|
+
}
|
|
2452
|
+
}
|
|
2453
|
+
for (const task of tasks) {
|
|
2454
|
+
const taskLower = task.title.toLowerCase();
|
|
2455
|
+
const firstWord = taskLower.split(' ')[0] || '';
|
|
2456
|
+
const hasKeywordMatch = adrKeywords.some(keyword => taskLower.includes(keyword) || keyword.includes(firstWord));
|
|
2457
|
+
// Environment-aware alignment scoring
|
|
2458
|
+
const hasEnvKeywordMatch = envKeywords.some(keyword => taskLower.includes(keyword));
|
|
2459
|
+
if (hasKeywordMatch || hasEnvKeywordMatch) {
|
|
2460
|
+
aligned.push(task);
|
|
2461
|
+
}
|
|
2462
|
+
else {
|
|
2463
|
+
misaligned.push(task);
|
|
2464
|
+
}
|
|
2465
|
+
}
|
|
2466
|
+
// Identify potential missing tasks based on ADR content
|
|
2467
|
+
for (const adr of adrs) {
|
|
2468
|
+
const adrRecord = adr;
|
|
2469
|
+
if (adrRecord['status'] === 'accepted' && adrRecord['decision']) {
|
|
2470
|
+
const decisionWords = String(adrRecord['decision']).toLowerCase().split(/\s+/);
|
|
2471
|
+
const implementationWords = [
|
|
2472
|
+
'implement',
|
|
2473
|
+
'create',
|
|
2474
|
+
'build',
|
|
2475
|
+
'develop',
|
|
2476
|
+
'add',
|
|
2477
|
+
'setup',
|
|
2478
|
+
'configure',
|
|
2479
|
+
];
|
|
2480
|
+
if (implementationWords.some(word => decisionWords.includes(word))) {
|
|
2481
|
+
const adrTitle = String(adrRecord['title'] || '');
|
|
2482
|
+
const adrFirstWord = adrTitle.toLowerCase().split(' ')[0] || '';
|
|
2483
|
+
const hasCorrespondingTask = tasks.some(task => task.title.toLowerCase().includes(adrFirstWord));
|
|
2484
|
+
if (!hasCorrespondingTask) {
|
|
2485
|
+
missing.push(`Implement ${adrTitle}`);
|
|
2486
|
+
}
|
|
2487
|
+
}
|
|
2488
|
+
}
|
|
2489
|
+
}
|
|
2490
|
+
// Environment-specific missing tasks
|
|
2491
|
+
if (environment && environmentConfig) {
|
|
2492
|
+
const envConfig = environmentConfig;
|
|
2493
|
+
if (envConfig['requiredFiles']) {
|
|
2494
|
+
for (const file of envConfig['requiredFiles']) {
|
|
2495
|
+
const hasFileTask = tasks.some(task => task.title.toLowerCase().includes(file.toLowerCase()));
|
|
2496
|
+
if (!hasFileTask) {
|
|
2497
|
+
missing.push(`Create ${file} for ${environment} environment`);
|
|
2498
|
+
}
|
|
2499
|
+
}
|
|
2500
|
+
}
|
|
2501
|
+
if (envConfig['requiredServices']) {
|
|
2502
|
+
for (const service of envConfig['requiredServices']) {
|
|
2503
|
+
const hasServiceTask = tasks.some(task => task.title.toLowerCase().includes(service.toLowerCase()));
|
|
2504
|
+
if (!hasServiceTask) {
|
|
2505
|
+
missing.push(`Setup ${service} service for ${environment}`);
|
|
2506
|
+
}
|
|
2507
|
+
}
|
|
2508
|
+
}
|
|
2509
|
+
}
|
|
2510
|
+
return { aligned, misaligned, missing };
|
|
2511
|
+
}
|
|
2512
|
+
/**
|
|
2513
|
+
* Check file existence for completed tasks
|
|
2514
|
+
*/
|
|
2515
|
+
performFileExistenceChecks(tasks, projectStructure) {
|
|
2516
|
+
if (!projectStructure)
|
|
2517
|
+
return '- Project structure not available';
|
|
2518
|
+
const allFiles = [
|
|
2519
|
+
...(projectStructure.packageFiles || []),
|
|
2520
|
+
...(projectStructure.configFiles || []),
|
|
2521
|
+
...(projectStructure.buildFiles || []),
|
|
2522
|
+
...(projectStructure.dockerFiles || []),
|
|
2523
|
+
...(projectStructure.ciFiles || []),
|
|
2524
|
+
...(projectStructure.scriptFiles || []),
|
|
2525
|
+
];
|
|
2526
|
+
let results = '### File Existence Validation\n';
|
|
2527
|
+
let checkCount = 0;
|
|
2528
|
+
for (const task of tasks) {
|
|
2529
|
+
if (task.completed) {
|
|
2530
|
+
// Simple heuristic: look for files mentioned in task title
|
|
2531
|
+
const taskLower = task.title.toLowerCase();
|
|
2532
|
+
const mentionedFiles = allFiles.filter(file => taskLower.includes(file.filename.toLowerCase()) ||
|
|
2533
|
+
taskLower.includes(file.filename.replace(/\.[^.]+$/, '').toLowerCase()));
|
|
2534
|
+
if (mentionedFiles.length > 0) {
|
|
2535
|
+
results += `- ✅ **${task.title}**: Found related files (${mentionedFiles.map(f => f.filename).join(', ')})\n`;
|
|
2536
|
+
checkCount++;
|
|
2537
|
+
}
|
|
2538
|
+
else if (taskLower.includes('file') ||
|
|
2539
|
+
taskLower.includes('create') ||
|
|
2540
|
+
taskLower.includes('implement')) {
|
|
2541
|
+
results += `- ⚠️ **${task.title}**: No clearly related files found\n`;
|
|
2542
|
+
checkCount++;
|
|
2543
|
+
}
|
|
2544
|
+
}
|
|
2545
|
+
}
|
|
2546
|
+
if (checkCount === 0) {
|
|
2547
|
+
results += '- No file-related completed tasks to validate\n';
|
|
2548
|
+
}
|
|
2549
|
+
return results;
|
|
2550
|
+
}
|
|
2551
|
+
/**
|
|
2552
|
+
* Analyze code for mock vs production implementation
|
|
2553
|
+
*/
|
|
2554
|
+
performMockVsProductionAnalysis(projectStructure, strictMode) {
|
|
2555
|
+
if (!projectStructure)
|
|
2556
|
+
return '';
|
|
2557
|
+
const codeFiles = [
|
|
2558
|
+
...(projectStructure.buildFiles || []),
|
|
2559
|
+
...(projectStructure.configFiles || []),
|
|
2560
|
+
].filter(file => file.content && file.content !== '[Binary or unreadable file]');
|
|
2561
|
+
if (codeFiles.length === 0)
|
|
2562
|
+
return '';
|
|
2563
|
+
let results = '\n### Mock vs Production Code Analysis\n';
|
|
2564
|
+
let mockIndicators = 0;
|
|
2565
|
+
let productionIndicators = 0;
|
|
2566
|
+
const mockPatterns = [
|
|
2567
|
+
/TODO:/gi,
|
|
2568
|
+
/FIXME:/gi,
|
|
2569
|
+
/NotImplementedException/gi,
|
|
2570
|
+
/throw.*not.*implement/gi,
|
|
2571
|
+
/return.*mock/gi,
|
|
2572
|
+
/placeholder/gi,
|
|
2573
|
+
/stub/gi,
|
|
2574
|
+
/return\s+null;/gi,
|
|
2575
|
+
/return\s+""/gi,
|
|
2576
|
+
/return\s+\[\]/gi,
|
|
2577
|
+
/return\s+{}/gi,
|
|
2578
|
+
];
|
|
2579
|
+
const productionPatterns = [
|
|
2580
|
+
/error\s+handling/gi,
|
|
2581
|
+
/try\s*{/gi,
|
|
2582
|
+
/catch\s*\(/gi,
|
|
2583
|
+
/validate/gi,
|
|
2584
|
+
/authentication/gi,
|
|
2585
|
+
/authorization/gi,
|
|
2586
|
+
/database/gi,
|
|
2587
|
+
/api/gi,
|
|
2588
|
+
/config/gi,
|
|
2589
|
+
];
|
|
2590
|
+
for (const file of codeFiles.slice(0, 10)) {
|
|
2591
|
+
// Limit analysis to prevent overwhelming output
|
|
2592
|
+
const content = file.content;
|
|
2593
|
+
const fileMockCount = mockPatterns.reduce((count, pattern) => count + (content.match(pattern) || []).length, 0);
|
|
2594
|
+
const fileProdCount = productionPatterns.reduce((count, pattern) => count + (content.match(pattern) || []).length, 0);
|
|
2595
|
+
mockIndicators += fileMockCount;
|
|
2596
|
+
productionIndicators += fileProdCount;
|
|
2597
|
+
if (fileMockCount > 0 || fileProdCount > 2) {
|
|
2598
|
+
const status = fileMockCount > fileProdCount
|
|
2599
|
+
? '❌ **Mock/Stub**'
|
|
2600
|
+
: fileProdCount > fileMockCount * 2
|
|
2601
|
+
? '✅ **Production Ready**'
|
|
2602
|
+
: '⚠️ **Partial Implementation**';
|
|
2603
|
+
results += `- ${status}: ${file.filename} `;
|
|
2604
|
+
if (fileMockCount > 0) {
|
|
2605
|
+
results += `(${fileMockCount} mock indicators) `;
|
|
2606
|
+
}
|
|
2607
|
+
if (fileProdCount > 0) {
|
|
2608
|
+
results += `(${fileProdCount} production indicators)`;
|
|
2609
|
+
}
|
|
2610
|
+
results += '\n';
|
|
2611
|
+
}
|
|
2612
|
+
}
|
|
2613
|
+
results += `\n#### Overall Code Quality Assessment\n`;
|
|
2614
|
+
results += `- **Mock Indicators Found**: ${mockIndicators} instances\n`;
|
|
2615
|
+
results += `- **Production Indicators Found**: ${productionIndicators} instances\n`;
|
|
2616
|
+
if (strictMode) {
|
|
2617
|
+
const qualityScore = productionIndicators > mockIndicators * 2
|
|
2618
|
+
? 'Good'
|
|
2619
|
+
: productionIndicators > mockIndicators
|
|
2620
|
+
? 'Fair'
|
|
2621
|
+
: 'Needs Improvement';
|
|
2622
|
+
results += `- **Quality Assessment**: ${qualityScore}\n`;
|
|
2623
|
+
if (mockIndicators > 0) {
|
|
2624
|
+
results += `- **⚠️ Strict Mode Warning**: Found ${mockIndicators} potential mock/stub indicators\n`;
|
|
2625
|
+
}
|
|
2626
|
+
}
|
|
2627
|
+
return results;
|
|
2628
|
+
}
|
|
2629
|
+
/**
|
|
2630
|
+
* Calculate environment-specific compliance score
|
|
2631
|
+
*/
|
|
2632
|
+
calculateEnvironmentScore(projectStructure, environment, environmentConfig) {
|
|
2633
|
+
if (!projectStructure || !environmentConfig)
|
|
2634
|
+
return 0;
|
|
2635
|
+
let score = 100; // Start with perfect score
|
|
2636
|
+
// Check required files
|
|
2637
|
+
if (environmentConfig.requiredFiles) {
|
|
2638
|
+
const allFiles = [
|
|
2639
|
+
...(projectStructure.packageFiles || []),
|
|
2640
|
+
...(projectStructure.configFiles || []),
|
|
2641
|
+
...(projectStructure.buildFiles || []),
|
|
2642
|
+
...(projectStructure.dockerFiles || []),
|
|
2643
|
+
...(projectStructure.ciFiles || []),
|
|
2644
|
+
...(projectStructure.scriptFiles || []),
|
|
2645
|
+
];
|
|
2646
|
+
const existingFiles = allFiles.map(f => f.filename);
|
|
2647
|
+
const missingFiles = environmentConfig.requiredFiles.filter((file) => !existingFiles.includes(file));
|
|
2648
|
+
// Deduct 10 points per missing required file
|
|
2649
|
+
score -= missingFiles.length * 10;
|
|
2650
|
+
}
|
|
2651
|
+
// Environment-specific penalties
|
|
2652
|
+
if (environment === 'production') {
|
|
2653
|
+
// Production requires higher standards
|
|
2654
|
+
if (!projectStructure.dockerFiles?.length)
|
|
2655
|
+
score -= 15;
|
|
2656
|
+
if (!projectStructure.ciFiles?.length)
|
|
2657
|
+
score -= 10;
|
|
2658
|
+
}
|
|
2659
|
+
return Math.max(score, 0);
|
|
2660
|
+
}
|
|
2661
|
+
/**
|
|
2662
|
+
* Perform environment compliance analysis
|
|
2663
|
+
*/
|
|
2664
|
+
performEnvironmentComplianceAnalysis(projectStructure, environment, environmentConfig, strictMode) {
|
|
2665
|
+
if (!projectStructure || !environmentConfig) {
|
|
2666
|
+
return '\n### Environment Compliance Analysis\n- Environment analysis disabled or no project structure available\n';
|
|
2667
|
+
}
|
|
2668
|
+
let results = '\n### Environment Compliance Analysis\n';
|
|
2669
|
+
// Required files analysis
|
|
2670
|
+
if (environmentConfig.requiredFiles) {
|
|
2671
|
+
results += `#### Required Files for ${environment} Environment\n`;
|
|
2672
|
+
const allFiles = [
|
|
2673
|
+
...(projectStructure.packageFiles || []),
|
|
2674
|
+
...(projectStructure.configFiles || []),
|
|
2675
|
+
...(projectStructure.buildFiles || []),
|
|
2676
|
+
...(projectStructure.dockerFiles || []),
|
|
2677
|
+
...(projectStructure.ciFiles || []),
|
|
2678
|
+
...(projectStructure.scriptFiles || []),
|
|
2679
|
+
];
|
|
2680
|
+
const existingFiles = allFiles.map(f => f.filename);
|
|
2681
|
+
for (const requiredFile of environmentConfig.requiredFiles) {
|
|
2682
|
+
const exists = existingFiles.includes(requiredFile);
|
|
2683
|
+
results += `- ${exists ? '✅' : '❌'} **${requiredFile}**: ${exists ? 'Found' : 'Missing'}\n`;
|
|
2684
|
+
}
|
|
2685
|
+
}
|
|
2686
|
+
// Security level compliance
|
|
2687
|
+
if (environmentConfig.securityLevel) {
|
|
2688
|
+
results += `\n#### Security Level: ${environmentConfig.securityLevel}\n`;
|
|
2689
|
+
const securityIndicators = this.analyzeSecurityCompliance(projectStructure, environmentConfig.securityLevel);
|
|
2690
|
+
results += securityIndicators;
|
|
2691
|
+
}
|
|
2692
|
+
// Environment-specific recommendations
|
|
2693
|
+
results += `\n#### ${environment} Environment Recommendations\n`;
|
|
2694
|
+
switch (environment) {
|
|
2695
|
+
case 'production':
|
|
2696
|
+
results +=
|
|
2697
|
+
'- ⚠️ **Production Critical**: Ensure monitoring, logging, and backup strategies are implemented\n';
|
|
2698
|
+
results += '- 🔒 **Security**: Implement comprehensive security measures\n';
|
|
2699
|
+
results += '- 📊 **Performance**: Monitor and optimize for production workloads\n';
|
|
2700
|
+
if (strictMode) {
|
|
2701
|
+
results +=
|
|
2702
|
+
'- 🔍 **Strict Mode**: Enhanced validation enabled for production environment\n';
|
|
2703
|
+
}
|
|
2704
|
+
break;
|
|
2705
|
+
case 'staging':
|
|
2706
|
+
results += '- 🧪 **Testing**: Ensure comprehensive test coverage and validation\n';
|
|
2707
|
+
results += '- 📋 **Validation**: Implement environment parity checks\n';
|
|
2708
|
+
break;
|
|
2709
|
+
case 'development':
|
|
2710
|
+
results += '- 🛠️ **Development**: Focus on developer experience and debugging tools\n';
|
|
2711
|
+
results += '- 🔄 **Iteration**: Ensure fast feedback loops\n';
|
|
2712
|
+
break;
|
|
2713
|
+
}
|
|
2714
|
+
return results;
|
|
2715
|
+
}
|
|
2716
|
+
/**
|
|
2717
|
+
* Analyze security compliance based on security level
|
|
2718
|
+
*/
|
|
2719
|
+
analyzeSecurityCompliance(projectStructure, securityLevel) {
|
|
2720
|
+
let results = '';
|
|
2721
|
+
const securityFiles = [
|
|
2722
|
+
...(projectStructure.configFiles || []),
|
|
2723
|
+
...(projectStructure.dockerFiles || []),
|
|
2724
|
+
].filter(file => file.filename.includes('security') ||
|
|
2725
|
+
file.filename.includes('auth') ||
|
|
2726
|
+
file.filename.includes('.env') ||
|
|
2727
|
+
file.filename === 'Dockerfile');
|
|
2728
|
+
const hasSecurityConfig = securityFiles.length > 0;
|
|
2729
|
+
switch (securityLevel) {
|
|
2730
|
+
case 'critical':
|
|
2731
|
+
results += `- ${hasSecurityConfig ? '✅' : '❌'} **Critical Security**: ${hasSecurityConfig ? 'Security configuration found' : 'No security configuration detected'}\n`;
|
|
2732
|
+
if (!hasSecurityConfig) {
|
|
2733
|
+
results += ' - **Action Required**: Implement comprehensive security measures\n';
|
|
2734
|
+
}
|
|
2735
|
+
break;
|
|
2736
|
+
case 'high':
|
|
2737
|
+
results += `- ${hasSecurityConfig ? '✅' : '⚠️'} **High Security**: ${hasSecurityConfig ? 'Some security configuration found' : 'Limited security configuration'}\n`;
|
|
2738
|
+
break;
|
|
2739
|
+
case 'medium':
|
|
2740
|
+
results += `- ℹ️ **Medium Security**: Basic security measures recommended\n`;
|
|
2741
|
+
break;
|
|
2742
|
+
default:
|
|
2743
|
+
results += `- ℹ️ **Security Level**: ${securityLevel} (consider increasing for production)\n`;
|
|
2744
|
+
}
|
|
2745
|
+
return results;
|
|
2746
|
+
}
|
|
2747
|
+
/**
|
|
2748
|
+
* Content masking tool implementations
|
|
2749
|
+
*/
|
|
2750
|
+
async analyzeContentSecurity(args) {
|
|
2751
|
+
const { analyzeContentSecurity } = await import('./tools/content-masking-tool.js');
|
|
2752
|
+
return await analyzeContentSecurity(args);
|
|
2753
|
+
}
|
|
2754
|
+
async generateContentMasking(args) {
|
|
2755
|
+
const { generateContentMasking } = await import('./tools/content-masking-tool.js');
|
|
2756
|
+
return await generateContentMasking(args);
|
|
2757
|
+
}
|
|
2758
|
+
async configureCustomPatterns(args) {
|
|
2759
|
+
const { configureCustomPatterns } = await import('./tools/content-masking-tool.js');
|
|
2760
|
+
return await configureCustomPatterns(args);
|
|
2761
|
+
}
|
|
2762
|
+
async applyBasicContentMasking(args) {
|
|
2763
|
+
const { applyBasicContentMasking } = await import('./tools/content-masking-tool.js');
|
|
2764
|
+
return await applyBasicContentMasking(args);
|
|
2765
|
+
}
|
|
2766
|
+
async validateContentMasking(args) {
|
|
2767
|
+
const { validateContentMasking } = await import('./tools/content-masking-tool.js');
|
|
2768
|
+
return await validateContentMasking(args);
|
|
2769
|
+
}
|
|
2770
|
+
async manageCache(args) {
|
|
2771
|
+
const { action, key } = args;
|
|
2772
|
+
try {
|
|
2773
|
+
const { clearCache, getCacheStats, cleanupCache, invalidateCache } = await import('./utils/cache.js');
|
|
2774
|
+
switch (action) {
|
|
2775
|
+
case 'clear': {
|
|
2776
|
+
const clearPrompt = await clearCache();
|
|
2777
|
+
return {
|
|
2778
|
+
content: [
|
|
2779
|
+
{
|
|
2780
|
+
type: 'text',
|
|
2781
|
+
text: `# Cache Clear Operation
|
|
2782
|
+
|
|
2783
|
+
## AI Delegation Required
|
|
2784
|
+
|
|
2785
|
+
Please execute the following cache clearing operation:
|
|
2786
|
+
|
|
2787
|
+
${clearPrompt.prompt}
|
|
2788
|
+
|
|
2789
|
+
## Implementation Instructions
|
|
2790
|
+
|
|
2791
|
+
${clearPrompt.instructions}
|
|
2792
|
+
|
|
2793
|
+
## Expected Result
|
|
2794
|
+
|
|
2795
|
+
After successful execution, all cache entries will be removed while preserving the cache directory structure and metadata.json file.`,
|
|
2796
|
+
},
|
|
2797
|
+
],
|
|
2798
|
+
};
|
|
2799
|
+
}
|
|
2800
|
+
case 'stats': {
|
|
2801
|
+
const statsPrompt = await getCacheStats();
|
|
2802
|
+
return {
|
|
2803
|
+
content: [
|
|
2804
|
+
{
|
|
2805
|
+
type: 'text',
|
|
2806
|
+
text: `# Cache Statistics Collection
|
|
2807
|
+
|
|
2808
|
+
## AI Delegation Required
|
|
2809
|
+
|
|
2810
|
+
Please execute the following cache statistics collection operation:
|
|
2811
|
+
|
|
2812
|
+
${statsPrompt.prompt}
|
|
2813
|
+
|
|
2814
|
+
## Implementation Instructions
|
|
2815
|
+
|
|
2816
|
+
${statsPrompt.instructions}
|
|
2817
|
+
|
|
2818
|
+
## Expected Information
|
|
2819
|
+
|
|
2820
|
+
The AI agent will provide:
|
|
2821
|
+
- **Total Entries**: Number of cache files
|
|
2822
|
+
- **Total Size**: Combined size of all cache files
|
|
2823
|
+
- **Oldest Entry**: Cache key of the oldest entry
|
|
2824
|
+
- **Newest Entry**: Cache key of the newest entry
|
|
2825
|
+
|
|
2826
|
+
## Cache Directory
|
|
2827
|
+
\`.mcp-adr-cache/\`
|
|
2828
|
+
|
|
2829
|
+
## Cache Types
|
|
2830
|
+
- **Knowledge Graph**: Architectural analysis results (TTL: 1 hour)
|
|
2831
|
+
- **Analysis Report**: Project analysis reports (TTL: 30 minutes)
|
|
2832
|
+
- **ADR List**: ADR inventory and metadata (TTL: 15 minutes)
|
|
2833
|
+
|
|
2834
|
+
## Management
|
|
2835
|
+
Use \`manage_cache\` tool with different actions:
|
|
2836
|
+
- \`clear\`: Remove all cache entries
|
|
2837
|
+
- \`cleanup\`: Remove expired entries only
|
|
2838
|
+
- \`invalidate\`: Remove specific cache entry`,
|
|
2839
|
+
},
|
|
2840
|
+
],
|
|
2841
|
+
};
|
|
2842
|
+
}
|
|
2843
|
+
case 'cleanup': {
|
|
2844
|
+
const cleanupPrompt = await cleanupCache();
|
|
2845
|
+
return {
|
|
2846
|
+
content: [
|
|
2847
|
+
{
|
|
2848
|
+
type: 'text',
|
|
2849
|
+
text: `# Cache Cleanup Operation
|
|
2850
|
+
|
|
2851
|
+
## AI Delegation Required
|
|
2852
|
+
|
|
2853
|
+
Please execute the following cache cleanup operation:
|
|
2854
|
+
|
|
2855
|
+
${cleanupPrompt.prompt}
|
|
2856
|
+
|
|
2857
|
+
## Implementation Instructions
|
|
2858
|
+
|
|
2859
|
+
${cleanupPrompt.instructions}
|
|
2860
|
+
|
|
2861
|
+
## Expected Result
|
|
2862
|
+
|
|
2863
|
+
The AI agent will remove expired cache entries and provide a count of cleaned files.`,
|
|
2864
|
+
},
|
|
2865
|
+
],
|
|
2866
|
+
};
|
|
2867
|
+
}
|
|
2868
|
+
case 'invalidate': {
|
|
2869
|
+
if (!key) {
|
|
2870
|
+
throw new McpAdrError('Cache key is required for invalidate action', 'INVALID_INPUT');
|
|
2871
|
+
}
|
|
2872
|
+
const invalidatePrompt = await invalidateCache(key);
|
|
2873
|
+
return {
|
|
2874
|
+
content: [
|
|
2875
|
+
{
|
|
2876
|
+
type: 'text',
|
|
2877
|
+
text: `# Cache Invalidation Operation
|
|
2878
|
+
|
|
2879
|
+
## AI Delegation Required
|
|
2880
|
+
|
|
2881
|
+
Please execute the following cache invalidation operation:
|
|
2882
|
+
|
|
2883
|
+
${invalidatePrompt.prompt}
|
|
2884
|
+
|
|
2885
|
+
## Implementation Instructions
|
|
2886
|
+
|
|
2887
|
+
${invalidatePrompt.instructions}
|
|
2888
|
+
|
|
2889
|
+
## Target Cache Entry
|
|
2890
|
+
|
|
2891
|
+
**Cache Key**: ${key}
|
|
2892
|
+
|
|
2893
|
+
The AI agent will safely remove the specified cache entry.`,
|
|
2894
|
+
},
|
|
2895
|
+
],
|
|
2896
|
+
};
|
|
2897
|
+
}
|
|
2898
|
+
default:
|
|
2899
|
+
throw new McpAdrError(`Unknown cache action: ${action}`, 'INVALID_INPUT');
|
|
2900
|
+
}
|
|
2901
|
+
}
|
|
2902
|
+
catch (error) {
|
|
2903
|
+
throw new McpAdrError(`Cache management failed: ${error instanceof Error ? error.message : String(error)}`, 'CACHE_ERROR');
|
|
2904
|
+
}
|
|
2905
|
+
}
|
|
2906
|
+
async configureOutputMasking(args) {
|
|
2907
|
+
const { action = 'get', enabled, strategy, customPatterns } = args;
|
|
2908
|
+
try {
|
|
2909
|
+
const { validateMaskingConfig } = await import('./utils/output-masking.js');
|
|
2910
|
+
switch (action) {
|
|
2911
|
+
case 'get': {
|
|
2912
|
+
return {
|
|
2913
|
+
content: [
|
|
2914
|
+
{
|
|
2915
|
+
type: 'text',
|
|
2916
|
+
text: `# Current Output Masking Configuration
|
|
2917
|
+
|
|
2918
|
+
## Settings
|
|
2919
|
+
- **Enabled**: ${this.maskingConfig.enabled}
|
|
2920
|
+
- **Strategy**: ${this.maskingConfig.strategy}
|
|
2921
|
+
- **Custom Patterns**: ${this.maskingConfig.customPatterns?.length || 0} patterns
|
|
2922
|
+
- **Skip Patterns**: ${this.maskingConfig.skipPatterns?.length || 0} patterns
|
|
2923
|
+
|
|
2924
|
+
## Available Strategies
|
|
2925
|
+
- **full**: Replace entire sensitive content with [REDACTED]
|
|
2926
|
+
- **partial**: Show safe prefix/suffix, mask middle (e.g., sk-...****)
|
|
2927
|
+
- **placeholder**: Replace with descriptive placeholders (e.g., <YOUR_API_KEY>)
|
|
2928
|
+
- **environment**: Replace with environment variable references (e.g., \${API_KEY})
|
|
2929
|
+
|
|
2930
|
+
## Configuration
|
|
2931
|
+
Use \`configure_output_masking\` tool with:
|
|
2932
|
+
- \`action: "set"\` to update configuration
|
|
2933
|
+
- \`action: "reset"\` to restore defaults
|
|
2934
|
+
|
|
2935
|
+
## Current Status
|
|
2936
|
+
${this.maskingConfig.enabled ? '✅ Output masking is ACTIVE' : '⚠️ Output masking is DISABLED'}
|
|
2937
|
+
`,
|
|
2938
|
+
},
|
|
2939
|
+
],
|
|
2940
|
+
};
|
|
2941
|
+
}
|
|
2942
|
+
case 'set': {
|
|
2943
|
+
const newConfig = { ...this.maskingConfig };
|
|
2944
|
+
if (typeof enabled === 'boolean') {
|
|
2945
|
+
newConfig.enabled = enabled;
|
|
2946
|
+
}
|
|
2947
|
+
if (strategy &&
|
|
2948
|
+
['full', 'partial', 'placeholder', 'environment'].includes(strategy)) {
|
|
2949
|
+
newConfig.strategy = strategy;
|
|
2950
|
+
}
|
|
2951
|
+
if (Array.isArray(customPatterns)) {
|
|
2952
|
+
newConfig.customPatterns = customPatterns;
|
|
2953
|
+
}
|
|
2954
|
+
const validation = validateMaskingConfig(newConfig);
|
|
2955
|
+
if (!validation.isValid) {
|
|
2956
|
+
throw new McpAdrError(`Invalid masking configuration: ${validation.errors.join(', ')}`, 'INVALID_CONFIG');
|
|
2957
|
+
}
|
|
2958
|
+
this.maskingConfig = newConfig;
|
|
2959
|
+
return {
|
|
2960
|
+
content: [
|
|
2961
|
+
{
|
|
2962
|
+
type: 'text',
|
|
2963
|
+
text: `✅ Output masking configuration updated successfully!
|
|
2964
|
+
|
|
2965
|
+
## New Settings
|
|
2966
|
+
- **Enabled**: ${newConfig.enabled}
|
|
2967
|
+
- **Strategy**: ${newConfig.strategy}
|
|
2968
|
+
- **Custom Patterns**: ${newConfig.customPatterns?.length || 0} patterns
|
|
2969
|
+
|
|
2970
|
+
${newConfig.enabled
|
|
2971
|
+
? '🔒 All MCP tool and resource outputs will now be masked according to the new configuration.'
|
|
2972
|
+
: '⚠️ Output masking is disabled. Sensitive information may be exposed in responses.'}
|
|
2973
|
+
`,
|
|
2974
|
+
},
|
|
2975
|
+
],
|
|
2976
|
+
};
|
|
2977
|
+
}
|
|
2978
|
+
case 'reset': {
|
|
2979
|
+
const { createMaskingConfig } = await import('./utils/output-masking.js');
|
|
2980
|
+
this.maskingConfig = createMaskingConfig();
|
|
2981
|
+
return {
|
|
2982
|
+
content: [
|
|
2983
|
+
{
|
|
2984
|
+
type: 'text',
|
|
2985
|
+
text: `✅ Output masking configuration reset to defaults!
|
|
2986
|
+
|
|
2987
|
+
## Default Settings
|
|
2988
|
+
- **Enabled**: ${this.maskingConfig.enabled}
|
|
2989
|
+
- **Strategy**: ${this.maskingConfig.strategy}
|
|
2990
|
+
- **Custom Patterns**: ${this.maskingConfig.customPatterns?.length || 0} patterns
|
|
2991
|
+
- **Skip Patterns**: ${this.maskingConfig.skipPatterns?.length || 0} patterns
|
|
2992
|
+
|
|
2993
|
+
🔒 Default masking is now active for all outputs.
|
|
2994
|
+
`,
|
|
2995
|
+
},
|
|
2996
|
+
],
|
|
2997
|
+
};
|
|
2998
|
+
}
|
|
2999
|
+
default:
|
|
3000
|
+
throw new McpAdrError(`Unknown masking action: ${action}`, 'INVALID_INPUT');
|
|
3001
|
+
}
|
|
3002
|
+
}
|
|
3003
|
+
catch (error) {
|
|
3004
|
+
throw new McpAdrError(`Output masking configuration failed: ${error instanceof Error ? error.message : String(error)}`, 'CONFIG_ERROR');
|
|
3005
|
+
}
|
|
3006
|
+
}
|
|
3007
|
+
/**
|
|
3008
|
+
* Helper method to get domains based on PRD type
|
|
3009
|
+
*/
|
|
3010
|
+
getPrdTypeDomains(prdType) {
|
|
3011
|
+
const domainMap = {
|
|
3012
|
+
'web-application': ['api-design', 'frontend-architecture', 'database-design', 'security'],
|
|
3013
|
+
'mobile-app': ['mobile-architecture', 'api-design', 'performance-optimization', 'security'],
|
|
3014
|
+
microservices: ['microservices', 'api-design', 'distributed-systems', 'database-design'],
|
|
3015
|
+
'data-platform': [
|
|
3016
|
+
'database-design',
|
|
3017
|
+
'data-architecture',
|
|
3018
|
+
'performance-optimization',
|
|
3019
|
+
'scalability',
|
|
3020
|
+
],
|
|
3021
|
+
'api-service': ['api-design', 'microservices', 'security', 'performance-optimization'],
|
|
3022
|
+
general: ['api-design', 'database-design', 'security'],
|
|
3023
|
+
};
|
|
3024
|
+
return (domainMap[prdType] || domainMap['general'] || ['api-design', 'database-design', 'security']);
|
|
3025
|
+
}
|
|
3026
|
+
/**
|
|
3027
|
+
* Helper method to get domains for ecosystem analysis based on technology focus
|
|
3028
|
+
*/
|
|
3029
|
+
getEcosystemAnalysisDomains(technologyFocus) {
|
|
3030
|
+
// Base domains for ecosystem analysis
|
|
3031
|
+
const baseDomains = ['api-design', 'database-design', 'security', 'performance-optimization'];
|
|
3032
|
+
// Technology-specific domain mapping
|
|
3033
|
+
const technologyDomainMap = {
|
|
3034
|
+
react: ['frontend-architecture', 'web-applications'],
|
|
3035
|
+
vue: ['frontend-architecture', 'web-applications'],
|
|
3036
|
+
angular: ['frontend-architecture', 'web-applications'],
|
|
3037
|
+
node: ['api-design', 'microservices'],
|
|
3038
|
+
express: ['api-design', 'web-applications'],
|
|
3039
|
+
fastify: ['api-design', 'performance-optimization'],
|
|
3040
|
+
nestjs: ['api-design', 'microservices'],
|
|
3041
|
+
spring: ['api-design', 'microservices'],
|
|
3042
|
+
django: ['api-design', 'web-applications'],
|
|
3043
|
+
flask: ['api-design', 'web-applications'],
|
|
3044
|
+
rails: ['api-design', 'web-applications'],
|
|
3045
|
+
laravel: ['api-design', 'web-applications'],
|
|
3046
|
+
docker: ['containerization', 'microservices'],
|
|
3047
|
+
kubernetes: ['containerization', 'distributed-systems'],
|
|
3048
|
+
mongodb: ['database-design', 'data-architecture'],
|
|
3049
|
+
postgresql: ['database-design', 'data-architecture'],
|
|
3050
|
+
mysql: ['database-design', 'data-architecture'],
|
|
3051
|
+
redis: ['database-design', 'performance-optimization'],
|
|
3052
|
+
elasticsearch: ['database-design', 'data-architecture'],
|
|
3053
|
+
kafka: ['distributed-systems', 'data-architecture'],
|
|
3054
|
+
rabbitmq: ['distributed-systems', 'microservices'],
|
|
3055
|
+
aws: ['cloud-architecture', 'scalability'],
|
|
3056
|
+
azure: ['cloud-architecture', 'scalability'],
|
|
3057
|
+
gcp: ['cloud-architecture', 'scalability'],
|
|
3058
|
+
terraform: ['infrastructure-as-code', 'cloud-architecture'],
|
|
3059
|
+
ansible: ['infrastructure-as-code', 'automation'],
|
|
3060
|
+
jenkins: ['ci-cd', 'automation'],
|
|
3061
|
+
'github-actions': ['ci-cd', 'automation'],
|
|
3062
|
+
'gitlab-ci': ['ci-cd', 'automation'],
|
|
3063
|
+
};
|
|
3064
|
+
// Collect domains based on technology focus
|
|
3065
|
+
const technologyDomains = new Set();
|
|
3066
|
+
for (const tech of technologyFocus) {
|
|
3067
|
+
const techLower = tech.toLowerCase();
|
|
3068
|
+
const domains = technologyDomainMap[techLower];
|
|
3069
|
+
if (domains) {
|
|
3070
|
+
domains.forEach(domain => technologyDomains.add(domain));
|
|
3071
|
+
}
|
|
3072
|
+
}
|
|
3073
|
+
// Combine base domains with technology-specific domains
|
|
3074
|
+
const allDomains = [...baseDomains, ...Array.from(technologyDomains)];
|
|
3075
|
+
// Remove duplicates and limit to reasonable number
|
|
3076
|
+
const uniqueDomains = [...new Set(allDomains)];
|
|
3077
|
+
// Return up to 6 most relevant domains
|
|
3078
|
+
return uniqueDomains.slice(0, 6);
|
|
3079
|
+
}
|
|
3080
|
+
/**
|
|
3081
|
+
* Helper method to create base ADR generation prompt
|
|
3082
|
+
*/
|
|
3083
|
+
createBaseAdrPrompt(prdPath, outputDirectory, knowledgeContext) {
|
|
3084
|
+
return `
|
|
3085
|
+
# Enhanced ADR Generation from PRD Request
|
|
3086
|
+
|
|
3087
|
+
This is a comprehensive prompt-driven ADR generation process enhanced with domain knowledge and optimized prompting.
|
|
3088
|
+
|
|
3089
|
+
${knowledgeContext}
|
|
3090
|
+
|
|
3091
|
+
## Step 1: File Validation
|
|
3092
|
+
Please verify that the PRD file exists at: ${prdPath}
|
|
3093
|
+
|
|
3094
|
+
## Step 2: PRD Content Reading
|
|
3095
|
+
Read and analyze the PRD content from: ${prdPath}
|
|
3096
|
+
|
|
3097
|
+
## Step 3: Enhanced ADR Generation and Creation
|
|
3098
|
+
|
|
3099
|
+
Once you have successfully read the PRD content, analyze it using the domain knowledge above and generate Architectural Decision Records (ADRs).
|
|
3100
|
+
|
|
3101
|
+
### Enhanced Analysis Requirements
|
|
3102
|
+
|
|
3103
|
+
1. **Extract Key Decisions**: Identify all architectural decisions implied or stated in the PRD
|
|
3104
|
+
2. **Apply Domain Knowledge**: Use the generated domain knowledge to enhance decision analysis
|
|
3105
|
+
3. **Decision Categorization**: Group decisions by:
|
|
3106
|
+
- Technology stack choices (informed by domain best practices)
|
|
3107
|
+
- Architectural patterns (leveraging domain-specific patterns)
|
|
3108
|
+
- Infrastructure decisions (considering domain requirements)
|
|
3109
|
+
- Security considerations (applying domain security knowledge)
|
|
3110
|
+
- Performance requirements (using domain performance insights)
|
|
3111
|
+
- Integration approaches (following domain integration patterns)
|
|
3112
|
+
|
|
3113
|
+
### Enhanced ADR Generation Requirements
|
|
3114
|
+
|
|
3115
|
+
1. **Follow ADR Format**: Use standard ADR template with domain-enhanced content
|
|
3116
|
+
2. **Number Sequentially**: Use format 001-decision-title.md, 002-next-decision.md, etc.
|
|
3117
|
+
3. **Output Directory**: Place ADRs in ${outputDirectory}/
|
|
3118
|
+
4. **Domain Context**: Include relevant domain knowledge in each ADR
|
|
3119
|
+
5. **File Creation**: Generate file creation prompts for each ADR
|
|
3120
|
+
|
|
3121
|
+
### Enhanced ADR Template Format
|
|
3122
|
+
|
|
3123
|
+
\`\`\`markdown
|
|
3124
|
+
# [Number]. [Title]
|
|
3125
|
+
|
|
3126
|
+
**Status**: [Proposed/Accepted/Deprecated/Superseded]
|
|
3127
|
+
**Date**: [YYYY-MM-DD]
|
|
3128
|
+
**Domain**: [Relevant domain from knowledge enhancement]
|
|
3129
|
+
|
|
3130
|
+
## Context
|
|
3131
|
+
[Describe the context and problem statement from PRD, enhanced with domain knowledge]
|
|
3132
|
+
|
|
3133
|
+
## Decision
|
|
3134
|
+
[Describe the architectural decision, informed by domain best practices]
|
|
3135
|
+
|
|
3136
|
+
## Consequences
|
|
3137
|
+
[Describe positive and negative consequences, considering domain-specific implications]
|
|
3138
|
+
|
|
3139
|
+
## Domain Considerations
|
|
3140
|
+
[Specific considerations from the domain knowledge that influenced this decision]
|
|
3141
|
+
|
|
3142
|
+
## Implementation Plan
|
|
3143
|
+
[Steps to implement this decision, leveraging domain expertise]
|
|
3144
|
+
|
|
3145
|
+
## Related PRD Sections
|
|
3146
|
+
[Reference specific sections from the PRD that led to this decision]
|
|
3147
|
+
|
|
3148
|
+
## Domain References
|
|
3149
|
+
[References to domain knowledge that informed this decision]
|
|
3150
|
+
\`\`\`
|
|
3151
|
+
|
|
3152
|
+
### Expected Enhanced Output
|
|
3153
|
+
|
|
3154
|
+
Please provide:
|
|
3155
|
+
1. **File Validation Results**: Confirmation that PRD file exists and is readable
|
|
3156
|
+
2. **PRD Content Summary**: Brief summary enhanced with domain context
|
|
3157
|
+
3. **Domain Analysis**: How domain knowledge applies to this PRD
|
|
3158
|
+
4. **Identified Decisions**: List of all architectural decisions with domain context
|
|
3159
|
+
5. **Generated ADRs**: Complete enhanced ADR content for each decision
|
|
3160
|
+
6. **File Creation Plan**: File names, directory structure, and creation order
|
|
3161
|
+
7. **Implementation Priority**: Recommended order considering domain best practices
|
|
3162
|
+
|
|
3163
|
+
### Quality Assurance with Domain Enhancement
|
|
3164
|
+
|
|
3165
|
+
- Ensure each ADR leverages relevant domain knowledge
|
|
3166
|
+
- Verify decisions align with domain best practices
|
|
3167
|
+
- Check that domain considerations are properly documented
|
|
3168
|
+
- Validate that ADR content is enhanced beyond basic analysis
|
|
3169
|
+
`;
|
|
3170
|
+
}
|
|
3171
|
+
/**
|
|
3172
|
+
* ADR suggestion tool implementations
|
|
3173
|
+
*/
|
|
3174
|
+
async suggestAdrs(args) {
|
|
3175
|
+
const { suggestAdrs } = await import('./tools/adr-suggestion-tool.js');
|
|
3176
|
+
return await suggestAdrs(args);
|
|
3177
|
+
}
|
|
3178
|
+
async generateAdrFromDecision(args) {
|
|
3179
|
+
const { generateAdrFromDecision } = await import('./tools/adr-suggestion-tool.js');
|
|
3180
|
+
return await generateAdrFromDecision(args);
|
|
3181
|
+
}
|
|
3182
|
+
async generateAdrBootstrap(args) {
|
|
3183
|
+
const { default: generateAdrBootstrapScripts } = await import('./tools/adr-bootstrap-validation-tool.js');
|
|
3184
|
+
return await generateAdrBootstrapScripts(args);
|
|
3185
|
+
}
|
|
3186
|
+
async bootstrapValidationLoop(args) {
|
|
3187
|
+
const { default: bootstrapValidationLoop } = await import('./tools/bootstrap-validation-loop-tool.js');
|
|
3188
|
+
return await bootstrapValidationLoop(args);
|
|
3189
|
+
}
|
|
3190
|
+
async discoverExistingAdrs(args, context) {
|
|
3191
|
+
const ctx = context || createNoOpContext();
|
|
3192
|
+
try {
|
|
3193
|
+
ctx.info('🔍 Starting ADR discovery process...');
|
|
3194
|
+
ctx.report_progress(0, 100);
|
|
3195
|
+
ctx.info('📂 Phase 1: Scanning ADR directory');
|
|
3196
|
+
ctx.report_progress(30, 100);
|
|
3197
|
+
const { discoverExistingAdrs } = await import('./tools/adr-suggestion-tool.js');
|
|
3198
|
+
ctx.info('📄 Phase 2: Analyzing ADR files');
|
|
3199
|
+
ctx.report_progress(60, 100);
|
|
3200
|
+
const result = await discoverExistingAdrs(args);
|
|
3201
|
+
ctx.info('✅ ADR discovery completed successfully');
|
|
3202
|
+
ctx.report_progress(100, 100);
|
|
3203
|
+
return result;
|
|
3204
|
+
}
|
|
3205
|
+
catch (error) {
|
|
3206
|
+
ctx.error?.(`❌ ADR discovery failed: ${error instanceof Error ? error.message : String(error)}`);
|
|
3207
|
+
throw error;
|
|
3208
|
+
}
|
|
3209
|
+
}
|
|
3210
|
+
async analyzeAdrTimeline(args) {
|
|
3211
|
+
try {
|
|
3212
|
+
const projectPath = args['projectPath'] || this.config.projectPath;
|
|
3213
|
+
const adrDirectory = args['adrDirectory'] || 'docs/adrs';
|
|
3214
|
+
const generateActions = args['generateActions'] ?? true;
|
|
3215
|
+
const thresholdProfile = args['thresholdProfile'];
|
|
3216
|
+
const autoDetectContext = args['autoDetectContext'] ?? true;
|
|
3217
|
+
const includeContent = args['includeContent'] ?? true;
|
|
3218
|
+
const forceExtract = args['forceExtract'] ?? false;
|
|
3219
|
+
const { discoverAdrsInDirectory } = await import('./utils/adr-discovery.js');
|
|
3220
|
+
const { formatActionReport } = await import('./utils/adr-action-analyzer.js');
|
|
3221
|
+
// Discover ADRs with timeline analysis
|
|
3222
|
+
const result = await discoverAdrsInDirectory(adrDirectory, projectPath, {
|
|
3223
|
+
includeContent,
|
|
3224
|
+
includeTimeline: true,
|
|
3225
|
+
timelineOptions: {
|
|
3226
|
+
forceExtract,
|
|
3227
|
+
useCache: true,
|
|
3228
|
+
cacheTTL: 3600,
|
|
3229
|
+
},
|
|
3230
|
+
generateActions,
|
|
3231
|
+
...(thresholdProfile ? { thresholdProfile } : {}),
|
|
3232
|
+
autoDetectContext,
|
|
3233
|
+
});
|
|
3234
|
+
// Format response
|
|
3235
|
+
let responseText = `# ADR Timeline Analysis\n\n`;
|
|
3236
|
+
responseText += `**Project:** ${projectPath}\n`;
|
|
3237
|
+
responseText += `**ADR Directory:** ${adrDirectory}\n`;
|
|
3238
|
+
responseText += `**Total ADRs:** ${result.totalAdrs}\n\n`;
|
|
3239
|
+
// Add timeline summary
|
|
3240
|
+
if (result.adrs.some(adr => adr.timeline)) {
|
|
3241
|
+
const withTimeline = result.adrs.filter(adr => adr.timeline).length;
|
|
3242
|
+
responseText += `## Timeline Data\n\n`;
|
|
3243
|
+
responseText += `- **ADRs with Timeline:** ${withTimeline}/${result.totalAdrs}\n`;
|
|
3244
|
+
const ages = result.adrs.filter(adr => adr.timeline).map(adr => adr.timeline.age_days);
|
|
3245
|
+
if (ages.length > 0) {
|
|
3246
|
+
const avgAge = Math.floor(ages.reduce((a, b) => a + b, 0) / ages.length);
|
|
3247
|
+
const oldestAge = Math.max(...ages);
|
|
3248
|
+
responseText += `- **Average ADR Age:** ${avgAge} days\n`;
|
|
3249
|
+
responseText += `- **Oldest ADR:** ${oldestAge} days\n`;
|
|
3250
|
+
}
|
|
3251
|
+
responseText += `\n`;
|
|
3252
|
+
}
|
|
3253
|
+
// Add action queue report
|
|
3254
|
+
if (result.actionQueue) {
|
|
3255
|
+
responseText += `---\n\n`;
|
|
3256
|
+
responseText += formatActionReport(result.actionQueue, {
|
|
3257
|
+
projectPath,
|
|
3258
|
+
thresholdProfile: thresholdProfile || 'auto-detected',
|
|
3259
|
+
});
|
|
3260
|
+
}
|
|
3261
|
+
else if (generateActions) {
|
|
3262
|
+
responseText += `## No Actions Required\n\n`;
|
|
3263
|
+
responseText += `All ADRs are up to date and within acceptable thresholds.\n`;
|
|
3264
|
+
}
|
|
3265
|
+
// Add summary stats
|
|
3266
|
+
if (result.summary.byStatus) {
|
|
3267
|
+
responseText += `\n---\n\n## ADR Status Distribution\n\n`;
|
|
3268
|
+
Object.entries(result.summary.byStatus).forEach(([status, count]) => {
|
|
3269
|
+
responseText += `- **${status}:** ${count}\n`;
|
|
3270
|
+
});
|
|
3271
|
+
}
|
|
3272
|
+
return {
|
|
3273
|
+
content: [
|
|
3274
|
+
{
|
|
3275
|
+
type: 'text',
|
|
3276
|
+
text: responseText,
|
|
3277
|
+
},
|
|
3278
|
+
],
|
|
3279
|
+
};
|
|
3280
|
+
}
|
|
3281
|
+
catch (error) {
|
|
3282
|
+
return {
|
|
3283
|
+
content: [
|
|
3284
|
+
{
|
|
3285
|
+
type: 'text',
|
|
3286
|
+
text: `# ADR Timeline Analysis Failed\n\n**Error:** ${error instanceof Error ? error.message : String(error)}\n\nPlease check that the ADR directory exists and contains valid ADR files.`,
|
|
3287
|
+
},
|
|
3288
|
+
],
|
|
3289
|
+
isError: true,
|
|
3290
|
+
};
|
|
3291
|
+
}
|
|
3292
|
+
}
|
|
3293
|
+
async reviewExistingAdrs(args) {
|
|
3294
|
+
const { reviewExistingAdrs } = await import('./tools/review-existing-adrs-tool.js');
|
|
3295
|
+
return await reviewExistingAdrs(args);
|
|
3296
|
+
}
|
|
3297
|
+
/**
|
|
3298
|
+
* ADR validation tool implementations
|
|
3299
|
+
*/
|
|
3300
|
+
async validateAdr(args) {
|
|
3301
|
+
const { validateAdr } = await import('./tools/adr-validation-tool.js');
|
|
3302
|
+
return await validateAdr(args);
|
|
3303
|
+
}
|
|
3304
|
+
async validateAllAdrs(args) {
|
|
3305
|
+
const { validateAllAdrs } = await import('./tools/adr-validation-tool.js');
|
|
3306
|
+
return await validateAllAdrs(args);
|
|
3307
|
+
}
|
|
3308
|
+
/**
|
|
3309
|
+
* Research integration tool implementations
|
|
3310
|
+
*/
|
|
3311
|
+
async incorporateResearch(args) {
|
|
3312
|
+
const { incorporateResearch } = await import('./tools/research-integration-tool.js');
|
|
3313
|
+
return await incorporateResearch(args);
|
|
3314
|
+
}
|
|
3315
|
+
async createResearchTemplate(args) {
|
|
3316
|
+
const { createResearchTemplate } = await import('./tools/research-integration-tool.js');
|
|
3317
|
+
return await createResearchTemplate(args);
|
|
3318
|
+
}
|
|
3319
|
+
async requestActionConfirmation(args) {
|
|
3320
|
+
const { requestActionConfirmation } = await import('./tools/research-integration-tool.js');
|
|
3321
|
+
return await requestActionConfirmation(args);
|
|
3322
|
+
}
|
|
3323
|
+
/**
|
|
3324
|
+
* Rule generation and validation tool implementations
|
|
3325
|
+
*/
|
|
3326
|
+
async generateRules(args) {
|
|
3327
|
+
const { generateRules } = await import('./tools/rule-generation-tool.js');
|
|
3328
|
+
return await generateRules(args);
|
|
3329
|
+
}
|
|
3330
|
+
async validateRules(args) {
|
|
3331
|
+
const { validateRules } = await import('./tools/rule-generation-tool.js');
|
|
3332
|
+
return await validateRules(args);
|
|
3333
|
+
}
|
|
3334
|
+
async createRuleSet(args) {
|
|
3335
|
+
const { createRuleSet } = await import('./tools/rule-generation-tool.js');
|
|
3336
|
+
return await createRuleSet(args);
|
|
3337
|
+
}
|
|
3338
|
+
/**
|
|
3339
|
+
* Environment analysis tool implementation
|
|
3340
|
+
*/
|
|
3341
|
+
async analyzeEnvironment(args) {
|
|
3342
|
+
const { analyzeEnvironment } = await import('./tools/environment-analysis-tool.js');
|
|
3343
|
+
return await analyzeEnvironment(args);
|
|
3344
|
+
}
|
|
3345
|
+
/**
|
|
3346
|
+
* Research question generation tool implementation
|
|
3347
|
+
*/
|
|
3348
|
+
async generateResearchQuestions(args) {
|
|
3349
|
+
const { generateResearchQuestions } = await import('./tools/research-question-tool.js');
|
|
3350
|
+
return await generateResearchQuestions(args);
|
|
3351
|
+
}
|
|
3352
|
+
/**
|
|
3353
|
+
* Perform research tool implementation
|
|
3354
|
+
*/
|
|
3355
|
+
async performResearch(args, context) {
|
|
3356
|
+
const ctx = context || createNoOpContext();
|
|
3357
|
+
if (!('question' in args) || typeof args['question'] !== 'string') {
|
|
3358
|
+
throw new McpAdrError('Missing required parameter: question', 'INVALID_ARGUMENTS');
|
|
3359
|
+
}
|
|
3360
|
+
try {
|
|
3361
|
+
ctx.info('🔍 Starting research process...');
|
|
3362
|
+
ctx.report_progress(0, 100);
|
|
3363
|
+
ctx.info('📊 Phase 1: Initializing research framework');
|
|
3364
|
+
ctx.report_progress(10, 100);
|
|
3365
|
+
const { performResearch } = await import('./tools/perform-research-tool.js');
|
|
3366
|
+
ctx.info('📚 Phase 2: Executing research orchestration');
|
|
3367
|
+
ctx.report_progress(20, 100);
|
|
3368
|
+
const result = await performResearch(args, ctx // ✅ Pass context to tool function for progress updates
|
|
3369
|
+
);
|
|
3370
|
+
return result;
|
|
3371
|
+
}
|
|
3372
|
+
catch (error) {
|
|
3373
|
+
ctx.error?.(`❌ Research execution failed: ${error instanceof Error ? error.message : String(error)}`);
|
|
3374
|
+
throw new McpAdrError(`Failed to perform research: ${error instanceof Error ? error.message : String(error)}`, 'RESEARCH_EXECUTION_ERROR');
|
|
3375
|
+
}
|
|
3376
|
+
}
|
|
3377
|
+
/**
|
|
3378
|
+
* Search codebase tool implementation
|
|
3379
|
+
*/
|
|
3380
|
+
async searchCodebase(args) {
|
|
3381
|
+
if (!('query' in args) || typeof args['query'] !== 'string') {
|
|
3382
|
+
throw new McpAdrError('Missing required parameter: query', 'INVALID_ARGUMENTS');
|
|
3383
|
+
}
|
|
3384
|
+
try {
|
|
3385
|
+
const { searchCodebaseTool } = await import('./tools/search-codebase-tool.js');
|
|
3386
|
+
return await searchCodebaseTool(args);
|
|
3387
|
+
}
|
|
3388
|
+
catch (error) {
|
|
3389
|
+
throw new McpAdrError(`Failed to search codebase: ${error instanceof Error ? error.message : String(error)}`, 'SEARCH_ERROR');
|
|
3390
|
+
}
|
|
3391
|
+
}
|
|
3392
|
+
/**
|
|
3393
|
+
* Deployment analysis tool implementation
|
|
3394
|
+
*/
|
|
3395
|
+
async analyzeDeploymentProgress(args) {
|
|
3396
|
+
const { analyzeDeploymentProgress } = await import('./tools/deployment-analysis-tool.js');
|
|
3397
|
+
return await analyzeDeploymentProgress(args);
|
|
3398
|
+
}
|
|
3399
|
+
/**
|
|
3400
|
+
* Apply content masking to MCP response
|
|
3401
|
+
*/
|
|
3402
|
+
/**
|
|
3403
|
+
* Track memory operations performed by tools
|
|
3404
|
+
*/
|
|
3405
|
+
async trackMemoryOperations(toolName, parameters, result, success) {
|
|
3406
|
+
try {
|
|
3407
|
+
// Check if memory integration was enabled and used
|
|
3408
|
+
if (parameters?.enableMemoryIntegration === false) {
|
|
3409
|
+
return; // Memory integration was explicitly disabled
|
|
3410
|
+
}
|
|
3411
|
+
// Extract memory operation information from result
|
|
3412
|
+
const memoryOps = this.extractMemoryOperations(toolName, parameters, result);
|
|
3413
|
+
if (memoryOps.length > 0) {
|
|
3414
|
+
// Store memory operation tracking in knowledge graph
|
|
3415
|
+
for (const op of memoryOps) {
|
|
3416
|
+
await this.kgManager.addMemoryExecution(toolName, op.action, op.entityType, success && op.success, op.details);
|
|
3417
|
+
}
|
|
3418
|
+
}
|
|
3419
|
+
}
|
|
3420
|
+
catch (error) {
|
|
3421
|
+
// Don't let memory tracking errors break execution
|
|
3422
|
+
console.error('[WARN] Memory operation tracking failed:', error);
|
|
3423
|
+
}
|
|
3424
|
+
}
|
|
3425
|
+
/**
|
|
3426
|
+
* Extract memory operation details from tool execution
|
|
3427
|
+
*/
|
|
3428
|
+
extractMemoryOperations(toolName, parameters, result) {
|
|
3429
|
+
const operations = [];
|
|
3430
|
+
// Define memory-enabled tools and their expected operations
|
|
3431
|
+
const memoryEnabledTools = {
|
|
3432
|
+
analyze_content_security: {
|
|
3433
|
+
entityType: 'security_pattern',
|
|
3434
|
+
actions: ['store_pattern', 'analyze_institutional_security', 'track_evolution'],
|
|
3435
|
+
},
|
|
3436
|
+
analyze_environment: {
|
|
3437
|
+
entityType: 'environment_snapshot',
|
|
3438
|
+
actions: ['store_snapshot', 'analyze_trends', 'compare_configurations'],
|
|
3439
|
+
},
|
|
3440
|
+
deployment_readiness: {
|
|
3441
|
+
entityType: 'deployment_assessment',
|
|
3442
|
+
actions: ['store_assessment', 'migrate_history', 'analyze_patterns'],
|
|
3443
|
+
},
|
|
3444
|
+
troubleshoot_guided_workflow: {
|
|
3445
|
+
entityType: 'troubleshooting_session',
|
|
3446
|
+
actions: ['store_session', 'pattern_recognition', 'suggest_adrs', 'generate_research'],
|
|
3447
|
+
},
|
|
3448
|
+
};
|
|
3449
|
+
// Check if this tool supports memory operations
|
|
3450
|
+
const toolConfig = memoryEnabledTools[toolName];
|
|
3451
|
+
if (!toolConfig) {
|
|
3452
|
+
return operations; // Tool doesn't support memory operations
|
|
3453
|
+
}
|
|
3454
|
+
// Extract memory operation details from result
|
|
3455
|
+
if (result?.memoryIntegration) {
|
|
3456
|
+
const memoryInfo = result.memoryIntegration;
|
|
3457
|
+
// Pattern entity storage operation
|
|
3458
|
+
if (memoryInfo.entityStored || memoryInfo.patternStored) {
|
|
3459
|
+
operations.push({
|
|
3460
|
+
action: 'entity_storage',
|
|
3461
|
+
entityType: toolConfig.entityType,
|
|
3462
|
+
success: memoryInfo.storageSuccess !== false,
|
|
3463
|
+
details: {
|
|
3464
|
+
entityId: memoryInfo.entityId || memoryInfo.patternId,
|
|
3465
|
+
entityCount: memoryInfo.entityCount || 1,
|
|
3466
|
+
storageMethod: memoryInfo.storageMethod || 'standard',
|
|
3467
|
+
},
|
|
3468
|
+
});
|
|
3469
|
+
}
|
|
3470
|
+
// Historical analysis operation
|
|
3471
|
+
if (memoryInfo.historicalAnalysis || memoryInfo.trendAnalysis) {
|
|
3472
|
+
operations.push({
|
|
3473
|
+
action: 'historical_analysis',
|
|
3474
|
+
entityType: toolConfig.entityType,
|
|
3475
|
+
success: memoryInfo.analysisSuccess !== false,
|
|
3476
|
+
details: {
|
|
3477
|
+
analysisType: memoryInfo.analysisType || 'trend_analysis',
|
|
3478
|
+
entitiesAnalyzed: memoryInfo.entitiesAnalyzed || 0,
|
|
3479
|
+
insights: memoryInfo.insights || [],
|
|
3480
|
+
},
|
|
3481
|
+
});
|
|
3482
|
+
}
|
|
3483
|
+
// Evolution tracking operation
|
|
3484
|
+
if (memoryInfo.evolutionTracking) {
|
|
3485
|
+
operations.push({
|
|
3486
|
+
action: 'evolution_tracking',
|
|
3487
|
+
entityType: toolConfig.entityType,
|
|
3488
|
+
success: memoryInfo.evolutionSuccess !== false,
|
|
3489
|
+
details: {
|
|
3490
|
+
improvements: memoryInfo.improvements || [],
|
|
3491
|
+
degradations: memoryInfo.degradations || [],
|
|
3492
|
+
recommendations: memoryInfo.recommendations || [],
|
|
3493
|
+
},
|
|
3494
|
+
});
|
|
3495
|
+
}
|
|
3496
|
+
// Migration operation (for deployment readiness)
|
|
3497
|
+
if (memoryInfo.migrationCompleted) {
|
|
3498
|
+
operations.push({
|
|
3499
|
+
action: 'data_migration',
|
|
3500
|
+
entityType: toolConfig.entityType,
|
|
3501
|
+
success: memoryInfo.migrationSuccess !== false,
|
|
3502
|
+
details: {
|
|
3503
|
+
migratedRecords: memoryInfo.migratedRecords || 0,
|
|
3504
|
+
migrationMethod: memoryInfo.migrationMethod || 'json_to_memory',
|
|
3505
|
+
},
|
|
3506
|
+
});
|
|
3507
|
+
}
|
|
3508
|
+
}
|
|
3509
|
+
// If no specific memory integration info, infer from parameters
|
|
3510
|
+
if (operations.length === 0 && parameters?.enableMemoryIntegration !== false) {
|
|
3511
|
+
// Default assumption: entity was stored
|
|
3512
|
+
operations.push({
|
|
3513
|
+
action: 'entity_storage',
|
|
3514
|
+
entityType: toolConfig.entityType,
|
|
3515
|
+
success: true, // Assume success if no explicit info
|
|
3516
|
+
details: {
|
|
3517
|
+
entityCount: 1,
|
|
3518
|
+
storageMethod: 'inferred',
|
|
3519
|
+
note: 'Memory operation inferred from tool execution',
|
|
3520
|
+
},
|
|
3521
|
+
});
|
|
3522
|
+
}
|
|
3523
|
+
return operations;
|
|
3524
|
+
}
|
|
3525
|
+
/**
|
|
3526
|
+
* Track tool execution in knowledge graph
|
|
3527
|
+
*/
|
|
3528
|
+
async trackToolExecution(toolName, parameters, result, success, error) {
|
|
3529
|
+
try {
|
|
3530
|
+
// Extract intentId from metadata if available
|
|
3531
|
+
let intentId;
|
|
3532
|
+
if (result?.metadata?.intentId) {
|
|
3533
|
+
intentId = result.metadata.intentId;
|
|
3534
|
+
}
|
|
3535
|
+
else {
|
|
3536
|
+
// Check for active intents that might be related to this tool execution
|
|
3537
|
+
const activeIntents = await this.kgManager.getActiveIntents();
|
|
3538
|
+
if (activeIntents.length > 0) {
|
|
3539
|
+
// Use the most recent active intent
|
|
3540
|
+
const latestIntent = activeIntents[activeIntents.length - 1];
|
|
3541
|
+
if (latestIntent) {
|
|
3542
|
+
intentId = latestIntent.intentId;
|
|
3543
|
+
}
|
|
3544
|
+
}
|
|
3545
|
+
}
|
|
3546
|
+
// If no intent found, create a standalone execution record
|
|
3547
|
+
if (!intentId) {
|
|
3548
|
+
// Extract human request from conversation context if available
|
|
3549
|
+
let humanRequest = `Standalone tool execution: ${toolName}`;
|
|
3550
|
+
if (parameters?.conversationContext?.humanRequest) {
|
|
3551
|
+
humanRequest = parameters.conversationContext.humanRequest;
|
|
3552
|
+
}
|
|
3553
|
+
intentId = await this.kgManager.createIntent(humanRequest, [`Execute ${toolName}`, 'Complete tool operation'], 'medium');
|
|
3554
|
+
}
|
|
3555
|
+
// Determine tasks created/modified from tool operation
|
|
3556
|
+
const todoTasksCreated = [];
|
|
3557
|
+
const todoTasksModified = [];
|
|
3558
|
+
// Extract task information from result metadata
|
|
3559
|
+
if (result?.metadata) {
|
|
3560
|
+
if (result.metadata.tasksCreated) {
|
|
3561
|
+
todoTasksCreated.push(...result.metadata.tasksCreated);
|
|
3562
|
+
}
|
|
3563
|
+
if (result.metadata.tasksModified) {
|
|
3564
|
+
todoTasksModified.push(...result.metadata.tasksModified);
|
|
3565
|
+
}
|
|
3566
|
+
if (result.metadata.taskIds) {
|
|
3567
|
+
todoTasksModified.push(...result.metadata.taskIds);
|
|
3568
|
+
}
|
|
3569
|
+
}
|
|
3570
|
+
// Track memory operations if present
|
|
3571
|
+
await this.trackMemoryOperations(toolName, parameters, result, success);
|
|
3572
|
+
// Store execution in knowledge graph
|
|
3573
|
+
await this.kgManager.addToolExecution(intentId, toolName, parameters, result, success, todoTasksCreated, todoTasksModified, error);
|
|
3574
|
+
// If execution completed successfully, update intent status
|
|
3575
|
+
if (success && !error) {
|
|
3576
|
+
// Check if this might be the final tool in a chain
|
|
3577
|
+
const intent = await this.kgManager.getIntentById(intentId);
|
|
3578
|
+
if (intent && intent.currentStatus === 'executing') {
|
|
3579
|
+
// Simple heuristic: if tool is a "completion" type tool, mark intent as completed
|
|
3580
|
+
const completionTools = ['smart_git_push', 'generate_deployment_guidance', 'smart_score'];
|
|
3581
|
+
if (completionTools.includes(toolName)) {
|
|
3582
|
+
await this.kgManager.updateIntentStatus(intentId, 'completed');
|
|
3583
|
+
}
|
|
3584
|
+
}
|
|
3585
|
+
}
|
|
3586
|
+
}
|
|
3587
|
+
catch (trackingError) {
|
|
3588
|
+
// Don't let tracking errors break tool execution
|
|
3589
|
+
console.error('[WARN] Knowledge graph tracking failed:', trackingError);
|
|
3590
|
+
}
|
|
3591
|
+
}
|
|
3592
|
+
async applyOutputMasking(response) {
|
|
3593
|
+
try {
|
|
3594
|
+
return await maskMcpResponse(response, this.maskingConfig);
|
|
3595
|
+
}
|
|
3596
|
+
catch (error) {
|
|
3597
|
+
// If masking fails, log warning and return original response
|
|
3598
|
+
// Log to stderr to avoid corrupting MCP protocol
|
|
3599
|
+
console.error('[WARN] Output masking failed:', error);
|
|
3600
|
+
return response;
|
|
3601
|
+
}
|
|
3602
|
+
}
|
|
3603
|
+
/**
|
|
3604
|
+
* Enrich response with state reinforcement and apply masking
|
|
3605
|
+
*
|
|
3606
|
+
* Implements Phase 2 of context decay mitigation by injecting
|
|
3607
|
+
* context reminders every N turns or when response exceeds token threshold.
|
|
3608
|
+
*
|
|
3609
|
+
* Phase 3 extension: Records conversation turns to structured external memory.
|
|
3610
|
+
*/
|
|
3611
|
+
async enrichResponseWithStateReinforcement(response, toolName, toolArgs) {
|
|
3612
|
+
const startTime = Date.now();
|
|
3613
|
+
try {
|
|
3614
|
+
// Extract text content from response
|
|
3615
|
+
const textContent = response.content
|
|
3616
|
+
.filter((item) => item.type === 'text')
|
|
3617
|
+
.map(item => item.text)
|
|
3618
|
+
.join('\n\n');
|
|
3619
|
+
if (!textContent) {
|
|
3620
|
+
// No text content to enrich, just apply masking
|
|
3621
|
+
return await this.applyOutputMasking(response);
|
|
3622
|
+
}
|
|
3623
|
+
// Enrich with state reinforcement (Phase 2)
|
|
3624
|
+
const enriched = await this.stateReinforcementManager.enrichResponseWithContext(textContent);
|
|
3625
|
+
// Prepare final response
|
|
3626
|
+
let finalResponse;
|
|
3627
|
+
// Replace text content with enriched version if context was injected
|
|
3628
|
+
if (enriched.contextInjected) {
|
|
3629
|
+
finalResponse = {
|
|
3630
|
+
...response,
|
|
3631
|
+
content: response.content.map(item => {
|
|
3632
|
+
if (item.type === 'text') {
|
|
3633
|
+
return {
|
|
3634
|
+
type: 'text',
|
|
3635
|
+
text: enriched.enrichedContent,
|
|
3636
|
+
};
|
|
3637
|
+
}
|
|
3638
|
+
return item;
|
|
3639
|
+
}),
|
|
3640
|
+
};
|
|
3641
|
+
}
|
|
3642
|
+
else {
|
|
3643
|
+
finalResponse = response;
|
|
3644
|
+
}
|
|
3645
|
+
// Record conversation turn (Phase 3: Structured External Memory)
|
|
3646
|
+
if (toolName) {
|
|
3647
|
+
const duration = Date.now() - startTime;
|
|
3648
|
+
// Check if response has expandableId (from tiered response)
|
|
3649
|
+
const expandableIdMatch = textContent.match(/expandableId:\s*(\S+)/);
|
|
3650
|
+
const expandableId = expandableIdMatch ? expandableIdMatch[1] : undefined;
|
|
3651
|
+
await this.conversationMemoryManager.recordTurn({
|
|
3652
|
+
type: 'tool_call',
|
|
3653
|
+
toolName,
|
|
3654
|
+
toolArgs,
|
|
3655
|
+
}, {
|
|
3656
|
+
content: enriched.enrichedContent || textContent,
|
|
3657
|
+
tokenCount: enriched.tokenCount,
|
|
3658
|
+
contextInjected: enriched.contextInjected,
|
|
3659
|
+
...(expandableId ? { expandableId } : {}),
|
|
3660
|
+
}, {
|
|
3661
|
+
duration,
|
|
3662
|
+
cacheHit: false, // Could be enhanced to track cache hits
|
|
3663
|
+
errorOccurred: false,
|
|
3664
|
+
});
|
|
3665
|
+
this.logger.debug(`Conversation turn recorded for ${toolName}`, 'McpAdrAnalysisServer', {
|
|
3666
|
+
turnNumber: enriched.turnNumber,
|
|
3667
|
+
});
|
|
3668
|
+
}
|
|
3669
|
+
// Apply masking to final response
|
|
3670
|
+
return await this.applyOutputMasking(finalResponse);
|
|
3671
|
+
}
|
|
3672
|
+
catch (error) {
|
|
3673
|
+
this.logger.error('State reinforcement or conversation recording failed, returning original response', 'McpAdrAnalysisServer', error instanceof Error ? error : undefined);
|
|
3674
|
+
// Fallback to just masking if enrichment fails
|
|
3675
|
+
return await this.applyOutputMasking(response);
|
|
3676
|
+
}
|
|
3677
|
+
}
|
|
3678
|
+
/**
|
|
3679
|
+
* Read MCP resource with prompt-driven caching
|
|
3680
|
+
*/
|
|
3681
|
+
async readResource(uri) {
|
|
3682
|
+
try {
|
|
3683
|
+
// Import resource router and templated resources (ensures routes are registered)
|
|
3684
|
+
const { resourceRouter } = await import('./resources/resource-router.js');
|
|
3685
|
+
// Import templated resources to register routes
|
|
3686
|
+
await import('./resources/adr-by-id-resource.js');
|
|
3687
|
+
await import('./resources/research-by-topic-resource.js');
|
|
3688
|
+
await import('./resources/todo-by-id-resource.js');
|
|
3689
|
+
await import('./resources/rule-by-id-resource.js');
|
|
3690
|
+
await import('./resources/technology-by-name-resource.js');
|
|
3691
|
+
await import('./resources/pattern-by-name-resource.js');
|
|
3692
|
+
await import('./resources/validated-pattern-by-platform-resource.js');
|
|
3693
|
+
await import('./resources/pattern-sources-by-platform-resource.js');
|
|
3694
|
+
await import('./resources/pattern-base-code-by-platform-resource.js');
|
|
3695
|
+
// Phase 1 & 2 resources (PR #346)
|
|
3696
|
+
await import('./resources/server-context-resource.js');
|
|
3697
|
+
await import('./resources/memory-stats-resource.js');
|
|
3698
|
+
await import('./resources/conversation-snapshot-resource.js');
|
|
3699
|
+
await import('./resources/tool-catalog-resource.js');
|
|
3700
|
+
await import('./resources/adrs-discovered-resource.js');
|
|
3701
|
+
// Knowledge Graph Resource (ADR-018)
|
|
3702
|
+
const { generateKnowledgeGraphResource } = await import('./resources/knowledge-graph-resource.js');
|
|
3703
|
+
// Handle knowledge://graph specially to inject KnowledgeGraphManager
|
|
3704
|
+
if (uri === 'knowledge://graph') {
|
|
3705
|
+
const url = new globalThis.URL(uri);
|
|
3706
|
+
const result = await generateKnowledgeGraphResource({}, url.searchParams, this.kgManager);
|
|
3707
|
+
return {
|
|
3708
|
+
contents: [
|
|
3709
|
+
{
|
|
3710
|
+
uri,
|
|
3711
|
+
mimeType: result.contentType,
|
|
3712
|
+
text: JSON.stringify(result.data, null, 2),
|
|
3713
|
+
},
|
|
3714
|
+
],
|
|
3715
|
+
_meta: {
|
|
3716
|
+
lastModified: result.lastModified,
|
|
3717
|
+
etag: result.etag,
|
|
3718
|
+
cacheKey: result.cacheKey,
|
|
3719
|
+
},
|
|
3720
|
+
};
|
|
3721
|
+
}
|
|
3722
|
+
// Try routing first (handles templated resources)
|
|
3723
|
+
if (resourceRouter.canRoute(uri)) {
|
|
3724
|
+
const result = await resourceRouter.route(uri);
|
|
3725
|
+
return {
|
|
3726
|
+
contents: [
|
|
3727
|
+
{
|
|
3728
|
+
uri,
|
|
3729
|
+
mimeType: result.contentType,
|
|
3730
|
+
text: JSON.stringify(result.data, null, 2),
|
|
3731
|
+
},
|
|
3732
|
+
],
|
|
3733
|
+
_meta: {
|
|
3734
|
+
lastModified: result.lastModified,
|
|
3735
|
+
etag: result.etag,
|
|
3736
|
+
cacheKey: result.cacheKey,
|
|
3737
|
+
},
|
|
3738
|
+
};
|
|
3739
|
+
}
|
|
3740
|
+
// Fall back to static resource handling
|
|
3741
|
+
// Parse URI to determine resource type and parameters
|
|
3742
|
+
const url = new globalThis.URL(uri);
|
|
3743
|
+
// For a non-special scheme like `adr://adr_list`, WHATWG URL puts the name in
|
|
3744
|
+
// `host`, not `pathname` -- pathname is ''. Reading pathname alone made every one
|
|
3745
|
+
// of the 16 cases below unreachable: resourceType was always '', so the switch fell
|
|
3746
|
+
// straight to `default` and threw "Unknown resource type: " with nothing after the
|
|
3747
|
+
// colon. 16 of the 17 concrete resources advertised in resources/list were dead.
|
|
3748
|
+
//
|
|
3749
|
+
// adr://adr_list -> host 'adr_list', pathname ''
|
|
3750
|
+
// adr://adr/{id} -> host 'adr', pathname '/%7Bid%7D'
|
|
3751
|
+
//
|
|
3752
|
+
// Prefer the host; fall back to pathname so path-style URIs still resolve.
|
|
3753
|
+
const resourceType = url.host || url.pathname.replace('/', '');
|
|
3754
|
+
const params = Object.fromEntries(url.searchParams.entries());
|
|
3755
|
+
switch (resourceType) {
|
|
3756
|
+
case 'architectural_knowledge_graph': {
|
|
3757
|
+
const { generateArchitecturalKnowledgeGraph } = await import('./resources/index.js');
|
|
3758
|
+
const projectPath = params['projectPath'] || process.cwd();
|
|
3759
|
+
// Generate resource directly (caching is now handled through AI delegation)
|
|
3760
|
+
const result = await generateArchitecturalKnowledgeGraph(projectPath);
|
|
3761
|
+
return {
|
|
3762
|
+
contents: [
|
|
3763
|
+
{
|
|
3764
|
+
uri,
|
|
3765
|
+
mimeType: result.contentType,
|
|
3766
|
+
text: JSON.stringify(result.data, null, 2),
|
|
3767
|
+
},
|
|
3768
|
+
],
|
|
3769
|
+
};
|
|
3770
|
+
}
|
|
3771
|
+
case 'analysis_report': {
|
|
3772
|
+
const { generateAnalysisReport } = await import('./resources/index.js');
|
|
3773
|
+
const projectPath = params['projectPath'] || process.cwd();
|
|
3774
|
+
const focusAreas = params['focusAreas'] ? params['focusAreas'].split(',') : undefined;
|
|
3775
|
+
// Generate resource directly (caching is now handled through AI delegation)
|
|
3776
|
+
const result = await generateAnalysisReport(projectPath, focusAreas);
|
|
3777
|
+
return {
|
|
3778
|
+
contents: [
|
|
3779
|
+
{
|
|
3780
|
+
uri,
|
|
3781
|
+
mimeType: result.contentType,
|
|
3782
|
+
text: JSON.stringify(result.data, null, 2),
|
|
3783
|
+
},
|
|
3784
|
+
],
|
|
3785
|
+
};
|
|
3786
|
+
}
|
|
3787
|
+
case 'adr_list': {
|
|
3788
|
+
const { generateAdrList } = await import('./resources/index.js');
|
|
3789
|
+
const { getAdrDirectoryPath } = await import('./utils/config.js');
|
|
3790
|
+
const path = await import('path');
|
|
3791
|
+
// Use absolute ADR path relative to project
|
|
3792
|
+
const absoluteAdrPath = params['adrDirectory']
|
|
3793
|
+
? path.resolve(this.config.projectPath, params['adrDirectory'])
|
|
3794
|
+
: getAdrDirectoryPath(this.config);
|
|
3795
|
+
// Generate resource directly (caching is now handled through AI delegation)
|
|
3796
|
+
const result = await generateAdrList(absoluteAdrPath, this.config.projectPath);
|
|
3797
|
+
return {
|
|
3798
|
+
contents: [
|
|
3799
|
+
{
|
|
3800
|
+
uri,
|
|
3801
|
+
mimeType: result.contentType,
|
|
3802
|
+
text: JSON.stringify(result.data, null, 2),
|
|
3803
|
+
},
|
|
3804
|
+
],
|
|
3805
|
+
};
|
|
3806
|
+
}
|
|
3807
|
+
case 'todo_list': {
|
|
3808
|
+
const { generateTodoListResource } = await import('./resources/todo-list-resource.js');
|
|
3809
|
+
const result = await generateTodoListResource();
|
|
3810
|
+
return {
|
|
3811
|
+
contents: [
|
|
3812
|
+
{
|
|
3813
|
+
uri,
|
|
3814
|
+
mimeType: result.contentType,
|
|
3815
|
+
text: JSON.stringify(result.data, null, 2),
|
|
3816
|
+
},
|
|
3817
|
+
],
|
|
3818
|
+
_meta: {
|
|
3819
|
+
lastModified: result.lastModified,
|
|
3820
|
+
etag: result.etag,
|
|
3821
|
+
cacheKey: result.cacheKey,
|
|
3822
|
+
},
|
|
3823
|
+
};
|
|
3824
|
+
}
|
|
3825
|
+
case 'research_index': {
|
|
3826
|
+
const { generateResearchIndexResource } = await import('./resources/research-index-resource.js');
|
|
3827
|
+
const result = await generateResearchIndexResource();
|
|
3828
|
+
return {
|
|
3829
|
+
contents: [
|
|
3830
|
+
{
|
|
3831
|
+
uri,
|
|
3832
|
+
mimeType: result.contentType,
|
|
3833
|
+
text: JSON.stringify(result.data, null, 2),
|
|
3834
|
+
},
|
|
3835
|
+
],
|
|
3836
|
+
_meta: {
|
|
3837
|
+
lastModified: result.lastModified,
|
|
3838
|
+
etag: result.etag,
|
|
3839
|
+
cacheKey: result.cacheKey,
|
|
3840
|
+
},
|
|
3841
|
+
};
|
|
3842
|
+
}
|
|
3843
|
+
case 'rule_catalog': {
|
|
3844
|
+
const { generateRuleCatalogResource } = await import('./resources/rule-catalog-resource.js');
|
|
3845
|
+
const result = await generateRuleCatalogResource();
|
|
3846
|
+
return {
|
|
3847
|
+
contents: [
|
|
3848
|
+
{
|
|
3849
|
+
uri,
|
|
3850
|
+
mimeType: result.contentType,
|
|
3851
|
+
text: JSON.stringify(result.data, null, 2),
|
|
3852
|
+
},
|
|
3853
|
+
],
|
|
3854
|
+
_meta: {
|
|
3855
|
+
lastModified: result.lastModified,
|
|
3856
|
+
etag: result.etag,
|
|
3857
|
+
cacheKey: result.cacheKey,
|
|
3858
|
+
},
|
|
3859
|
+
};
|
|
3860
|
+
}
|
|
3861
|
+
case 'rule_generation': {
|
|
3862
|
+
const { generateRuleGenerationResource } = await import('./resources/rule-generation-resource.js');
|
|
3863
|
+
const result = await generateRuleGenerationResource(undefined, url.searchParams);
|
|
3864
|
+
return {
|
|
3865
|
+
contents: [
|
|
3866
|
+
{
|
|
3867
|
+
uri,
|
|
3868
|
+
mimeType: result.contentType,
|
|
3869
|
+
text: JSON.stringify(result.data, null, 2),
|
|
3870
|
+
},
|
|
3871
|
+
],
|
|
3872
|
+
_meta: {
|
|
3873
|
+
lastModified: result.lastModified,
|
|
3874
|
+
etag: result.etag,
|
|
3875
|
+
cacheKey: result.cacheKey,
|
|
3876
|
+
},
|
|
3877
|
+
};
|
|
3878
|
+
}
|
|
3879
|
+
case 'project_status': {
|
|
3880
|
+
const { generateProjectStatusResource } = await import('./resources/project-status-resource.js');
|
|
3881
|
+
const result = await generateProjectStatusResource();
|
|
3882
|
+
return {
|
|
3883
|
+
contents: [
|
|
3884
|
+
{
|
|
3885
|
+
uri,
|
|
3886
|
+
mimeType: result.contentType,
|
|
3887
|
+
text: JSON.stringify(result.data, null, 2),
|
|
3888
|
+
},
|
|
3889
|
+
],
|
|
3890
|
+
_meta: {
|
|
3891
|
+
lastModified: result.lastModified,
|
|
3892
|
+
etag: result.etag,
|
|
3893
|
+
cacheKey: result.cacheKey,
|
|
3894
|
+
},
|
|
3895
|
+
};
|
|
3896
|
+
}
|
|
3897
|
+
case 'deployment_status': {
|
|
3898
|
+
const { generateDeploymentStatusResource } = await import('./resources/deployment-status-resource.js');
|
|
3899
|
+
const result = await generateDeploymentStatusResource(undefined, url.searchParams);
|
|
3900
|
+
return {
|
|
3901
|
+
contents: [
|
|
3902
|
+
{
|
|
3903
|
+
uri,
|
|
3904
|
+
mimeType: result.contentType,
|
|
3905
|
+
text: JSON.stringify(result.data, null, 2),
|
|
3906
|
+
},
|
|
3907
|
+
],
|
|
3908
|
+
_meta: {
|
|
3909
|
+
lastModified: result.lastModified,
|
|
3910
|
+
etag: result.etag,
|
|
3911
|
+
cacheKey: result.cacheKey,
|
|
3912
|
+
},
|
|
3913
|
+
};
|
|
3914
|
+
}
|
|
3915
|
+
case 'environment_analysis': {
|
|
3916
|
+
const { generateEnvironmentAnalysisResource } = await import('./resources/environment-analysis-resource.js');
|
|
3917
|
+
const result = await generateEnvironmentAnalysisResource(undefined, url.searchParams);
|
|
3918
|
+
return {
|
|
3919
|
+
contents: [
|
|
3920
|
+
{
|
|
3921
|
+
uri,
|
|
3922
|
+
mimeType: result.contentType,
|
|
3923
|
+
text: JSON.stringify(result.data, null, 2),
|
|
3924
|
+
},
|
|
3925
|
+
],
|
|
3926
|
+
_meta: {
|
|
3927
|
+
lastModified: result.lastModified,
|
|
3928
|
+
etag: result.etag,
|
|
3929
|
+
cacheKey: result.cacheKey,
|
|
3930
|
+
},
|
|
3931
|
+
};
|
|
3932
|
+
}
|
|
3933
|
+
case 'memory_snapshots': {
|
|
3934
|
+
const { generateMemorySnapshotsResource } = await import('./resources/memory-snapshots-resource.js');
|
|
3935
|
+
const result = await generateMemorySnapshotsResource(undefined, url.searchParams);
|
|
3936
|
+
return {
|
|
3937
|
+
contents: [
|
|
3938
|
+
{
|
|
3939
|
+
uri,
|
|
3940
|
+
mimeType: result.contentType,
|
|
3941
|
+
text: JSON.stringify(result.data, null, 2),
|
|
3942
|
+
},
|
|
3943
|
+
],
|
|
3944
|
+
_meta: {
|
|
3945
|
+
lastModified: result.lastModified,
|
|
3946
|
+
etag: result.etag,
|
|
3947
|
+
cacheKey: result.cacheKey,
|
|
3948
|
+
},
|
|
3949
|
+
};
|
|
3950
|
+
}
|
|
3951
|
+
case 'project_metrics': {
|
|
3952
|
+
const { generateProjectMetricsResource } = await import('./resources/project-metrics-resource.js');
|
|
3953
|
+
const result = await generateProjectMetricsResource();
|
|
3954
|
+
return {
|
|
3955
|
+
contents: [
|
|
3956
|
+
{
|
|
3957
|
+
uri,
|
|
3958
|
+
mimeType: result.contentType,
|
|
3959
|
+
text: JSON.stringify(result.data, null, 2),
|
|
3960
|
+
},
|
|
3961
|
+
],
|
|
3962
|
+
_meta: {
|
|
3963
|
+
lastModified: result.lastModified,
|
|
3964
|
+
etag: result.etag,
|
|
3965
|
+
cacheKey: result.cacheKey,
|
|
3966
|
+
},
|
|
3967
|
+
};
|
|
3968
|
+
}
|
|
3969
|
+
case 'deployment_history': {
|
|
3970
|
+
const { generateDeploymentHistoryResource } = await import('./resources/deployment-history-resource.js');
|
|
3971
|
+
const result = await generateDeploymentHistoryResource(undefined, url.searchParams);
|
|
3972
|
+
return {
|
|
3973
|
+
contents: [
|
|
3974
|
+
{
|
|
3975
|
+
uri,
|
|
3976
|
+
mimeType: result.contentType,
|
|
3977
|
+
text: JSON.stringify(result.data, null, 2),
|
|
3978
|
+
},
|
|
3979
|
+
],
|
|
3980
|
+
_meta: {
|
|
3981
|
+
lastModified: result.lastModified,
|
|
3982
|
+
etag: result.etag,
|
|
3983
|
+
cacheKey: result.cacheKey,
|
|
3984
|
+
},
|
|
3985
|
+
};
|
|
3986
|
+
}
|
|
3987
|
+
case 'release_history': {
|
|
3988
|
+
const { generateReleaseHistoryResource } = await import('./resources/release-history-resource.js');
|
|
3989
|
+
const releaseProjectPath = process.env['PROJECT_PATH'] || process.cwd();
|
|
3990
|
+
const result = await generateReleaseHistoryResource(releaseProjectPath, url.searchParams);
|
|
3991
|
+
return {
|
|
3992
|
+
contents: [
|
|
3993
|
+
{
|
|
3994
|
+
uri,
|
|
3995
|
+
mimeType: result.contentType,
|
|
3996
|
+
text: JSON.stringify(result.data, null, 2),
|
|
3997
|
+
},
|
|
3998
|
+
],
|
|
3999
|
+
_meta: {
|
|
4000
|
+
lastModified: result.lastModified,
|
|
4001
|
+
etag: result.etag,
|
|
4002
|
+
cacheKey: result.cacheKey,
|
|
4003
|
+
},
|
|
4004
|
+
};
|
|
4005
|
+
}
|
|
4006
|
+
case 'code_quality': {
|
|
4007
|
+
const { generateCodeQualityResource } = await import('./resources/code-quality-resource.js');
|
|
4008
|
+
const result = await generateCodeQualityResource(undefined, url.searchParams);
|
|
4009
|
+
return {
|
|
4010
|
+
contents: [
|
|
4011
|
+
{
|
|
4012
|
+
uri,
|
|
4013
|
+
mimeType: result.contentType,
|
|
4014
|
+
text: JSON.stringify(result.data, null, 2),
|
|
4015
|
+
},
|
|
4016
|
+
],
|
|
4017
|
+
_meta: {
|
|
4018
|
+
lastModified: result.lastModified,
|
|
4019
|
+
etag: result.etag,
|
|
4020
|
+
cacheKey: result.cacheKey,
|
|
4021
|
+
},
|
|
4022
|
+
};
|
|
4023
|
+
}
|
|
4024
|
+
case 'validated_patterns': {
|
|
4025
|
+
const { generateValidatedPatternsCatalogResource } = await import('./resources/validated-patterns-catalog-resource.js');
|
|
4026
|
+
const result = await generateValidatedPatternsCatalogResource();
|
|
4027
|
+
return {
|
|
4028
|
+
contents: [
|
|
4029
|
+
{
|
|
4030
|
+
uri,
|
|
4031
|
+
mimeType: result.contentType,
|
|
4032
|
+
text: JSON.stringify(result.data, null, 2),
|
|
4033
|
+
},
|
|
4034
|
+
],
|
|
4035
|
+
_meta: {
|
|
4036
|
+
lastModified: result.lastModified,
|
|
4037
|
+
etag: result.etag,
|
|
4038
|
+
cacheKey: result.cacheKey,
|
|
4039
|
+
},
|
|
4040
|
+
};
|
|
4041
|
+
}
|
|
4042
|
+
default:
|
|
4043
|
+
throw new McpAdrError(`Unknown resource type: ${resourceType}`, 'UNKNOWN_RESOURCE');
|
|
4044
|
+
}
|
|
4045
|
+
}
|
|
4046
|
+
catch (error) {
|
|
4047
|
+
if (error instanceof McpAdrError) {
|
|
4048
|
+
throw error;
|
|
4049
|
+
}
|
|
4050
|
+
throw new McpAdrError(`Failed to read resource: ${error instanceof Error ? error.message : String(error)}`, 'RESOURCE_ERROR');
|
|
4051
|
+
}
|
|
4052
|
+
}
|
|
4053
|
+
/**
|
|
4054
|
+
* Start the server
|
|
4055
|
+
*/
|
|
4056
|
+
async start() {
|
|
4057
|
+
// Validate configuration before starting
|
|
4058
|
+
await this.validateConfiguration();
|
|
4059
|
+
// Initialize memory entity manager
|
|
4060
|
+
await this.memoryEntityManager.initialize();
|
|
4061
|
+
this.logger.info('Memory Entity Manager initialized', 'McpAdrAnalysisServer');
|
|
4062
|
+
// Initialize conversation memory manager (Phase 3: Structured External Memory)
|
|
4063
|
+
await this.conversationMemoryManager.initialize();
|
|
4064
|
+
this.logger.info('Phase 3 (Structured External Memory) initialized', 'McpAdrAnalysisServer');
|
|
4065
|
+
// Generate initial server context file
|
|
4066
|
+
try {
|
|
4067
|
+
await this.contextGenerator.writeContextFile(this.kgManager, this.memoryEntityManager, this.conversationMemoryManager);
|
|
4068
|
+
this.logger.info('Server context file generated at .mcp-server-context.md', 'McpAdrAnalysisServer');
|
|
4069
|
+
}
|
|
4070
|
+
catch (error) {
|
|
4071
|
+
this.logger.warn('Failed to generate initial server context file', 'McpAdrAnalysisServer', {
|
|
4072
|
+
error: error instanceof Error ? error.message : String(error),
|
|
4073
|
+
});
|
|
4074
|
+
}
|
|
4075
|
+
const transport = new StdioServerTransport();
|
|
4076
|
+
await this.server.connect(transport);
|
|
4077
|
+
// Keep the process alive
|
|
4078
|
+
process.on('SIGINT', async () => {
|
|
4079
|
+
await this.server.close();
|
|
4080
|
+
process.exit(0);
|
|
4081
|
+
});
|
|
4082
|
+
}
|
|
4083
|
+
/**
|
|
4084
|
+
* File system tool implementations
|
|
4085
|
+
*/
|
|
4086
|
+
/**
|
|
4087
|
+
* List accessible roots (MCP best practice)
|
|
4088
|
+
*/
|
|
4089
|
+
async listRoots() {
|
|
4090
|
+
const roots = this.rootManager.listRoots();
|
|
4091
|
+
const rootsList = roots
|
|
4092
|
+
.map(r => `### ${r.name}\n\n**Path**: \`${r.path}\`\n\n**Description**: ${r.description}\n`)
|
|
4093
|
+
.join('\n');
|
|
4094
|
+
return {
|
|
4095
|
+
content: [
|
|
4096
|
+
{
|
|
4097
|
+
type: 'text',
|
|
4098
|
+
text: `# Available File System Roots\n\nThese are the directories that can be accessed by this MCP server.\n\n${rootsList}\nUse these paths with \`read_directory\` and \`read_file\` tools to explore and access files.`,
|
|
4099
|
+
},
|
|
4100
|
+
],
|
|
4101
|
+
};
|
|
4102
|
+
}
|
|
4103
|
+
/**
|
|
4104
|
+
* Read directory contents (MCP best practice for autonomous file discovery)
|
|
4105
|
+
*/
|
|
4106
|
+
async readDirectory(args) {
|
|
4107
|
+
const targetPath = args.path || this.config.projectPath;
|
|
4108
|
+
try {
|
|
4109
|
+
const path = await import('path');
|
|
4110
|
+
const resolvedPath = path.resolve(targetPath);
|
|
4111
|
+
// Security check: ensure path is within accessible roots
|
|
4112
|
+
if (!this.rootManager.isPathAllowed(resolvedPath)) {
|
|
4113
|
+
const roots = this.rootManager.listRoots();
|
|
4114
|
+
const rootList = roots.map(r => ` - ${r.name}: ${r.path}`).join('\n');
|
|
4115
|
+
throw new McpAdrError(`Access denied: Path '${targetPath}' is outside accessible roots.\n\nAccessible roots:\n${rootList}\n\nUse list_roots tool for more details.`, 'ACCESS_DENIED');
|
|
4116
|
+
}
|
|
4117
|
+
const { readdir } = await import('fs/promises');
|
|
4118
|
+
const entries = await readdir(resolvedPath, { withFileTypes: true });
|
|
4119
|
+
const files = entries.filter(e => e.isFile()).map(e => `📄 ${e.name}`);
|
|
4120
|
+
const dirs = entries.filter(e => e.isDirectory()).map(e => `📁 ${e.name}/`);
|
|
4121
|
+
const root = this.rootManager.getRootForPath(resolvedPath);
|
|
4122
|
+
const relPath = this.rootManager.getRelativePathFromRoot(resolvedPath);
|
|
4123
|
+
const filesList = files.length > 0 ? files.join('\n') : '(no files)';
|
|
4124
|
+
const dirsList = dirs.length > 0 ? dirs.join('\n') : '(no directories)';
|
|
4125
|
+
return {
|
|
4126
|
+
content: [
|
|
4127
|
+
{
|
|
4128
|
+
type: 'text',
|
|
4129
|
+
text: `# Directory: ${targetPath}\n\n**Root**: ${root?.name}\n**Relative Path**: ${relPath || '/'}\n**Full Path**: \`${resolvedPath}\`\n\n## Directories (${dirs.length})\n\n${dirsList}\n\n## Files (${files.length})\n\n${filesList}`,
|
|
4130
|
+
},
|
|
4131
|
+
],
|
|
4132
|
+
};
|
|
4133
|
+
}
|
|
4134
|
+
catch (error) {
|
|
4135
|
+
throw new McpAdrError(`Failed to read directory: ${error instanceof Error ? error.message : String(error)}`, 'DIRECTORY_READ_ERROR');
|
|
4136
|
+
}
|
|
4137
|
+
}
|
|
4138
|
+
async readFile(args) {
|
|
4139
|
+
const { filePath } = args;
|
|
4140
|
+
try {
|
|
4141
|
+
const fs = await import('fs/promises');
|
|
4142
|
+
const path = await import('path');
|
|
4143
|
+
// Resolve path (handle both relative and absolute paths)
|
|
4144
|
+
const safePath = path.resolve(filePath);
|
|
4145
|
+
// Security check: ensure path is within accessible roots
|
|
4146
|
+
if (!this.rootManager.isPathAllowed(safePath)) {
|
|
4147
|
+
const roots = this.rootManager.listRoots();
|
|
4148
|
+
const rootList = roots.map(r => ` - ${r.name}: ${r.path}`).join('\n');
|
|
4149
|
+
throw new McpAdrError(`Access denied: Path '${filePath}' is outside accessible roots.\n\nAccessible roots:\n${rootList}\n\nUse list_roots tool for more details.`, 'ACCESS_DENIED');
|
|
4150
|
+
}
|
|
4151
|
+
const content = await fs.readFile(safePath, 'utf-8');
|
|
4152
|
+
return {
|
|
4153
|
+
content: [
|
|
4154
|
+
{
|
|
4155
|
+
type: 'text',
|
|
4156
|
+
text: content,
|
|
4157
|
+
},
|
|
4158
|
+
],
|
|
4159
|
+
};
|
|
4160
|
+
}
|
|
4161
|
+
catch (error) {
|
|
4162
|
+
throw new McpAdrError(`Failed to read file: ${error instanceof Error ? error.message : String(error)}`, 'FILE_READ_ERROR');
|
|
4163
|
+
}
|
|
4164
|
+
}
|
|
4165
|
+
async writeFile(args) {
|
|
4166
|
+
const { filePath, content } = args;
|
|
4167
|
+
try {
|
|
4168
|
+
const fs = await import('fs/promises');
|
|
4169
|
+
const path = await import('path');
|
|
4170
|
+
// Resolve path relative to project path for security
|
|
4171
|
+
const safePath = path.resolve(this.config.projectPath, filePath);
|
|
4172
|
+
// Security check: ensure path is within project directory
|
|
4173
|
+
if (!safePath.startsWith(this.config.projectPath)) {
|
|
4174
|
+
throw new McpAdrError('Access denied: Path is outside project directory', 'ACCESS_DENIED');
|
|
4175
|
+
}
|
|
4176
|
+
// Ensure directory exists
|
|
4177
|
+
await fs.mkdir(path.dirname(safePath), { recursive: true });
|
|
4178
|
+
// Write file
|
|
4179
|
+
await fs.writeFile(safePath, content, 'utf-8');
|
|
4180
|
+
return {
|
|
4181
|
+
content: [
|
|
4182
|
+
{
|
|
4183
|
+
type: 'text',
|
|
4184
|
+
text: `Successfully wrote to ${filePath}`,
|
|
4185
|
+
},
|
|
4186
|
+
],
|
|
4187
|
+
};
|
|
4188
|
+
}
|
|
4189
|
+
catch (error) {
|
|
4190
|
+
throw new McpAdrError(`Failed to write file: ${error instanceof Error ? error.message : String(error)}`, 'FILE_WRITE_ERROR');
|
|
4191
|
+
}
|
|
4192
|
+
}
|
|
4193
|
+
async listDirectory(args) {
|
|
4194
|
+
const { path: dirPath } = args;
|
|
4195
|
+
try {
|
|
4196
|
+
const fs = await import('fs/promises');
|
|
4197
|
+
const path = await import('path');
|
|
4198
|
+
// Resolve path relative to project path for security
|
|
4199
|
+
const safePath = path.resolve(this.config.projectPath, dirPath);
|
|
4200
|
+
// Security check: ensure path is within project directory
|
|
4201
|
+
if (!safePath.startsWith(this.config.projectPath)) {
|
|
4202
|
+
throw new McpAdrError('Access denied: Path is outside project directory', 'ACCESS_DENIED');
|
|
4203
|
+
}
|
|
4204
|
+
const entries = await fs.readdir(safePath, { withFileTypes: true });
|
|
4205
|
+
const fileList = entries.map(entry => ({
|
|
4206
|
+
name: entry.name,
|
|
4207
|
+
type: entry.isDirectory() ? 'directory' : 'file',
|
|
4208
|
+
path: path.join(dirPath, entry.name),
|
|
4209
|
+
}));
|
|
4210
|
+
return {
|
|
4211
|
+
content: [
|
|
4212
|
+
{
|
|
4213
|
+
type: 'text',
|
|
4214
|
+
text: JSON.stringify(fileList, null, 2),
|
|
4215
|
+
},
|
|
4216
|
+
],
|
|
4217
|
+
};
|
|
4218
|
+
}
|
|
4219
|
+
catch (error) {
|
|
4220
|
+
throw new McpAdrError(`Failed to list directory: ${error instanceof Error ? error.message : String(error)}`, 'DIRECTORY_LIST_ERROR');
|
|
4221
|
+
}
|
|
4222
|
+
}
|
|
4223
|
+
async generateDeploymentGuidance(args) {
|
|
4224
|
+
try {
|
|
4225
|
+
const { generateDeploymentGuidance } = await import('./tools/deployment-guidance-tool.js');
|
|
4226
|
+
return await generateDeploymentGuidance(args);
|
|
4227
|
+
}
|
|
4228
|
+
catch (error) {
|
|
4229
|
+
throw new McpAdrError(`Deployment guidance generation failed: ${error instanceof Error ? error.message : String(error)}`, 'DEPLOYMENT_GUIDANCE_ERROR');
|
|
4230
|
+
}
|
|
4231
|
+
}
|
|
4232
|
+
async smartGitPush(args) {
|
|
4233
|
+
try {
|
|
4234
|
+
const { smartGitPush } = await import('./tools/smart-git-push-tool-v2.js');
|
|
4235
|
+
return await smartGitPush(args);
|
|
4236
|
+
}
|
|
4237
|
+
catch (error) {
|
|
4238
|
+
throw new McpAdrError(`Smart git push failed: ${error instanceof Error ? error.message : String(error)}`, 'SMART_GIT_PUSH_ERROR');
|
|
4239
|
+
}
|
|
4240
|
+
}
|
|
4241
|
+
async deploymentReadiness(args) {
|
|
4242
|
+
try {
|
|
4243
|
+
const { deploymentReadiness } = await import('./tools/deployment-readiness-tool.js');
|
|
4244
|
+
return await deploymentReadiness(args);
|
|
4245
|
+
}
|
|
4246
|
+
catch (error) {
|
|
4247
|
+
throw new McpAdrError(`Deployment readiness check failed: ${error instanceof Error ? error.message : String(error)}`, 'DEPLOYMENT_READINESS_ERROR');
|
|
4248
|
+
}
|
|
4249
|
+
}
|
|
4250
|
+
async releaseTracking(args) {
|
|
4251
|
+
try {
|
|
4252
|
+
const { releaseTracking } = await import('./tools/release-tracking-tool.js');
|
|
4253
|
+
return await releaseTracking(args);
|
|
4254
|
+
}
|
|
4255
|
+
catch (error) {
|
|
4256
|
+
throw new McpAdrError(`Release tracking failed: ${error instanceof Error ? error.message : String(error)}`, 'RELEASE_TRACKING_ERROR');
|
|
4257
|
+
}
|
|
4258
|
+
}
|
|
4259
|
+
async generateAdrTodo(args) {
|
|
4260
|
+
try {
|
|
4261
|
+
const { generateAdrTodo } = await import('./tools/generate-adr-todo-tool.js');
|
|
4262
|
+
return await generateAdrTodo(args);
|
|
4263
|
+
}
|
|
4264
|
+
catch (error) {
|
|
4265
|
+
throw new McpAdrError(`generate_adr_todo failed: ${error instanceof Error ? error.message : String(error)}`, 'GENERATE_ADR_TODO_ERROR');
|
|
4266
|
+
}
|
|
4267
|
+
}
|
|
4268
|
+
async troubleshootGuidedWorkflow(args) {
|
|
4269
|
+
try {
|
|
4270
|
+
const { troubleshootGuidedWorkflow } = await import('./tools/troubleshoot-guided-workflow-tool.js');
|
|
4271
|
+
return await troubleshootGuidedWorkflow(args);
|
|
4272
|
+
}
|
|
4273
|
+
catch (error) {
|
|
4274
|
+
throw new McpAdrError(`Troubleshoot guided workflow failed: ${error instanceof Error ? error.message : String(error)}`, 'TROUBLESHOOT_GUIDED_WORKFLOW_ERROR');
|
|
4275
|
+
}
|
|
4276
|
+
}
|
|
4277
|
+
async smartScore(_args) {
|
|
4278
|
+
// Smart score tool was removed - return deprecation message
|
|
4279
|
+
return {
|
|
4280
|
+
content: [
|
|
4281
|
+
{
|
|
4282
|
+
type: 'text',
|
|
4283
|
+
text: `⚠️ **Smart Score Tool Deprecated**
|
|
4284
|
+
|
|
4285
|
+
This tool has been deprecated and replaced with memory-centric health scoring.
|
|
4286
|
+
|
|
4287
|
+
**Replacement:** The new MemoryHealthScoring system tracks:
|
|
4288
|
+
- Memory quality and relevance
|
|
4289
|
+
- Retrieval performance
|
|
4290
|
+
- Entity relationship coherence
|
|
4291
|
+
- Context utilization
|
|
4292
|
+
- Decision alignment
|
|
4293
|
+
|
|
4294
|
+
**Migration:** Health scoring is now integrated into the knowledge graph and automatically calculated based on memory usage patterns.`,
|
|
4295
|
+
},
|
|
4296
|
+
],
|
|
4297
|
+
isError: false,
|
|
4298
|
+
};
|
|
4299
|
+
}
|
|
4300
|
+
async mcpPlanning(args) {
|
|
4301
|
+
try {
|
|
4302
|
+
const { mcpPlanning } = await import('./tools/mcp-planning-tool.js');
|
|
4303
|
+
return await mcpPlanning(args);
|
|
4304
|
+
}
|
|
4305
|
+
catch (error) {
|
|
4306
|
+
throw new McpAdrError(`MCP planning failed: ${error instanceof Error ? error.message : String(error)}`, 'MCP_PLANNING_ERROR');
|
|
4307
|
+
}
|
|
4308
|
+
}
|
|
4309
|
+
async memoryLoading(args) {
|
|
4310
|
+
try {
|
|
4311
|
+
const { MemoryLoadingTool } = await import('./tools/memory-loading-tool.js');
|
|
4312
|
+
const memoryTool = new MemoryLoadingTool();
|
|
4313
|
+
return await memoryTool.execute(args);
|
|
4314
|
+
}
|
|
4315
|
+
catch (error) {
|
|
4316
|
+
throw new McpAdrError(`Memory loading failed: ${error instanceof Error ? error.message : String(error)}`, 'MEMORY_LOADING_ERROR');
|
|
4317
|
+
}
|
|
4318
|
+
}
|
|
4319
|
+
async expandAnalysisSection(args) {
|
|
4320
|
+
try {
|
|
4321
|
+
const { expandAnalysisSection } = await import('./tools/expand-analysis-tool.js');
|
|
4322
|
+
return await expandAnalysisSection(args);
|
|
4323
|
+
}
|
|
4324
|
+
catch (error) {
|
|
4325
|
+
throw new McpAdrError(`Failed to expand analysis: ${error instanceof Error ? error.message : String(error)}`, 'EXPAND_ANALYSIS_ERROR');
|
|
4326
|
+
}
|
|
4327
|
+
}
|
|
4328
|
+
async interactiveAdrPlanning(args) {
|
|
4329
|
+
try {
|
|
4330
|
+
const { interactiveAdrPlanning } = await import('./tools/interactive-adr-planning-tool.js');
|
|
4331
|
+
return await interactiveAdrPlanning(args);
|
|
4332
|
+
}
|
|
4333
|
+
catch (error) {
|
|
4334
|
+
throw new McpAdrError(`Interactive ADR planning failed: ${error instanceof Error ? error.message : String(error)}`, 'INTERACTIVE_ADR_PLANNING_ERROR');
|
|
4335
|
+
}
|
|
4336
|
+
}
|
|
4337
|
+
/**
|
|
4338
|
+
* Tool chain orchestrator implementation
|
|
4339
|
+
*/
|
|
4340
|
+
async toolChainOrchestrator(args) {
|
|
4341
|
+
try {
|
|
4342
|
+
const { toolChainOrchestrator } = await import('./tools/tool-chain-orchestrator.js');
|
|
4343
|
+
return await toolChainOrchestrator(args);
|
|
4344
|
+
}
|
|
4345
|
+
catch (error) {
|
|
4346
|
+
throw new McpAdrError(`Tool chain orchestration failed: ${error instanceof Error ? error.message : String(error)}`, 'TOOL_CHAIN_ORCHESTRATOR_ERROR');
|
|
4347
|
+
}
|
|
4348
|
+
}
|
|
4349
|
+
/**
|
|
4350
|
+
* Phase 3: Expand Memory Tool
|
|
4351
|
+
* Retrieves and expands stored content from tiered responses
|
|
4352
|
+
*/
|
|
4353
|
+
async expandMemory(args) {
|
|
4354
|
+
try {
|
|
4355
|
+
const { expandMemory } = await import('./tools/conversation-memory-tool.js');
|
|
4356
|
+
return await expandMemory(args, this.conversationMemoryManager);
|
|
4357
|
+
}
|
|
4358
|
+
catch (error) {
|
|
4359
|
+
throw new McpAdrError(`Memory expansion failed: ${error instanceof Error ? error.message : String(error)}`, 'MEMORY_EXPANSION_ERROR');
|
|
4360
|
+
}
|
|
4361
|
+
}
|
|
4362
|
+
/**
|
|
4363
|
+
* Phase 3: Query Conversation History Tool
|
|
4364
|
+
* Searches and retrieves conversation sessions
|
|
4365
|
+
*/
|
|
4366
|
+
async queryConversationHistory(args) {
|
|
4367
|
+
try {
|
|
4368
|
+
const { queryConversationHistory } = await import('./tools/conversation-memory-tool.js');
|
|
4369
|
+
return await queryConversationHistory(args, this.conversationMemoryManager);
|
|
4370
|
+
}
|
|
4371
|
+
catch (error) {
|
|
4372
|
+
throw new McpAdrError(`Conversation history query failed: ${error instanceof Error ? error.message : String(error)}`, 'CONVERSATION_QUERY_ERROR');
|
|
4373
|
+
}
|
|
4374
|
+
}
|
|
4375
|
+
/**
|
|
4376
|
+
* Phase 3: Get Conversation Snapshot Tool
|
|
4377
|
+
* Retrieves current conversation context
|
|
4378
|
+
*/
|
|
4379
|
+
async getConversationSnapshot(args) {
|
|
4380
|
+
try {
|
|
4381
|
+
const { getConversationSnapshot } = await import('./tools/conversation-memory-tool.js');
|
|
4382
|
+
return await getConversationSnapshot(args, this.conversationMemoryManager);
|
|
4383
|
+
}
|
|
4384
|
+
catch (error) {
|
|
4385
|
+
throw new McpAdrError(`Conversation snapshot retrieval failed: ${error instanceof Error ? error.message : String(error)}`, 'SNAPSHOT_ERROR');
|
|
4386
|
+
}
|
|
4387
|
+
}
|
|
4388
|
+
/**
|
|
4389
|
+
* Phase 3: Get Memory Statistics Tool
|
|
4390
|
+
* Retrieves conversation memory statistics
|
|
4391
|
+
*/
|
|
4392
|
+
async getMemoryStats() {
|
|
4393
|
+
try {
|
|
4394
|
+
const { getMemoryStats } = await import('./tools/conversation-memory-tool.js');
|
|
4395
|
+
return await getMemoryStats(this.conversationMemoryManager);
|
|
4396
|
+
}
|
|
4397
|
+
catch (error) {
|
|
4398
|
+
throw new McpAdrError(`Memory stats retrieval failed: ${error instanceof Error ? error.message : String(error)}`, 'MEMORY_STATS_ERROR');
|
|
4399
|
+
}
|
|
4400
|
+
}
|
|
4401
|
+
/**
|
|
4402
|
+
* Update Knowledge Tool (ADR-018)
|
|
4403
|
+
* Simple CRUD operations for knowledge graph
|
|
4404
|
+
*/
|
|
4405
|
+
async updateKnowledge(args) {
|
|
4406
|
+
try {
|
|
4407
|
+
const { updateKnowledge } = await import('./tools/update-knowledge-tool.js');
|
|
4408
|
+
return await updateKnowledge(args, createNoOpContext(), this.kgManager);
|
|
4409
|
+
}
|
|
4410
|
+
catch (error) {
|
|
4411
|
+
throw new McpAdrError(`Knowledge update failed: ${error instanceof Error ? error.message : String(error)}`, 'KNOWLEDGE_UPDATE_ERROR');
|
|
4412
|
+
}
|
|
4413
|
+
}
|
|
4414
|
+
/**
|
|
4415
|
+
* Get Server Context Tool
|
|
4416
|
+
* Generates comprehensive server context file for LLM @ referencing
|
|
4417
|
+
*/
|
|
4418
|
+
async getServerContext(args) {
|
|
4419
|
+
try {
|
|
4420
|
+
const { getServerContext } = await import('./tools/get-server-context-tool.js');
|
|
4421
|
+
return await getServerContext(args, this.kgManager, this.memoryEntityManager, this.conversationMemoryManager);
|
|
4422
|
+
}
|
|
4423
|
+
catch (error) {
|
|
4424
|
+
throw new McpAdrError(`Server context generation failed: ${error instanceof Error ? error.message : String(error)}`, 'SERVER_CONTEXT_ERROR');
|
|
4425
|
+
}
|
|
4426
|
+
}
|
|
4427
|
+
/**
|
|
4428
|
+
* Get Current Datetime Tool
|
|
4429
|
+
* Returns the current date and time in various formats for ADR generation and timestamping
|
|
4430
|
+
*/
|
|
4431
|
+
async getCurrentDatetime(args) {
|
|
4432
|
+
const { timezone = 'UTC', format = 'all', includeTimestamp = true } = args;
|
|
4433
|
+
try {
|
|
4434
|
+
const now = new Date();
|
|
4435
|
+
// Format date for different timezones
|
|
4436
|
+
const formatOptions = {
|
|
4437
|
+
timeZone: timezone,
|
|
4438
|
+
year: 'numeric',
|
|
4439
|
+
month: '2-digit',
|
|
4440
|
+
day: '2-digit',
|
|
4441
|
+
hour: '2-digit',
|
|
4442
|
+
minute: '2-digit',
|
|
4443
|
+
second: '2-digit',
|
|
4444
|
+
hour12: false,
|
|
4445
|
+
};
|
|
4446
|
+
// Get date parts for the specified timezone
|
|
4447
|
+
const formatter = new Intl.DateTimeFormat('en-CA', {
|
|
4448
|
+
timeZone: timezone,
|
|
4449
|
+
year: 'numeric',
|
|
4450
|
+
month: '2-digit',
|
|
4451
|
+
day: '2-digit',
|
|
4452
|
+
});
|
|
4453
|
+
const parts = formatter.formatToParts(now);
|
|
4454
|
+
const year = parts.find(p => p.type === 'year')?.value || '';
|
|
4455
|
+
const month = parts.find(p => p.type === 'month')?.value || '';
|
|
4456
|
+
const day = parts.find(p => p.type === 'day')?.value || '';
|
|
4457
|
+
// ADR date format: YYYY-MM-DD
|
|
4458
|
+
const adrDate = `${year}-${month}-${day}`;
|
|
4459
|
+
// ISO 8601 format
|
|
4460
|
+
const isoDate = now.toISOString();
|
|
4461
|
+
// Human-readable format
|
|
4462
|
+
const humanFormatter = new Intl.DateTimeFormat('en-US', {
|
|
4463
|
+
...formatOptions,
|
|
4464
|
+
weekday: 'long',
|
|
4465
|
+
month: 'long',
|
|
4466
|
+
});
|
|
4467
|
+
const humanDate = humanFormatter.format(now);
|
|
4468
|
+
// Build response based on requested format
|
|
4469
|
+
let responseData = {};
|
|
4470
|
+
switch (format) {
|
|
4471
|
+
case 'iso':
|
|
4472
|
+
responseData = { iso: isoDate };
|
|
4473
|
+
break;
|
|
4474
|
+
case 'human':
|
|
4475
|
+
responseData = { human: humanDate };
|
|
4476
|
+
break;
|
|
4477
|
+
case 'adr':
|
|
4478
|
+
responseData = { adr: adrDate };
|
|
4479
|
+
break;
|
|
4480
|
+
case 'all':
|
|
4481
|
+
default:
|
|
4482
|
+
responseData = {
|
|
4483
|
+
iso: isoDate,
|
|
4484
|
+
human: humanDate,
|
|
4485
|
+
adr: adrDate,
|
|
4486
|
+
timezone: timezone,
|
|
4487
|
+
};
|
|
4488
|
+
}
|
|
4489
|
+
if (includeTimestamp) {
|
|
4490
|
+
responseData['timestamp'] = now.getTime();
|
|
4491
|
+
}
|
|
4492
|
+
const responseText = `# Current Date and Time
|
|
4493
|
+
|
|
4494
|
+
## Formats
|
|
4495
|
+
${format === 'all' || format === 'iso' ? `- **ISO 8601**: ${isoDate}` : ''}
|
|
4496
|
+
${format === 'all' || format === 'human' ? `- **Human Readable**: ${humanDate}` : ''}
|
|
4497
|
+
${format === 'all' || format === 'adr' ? `- **ADR Date (YYYY-MM-DD)**: ${adrDate}` : ''}
|
|
4498
|
+
${format === 'all' ? `- **Timezone**: ${timezone}` : ''}
|
|
4499
|
+
${includeTimestamp ? `- **Unix Timestamp (ms)**: ${now.getTime()}` : ''}
|
|
4500
|
+
|
|
4501
|
+
## Usage for ADR Generation
|
|
4502
|
+
|
|
4503
|
+
When generating ADRs, use the ADR date format (\`${adrDate}\`) in the Date field:
|
|
4504
|
+
|
|
4505
|
+
\`\`\`markdown
|
|
4506
|
+
# ADR-XXXX: [Title]
|
|
4507
|
+
|
|
4508
|
+
## Date
|
|
4509
|
+
${adrDate}
|
|
4510
|
+
|
|
4511
|
+
## Status
|
|
4512
|
+
Proposed
|
|
4513
|
+
\`\`\`
|
|
4514
|
+
|
|
4515
|
+
## Raw Data
|
|
4516
|
+
|
|
4517
|
+
\`\`\`json
|
|
4518
|
+
${JSON.stringify(responseData, null, 2)}
|
|
4519
|
+
\`\`\`
|
|
4520
|
+
`;
|
|
4521
|
+
return {
|
|
4522
|
+
content: [
|
|
4523
|
+
{
|
|
4524
|
+
type: 'text',
|
|
4525
|
+
text: responseText,
|
|
4526
|
+
},
|
|
4527
|
+
],
|
|
4528
|
+
};
|
|
4529
|
+
}
|
|
4530
|
+
catch (error) {
|
|
4531
|
+
throw new McpAdrError(`Failed to get current datetime: ${error instanceof Error ? error.message : String(error)}`, 'DATETIME_ERROR');
|
|
4532
|
+
}
|
|
4533
|
+
}
|
|
4534
|
+
/**
|
|
4535
|
+
* Set Project Path Tool - Dynamic Session Configuration
|
|
4536
|
+
*
|
|
4537
|
+
* @description Dynamically sets the active project path for the current session.
|
|
4538
|
+
* This allows switching between projects without restarting the server or modifying
|
|
4539
|
+
* environment variables. Updates both the config and the RootManager.
|
|
4540
|
+
*
|
|
4541
|
+
* @param args - Set project path arguments
|
|
4542
|
+
* @param args.path - Absolute path to the project directory
|
|
4543
|
+
* @param args.validatePath - Whether to validate the path exists (default: true)
|
|
4544
|
+
* @returns Promise<CallToolResult> - Confirmation of the path change
|
|
4545
|
+
*/
|
|
4546
|
+
async setProjectPath(args) {
|
|
4547
|
+
const { path: newPath, validatePath = true } = args;
|
|
4548
|
+
const { resolve } = await import('path');
|
|
4549
|
+
try {
|
|
4550
|
+
// Resolve to absolute path
|
|
4551
|
+
const absolutePath = resolve(newPath);
|
|
4552
|
+
const previousPath = this.config.projectPath;
|
|
4553
|
+
// Validate the path if requested
|
|
4554
|
+
if (validatePath) {
|
|
4555
|
+
await validateProjectPath(absolutePath);
|
|
4556
|
+
}
|
|
4557
|
+
// Update the server configuration
|
|
4558
|
+
this.config.projectPath = absolutePath;
|
|
4559
|
+
// Re-initialize the RootManager with the new path
|
|
4560
|
+
this.rootManager = new RootManager(absolutePath, this.config.adrDirectory);
|
|
4561
|
+
this.logger.info(`Project path changed: ${previousPath} -> ${absolutePath}`);
|
|
4562
|
+
const responseText = `# Project Path Updated
|
|
4563
|
+
|
|
4564
|
+
## Configuration
|
|
4565
|
+
- **Previous Path**: \`${previousPath}\`
|
|
4566
|
+
- **New Path**: \`${absolutePath}\`
|
|
4567
|
+
- **ADR Directory**: \`${this.config.adrDirectory}\`
|
|
4568
|
+
- **Full ADR Path**: \`${resolve(absolutePath, this.config.adrDirectory)}\`
|
|
4569
|
+
|
|
4570
|
+
## Status
|
|
4571
|
+
✅ Project path successfully updated for this session.
|
|
4572
|
+
|
|
4573
|
+
## Note
|
|
4574
|
+
All subsequent tool calls will use this path as the default project path.
|
|
4575
|
+
You can still override it per-tool by passing \`projectPath\` as an argument.
|
|
4576
|
+
|
|
4577
|
+
To make this permanent, set the \`PROJECT_PATH\` environment variable.
|
|
4578
|
+
`;
|
|
4579
|
+
return {
|
|
4580
|
+
content: [
|
|
4581
|
+
{
|
|
4582
|
+
type: 'text',
|
|
4583
|
+
text: responseText,
|
|
4584
|
+
},
|
|
4585
|
+
],
|
|
4586
|
+
};
|
|
4587
|
+
}
|
|
4588
|
+
catch (error) {
|
|
4589
|
+
throw new McpAdrError(`Failed to set project path: ${error instanceof Error ? error.message : String(error)}`, 'SET_PROJECT_PATH_ERROR');
|
|
4590
|
+
}
|
|
4591
|
+
}
|
|
4592
|
+
/**
|
|
4593
|
+
* Load Prompt Tool - CE-MCP Phase 4 Lazy Loading
|
|
4594
|
+
*
|
|
4595
|
+
* @description Loads prompts on-demand instead of eagerly loading all prompts at startup.
|
|
4596
|
+
* This reduces token usage by ~96% (from 28K tokens to ~1K on-demand).
|
|
4597
|
+
*
|
|
4598
|
+
* @param args - Load prompt arguments
|
|
4599
|
+
* @param args.promptName - Name of the prompt to load
|
|
4600
|
+
* @param args.section - Optional section within the prompt
|
|
4601
|
+
* @param args.estimateOnly - If true, returns only token estimate
|
|
4602
|
+
* @returns Promise<CallToolResult> - Loaded prompt content or estimate
|
|
4603
|
+
*/
|
|
4604
|
+
async loadPrompt(args) {
|
|
4605
|
+
const { promptName, section, estimateOnly = false } = args;
|
|
4606
|
+
// Import the prompt catalog dynamically to enable lazy loading
|
|
4607
|
+
const { getPromptLoader, getPromptMetadata, calculateTokenSavings } = await import('./prompts/prompt-catalog.js');
|
|
4608
|
+
const metadata = getPromptMetadata(promptName);
|
|
4609
|
+
if (!metadata) {
|
|
4610
|
+
const availablePrompts = [
|
|
4611
|
+
'adr-suggestion',
|
|
4612
|
+
'deployment-analysis',
|
|
4613
|
+
'environment-analysis',
|
|
4614
|
+
'research-question',
|
|
4615
|
+
'rule-generation',
|
|
4616
|
+
'analysis',
|
|
4617
|
+
'research-integration',
|
|
4618
|
+
'validated-pattern',
|
|
4619
|
+
'security',
|
|
4620
|
+
];
|
|
4621
|
+
return {
|
|
4622
|
+
content: [
|
|
4623
|
+
{
|
|
4624
|
+
type: 'text',
|
|
4625
|
+
text: JSON.stringify({
|
|
4626
|
+
success: false,
|
|
4627
|
+
error: `Unknown prompt: ${promptName}`,
|
|
4628
|
+
availablePrompts,
|
|
4629
|
+
hint: 'Use one of the available prompt names listed above',
|
|
4630
|
+
}, null, 2),
|
|
4631
|
+
},
|
|
4632
|
+
],
|
|
4633
|
+
isError: true,
|
|
4634
|
+
};
|
|
4635
|
+
}
|
|
4636
|
+
// If estimate only, return token information without loading
|
|
4637
|
+
if (estimateOnly) {
|
|
4638
|
+
const loader = getPromptLoader();
|
|
4639
|
+
const estimatedTokens = loader.getEstimatedTokens(promptName, section);
|
|
4640
|
+
const savings = calculateTokenSavings([promptName]);
|
|
4641
|
+
return {
|
|
4642
|
+
content: [
|
|
4643
|
+
{
|
|
4644
|
+
type: 'text',
|
|
4645
|
+
text: JSON.stringify({
|
|
4646
|
+
success: true,
|
|
4647
|
+
promptName,
|
|
4648
|
+
section: section || 'full',
|
|
4649
|
+
estimatedTokens,
|
|
4650
|
+
metadata: {
|
|
4651
|
+
file: metadata.file,
|
|
4652
|
+
category: metadata.category,
|
|
4653
|
+
totalTokens: metadata.tokens,
|
|
4654
|
+
availableSections: metadata.sections,
|
|
4655
|
+
loadOnDemand: metadata.loadOnDemand,
|
|
4656
|
+
},
|
|
4657
|
+
tokenSavings: {
|
|
4658
|
+
loaded: savings.loaded,
|
|
4659
|
+
total: savings.total,
|
|
4660
|
+
saved: savings.saved,
|
|
4661
|
+
percentage: `${savings.percentage}%`,
|
|
4662
|
+
},
|
|
4663
|
+
}, null, 2),
|
|
4664
|
+
},
|
|
4665
|
+
],
|
|
4666
|
+
};
|
|
4667
|
+
}
|
|
4668
|
+
// Load the prompt content
|
|
4669
|
+
try {
|
|
4670
|
+
const loader = getPromptLoader();
|
|
4671
|
+
const content = await loader.loadPrompt(promptName, section);
|
|
4672
|
+
return {
|
|
4673
|
+
content: [
|
|
4674
|
+
{
|
|
4675
|
+
type: 'text',
|
|
4676
|
+
text: `# Loaded Prompt: ${promptName}${section ? ` (section: ${section})` : ''}
|
|
4677
|
+
|
|
4678
|
+
## Metadata
|
|
4679
|
+
- **Category**: ${metadata.category}
|
|
4680
|
+
- **Estimated Tokens**: ${metadata.tokens}
|
|
4681
|
+
- **Available Sections**: ${metadata.sections.join(', ')}
|
|
4682
|
+
|
|
4683
|
+
## Content
|
|
4684
|
+
|
|
4685
|
+
${content}
|
|
4686
|
+
|
|
4687
|
+
---
|
|
4688
|
+
|
|
4689
|
+
*Loaded on-demand via CE-MCP lazy loading system. Token savings: ~96% compared to eager loading all prompts.*
|
|
4690
|
+
`,
|
|
4691
|
+
},
|
|
4692
|
+
],
|
|
4693
|
+
};
|
|
4694
|
+
}
|
|
4695
|
+
catch (error) {
|
|
4696
|
+
throw new McpAdrError(`Failed to load prompt '${promptName}'${section ? ` section '${section}'` : ''}: ${error instanceof Error ? error.message : String(error)}`, 'PROMPT_LOAD_ERROR');
|
|
4697
|
+
}
|
|
4698
|
+
}
|
|
4699
|
+
}
|
|
4700
|
+
//# sourceMappingURL=mcp-adr-analysis-server.js.map
|