mcp-adr-analysis-server 1.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +608 -0
- package/dist/src/index.d.ts +10 -0
- package/dist/src/index.d.ts.map +1 -0
- package/dist/src/index.js +1722 -0
- package/dist/src/index.js.map +1 -0
- package/dist/src/prompts/adr-suggestion-prompts.d.ts +24 -0
- package/dist/src/prompts/adr-suggestion-prompts.d.ts.map +1 -0
- package/dist/src/prompts/adr-suggestion-prompts.js +383 -0
- package/dist/src/prompts/adr-suggestion-prompts.js.map +1 -0
- package/dist/src/prompts/analysis-prompts.d.ts +24 -0
- package/dist/src/prompts/analysis-prompts.d.ts.map +1 -0
- package/dist/src/prompts/analysis-prompts.js +489 -0
- package/dist/src/prompts/analysis-prompts.js.map +1 -0
- package/dist/src/prompts/deployment-analysis-prompts.d.ts +54 -0
- package/dist/src/prompts/deployment-analysis-prompts.d.ts.map +1 -0
- package/dist/src/prompts/deployment-analysis-prompts.js +712 -0
- package/dist/src/prompts/deployment-analysis-prompts.js.map +1 -0
- package/dist/src/prompts/environment-analysis-prompts.d.ts +34 -0
- package/dist/src/prompts/environment-analysis-prompts.d.ts.map +1 -0
- package/dist/src/prompts/environment-analysis-prompts.js +724 -0
- package/dist/src/prompts/environment-analysis-prompts.js.map +1 -0
- package/dist/src/prompts/index.d.ts +43 -0
- package/dist/src/prompts/index.d.ts.map +1 -0
- package/dist/src/prompts/index.js +384 -0
- package/dist/src/prompts/index.js.map +1 -0
- package/dist/src/prompts/research-integration-prompts.d.ts +43 -0
- package/dist/src/prompts/research-integration-prompts.d.ts.map +1 -0
- package/dist/src/prompts/research-integration-prompts.js +398 -0
- package/dist/src/prompts/research-integration-prompts.js.map +1 -0
- package/dist/src/prompts/research-question-prompts.d.ts +75 -0
- package/dist/src/prompts/research-question-prompts.d.ts.map +1 -0
- package/dist/src/prompts/research-question-prompts.js +695 -0
- package/dist/src/prompts/research-question-prompts.js.map +1 -0
- package/dist/src/prompts/rule-generation-prompts.d.ts +63 -0
- package/dist/src/prompts/rule-generation-prompts.d.ts.map +1 -0
- package/dist/src/prompts/rule-generation-prompts.js +630 -0
- package/dist/src/prompts/rule-generation-prompts.js.map +1 -0
- package/dist/src/prompts/security-prompts.d.ts +23 -0
- package/dist/src/prompts/security-prompts.d.ts.map +1 -0
- package/dist/src/prompts/security-prompts.js +287 -0
- package/dist/src/prompts/security-prompts.js.map +1 -0
- package/dist/src/resources/index.d.ts +24 -0
- package/dist/src/resources/index.d.ts.map +1 -0
- package/dist/src/resources/index.js +458 -0
- package/dist/src/resources/index.js.map +1 -0
- package/dist/src/tools/adr-suggestion-tool.d.ts +40 -0
- package/dist/src/tools/adr-suggestion-tool.d.ts.map +1 -0
- package/dist/src/tools/adr-suggestion-tool.js +338 -0
- package/dist/src/tools/adr-suggestion-tool.js.map +1 -0
- package/dist/src/tools/content-masking-tool.d.ts +52 -0
- package/dist/src/tools/content-masking-tool.d.ts.map +1 -0
- package/dist/src/tools/content-masking-tool.js +206 -0
- package/dist/src/tools/content-masking-tool.js.map +1 -0
- package/dist/src/tools/deployment-analysis-tool.d.ts +39 -0
- package/dist/src/tools/deployment-analysis-tool.d.ts.map +1 -0
- package/dist/src/tools/deployment-analysis-tool.js +310 -0
- package/dist/src/tools/deployment-analysis-tool.js.map +1 -0
- package/dist/src/tools/environment-analysis-tool.d.ts +16 -0
- package/dist/src/tools/environment-analysis-tool.d.ts.map +1 -0
- package/dist/src/tools/environment-analysis-tool.js +298 -0
- package/dist/src/tools/environment-analysis-tool.js.map +1 -0
- package/dist/src/tools/research-integration-tool.d.ts +44 -0
- package/dist/src/tools/research-integration-tool.d.ts.map +1 -0
- package/dist/src/tools/research-integration-tool.js +429 -0
- package/dist/src/tools/research-integration-tool.js.map +1 -0
- package/dist/src/tools/research-question-tool.d.ts +55 -0
- package/dist/src/tools/research-question-tool.d.ts.map +1 -0
- package/dist/src/tools/research-question-tool.js +333 -0
- package/dist/src/tools/research-question-tool.js.map +1 -0
- package/dist/src/tools/rule-generation-tool.d.ts +49 -0
- package/dist/src/tools/rule-generation-tool.d.ts.map +1 -0
- package/dist/src/tools/rule-generation-tool.js +432 -0
- package/dist/src/tools/rule-generation-tool.js.map +1 -0
- package/dist/src/types/index.d.ts +531 -0
- package/dist/src/types/index.d.ts.map +1 -0
- package/dist/src/types/index.js +129 -0
- package/dist/src/types/index.js.map +1 -0
- package/dist/src/utils/adr-suggestions.d.ts +104 -0
- package/dist/src/utils/adr-suggestions.d.ts.map +1 -0
- package/dist/src/utils/adr-suggestions.js +228 -0
- package/dist/src/utils/adr-suggestions.js.map +1 -0
- package/dist/src/utils/cache.d.ts +51 -0
- package/dist/src/utils/cache.d.ts.map +1 -0
- package/dist/src/utils/cache.js +243 -0
- package/dist/src/utils/cache.js.map +1 -0
- package/dist/src/utils/config.d.ts +65 -0
- package/dist/src/utils/config.d.ts.map +1 -0
- package/dist/src/utils/config.js +118 -0
- package/dist/src/utils/config.js.map +1 -0
- package/dist/src/utils/content-masking.d.ts +79 -0
- package/dist/src/utils/content-masking.d.ts.map +1 -0
- package/dist/src/utils/content-masking.js +203 -0
- package/dist/src/utils/content-masking.js.map +1 -0
- package/dist/src/utils/deployment-analysis.d.ts +67 -0
- package/dist/src/utils/deployment-analysis.d.ts.map +1 -0
- package/dist/src/utils/deployment-analysis.js +263 -0
- package/dist/src/utils/deployment-analysis.js.map +1 -0
- package/dist/src/utils/environment-analysis.d.ts +76 -0
- package/dist/src/utils/environment-analysis.d.ts.map +1 -0
- package/dist/src/utils/environment-analysis.js +329 -0
- package/dist/src/utils/environment-analysis.js.map +1 -0
- package/dist/src/utils/file-system.d.ts +63 -0
- package/dist/src/utils/file-system.d.ts.map +1 -0
- package/dist/src/utils/file-system.js +189 -0
- package/dist/src/utils/file-system.js.map +1 -0
- package/dist/src/utils/output-masking.d.ts +45 -0
- package/dist/src/utils/output-masking.d.ts.map +1 -0
- package/dist/src/utils/output-masking.js +200 -0
- package/dist/src/utils/output-masking.js.map +1 -0
- package/dist/src/utils/research-documentation.d.ts +58 -0
- package/dist/src/utils/research-documentation.d.ts.map +1 -0
- package/dist/src/utils/research-documentation.js +438 -0
- package/dist/src/utils/research-documentation.js.map +1 -0
- package/dist/src/utils/research-integration.d.ts +89 -0
- package/dist/src/utils/research-integration.d.ts.map +1 -0
- package/dist/src/utils/research-integration.js +432 -0
- package/dist/src/utils/research-integration.js.map +1 -0
- package/dist/src/utils/research-questions.d.ts +97 -0
- package/dist/src/utils/research-questions.d.ts.map +1 -0
- package/dist/src/utils/research-questions.js +319 -0
- package/dist/src/utils/research-questions.js.map +1 -0
- package/dist/src/utils/rule-format.d.ts +76 -0
- package/dist/src/utils/rule-format.d.ts.map +1 -0
- package/dist/src/utils/rule-format.js +257 -0
- package/dist/src/utils/rule-format.js.map +1 -0
- package/dist/src/utils/rule-generation.d.ts +86 -0
- package/dist/src/utils/rule-generation.d.ts.map +1 -0
- package/dist/src/utils/rule-generation.js +330 -0
- package/dist/src/utils/rule-generation.js.map +1 -0
- package/package.json +71 -0
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* ADR suggestion utilities using prompt-driven AI analysis
|
|
3
|
+
* Implements intelligent ADR recommendations based on code analysis
|
|
4
|
+
*/
|
|
5
|
+
export interface ImplicitDecision {
|
|
6
|
+
id: string;
|
|
7
|
+
title: string;
|
|
8
|
+
category: string;
|
|
9
|
+
confidence: number;
|
|
10
|
+
evidence: string[];
|
|
11
|
+
filePaths: string[];
|
|
12
|
+
description: string;
|
|
13
|
+
context: string;
|
|
14
|
+
consequences: string;
|
|
15
|
+
alternatives: string[];
|
|
16
|
+
priority: 'low' | 'medium' | 'high' | 'critical';
|
|
17
|
+
complexity: 'low' | 'medium' | 'high';
|
|
18
|
+
riskLevel: 'low' | 'medium' | 'high' | 'critical';
|
|
19
|
+
suggestedAdrTitle: string;
|
|
20
|
+
relatedPatterns: string[];
|
|
21
|
+
}
|
|
22
|
+
export interface DecisionCluster {
|
|
23
|
+
theme: string;
|
|
24
|
+
decisions: string[];
|
|
25
|
+
suggestedCombinedAdr: string;
|
|
26
|
+
}
|
|
27
|
+
export interface ImplicitDecisionAnalysis {
|
|
28
|
+
implicitDecisions: ImplicitDecision[];
|
|
29
|
+
decisionClusters: DecisionCluster[];
|
|
30
|
+
recommendations: string[];
|
|
31
|
+
gaps: Array<{
|
|
32
|
+
area: string;
|
|
33
|
+
description: string;
|
|
34
|
+
suggestedInvestigation: string;
|
|
35
|
+
}>;
|
|
36
|
+
}
|
|
37
|
+
export interface CodeChangeDecision {
|
|
38
|
+
id: string;
|
|
39
|
+
title: string;
|
|
40
|
+
category: string;
|
|
41
|
+
confidence: number;
|
|
42
|
+
evidence: string[];
|
|
43
|
+
context: string;
|
|
44
|
+
decision: string;
|
|
45
|
+
consequences: string;
|
|
46
|
+
alternatives: string[];
|
|
47
|
+
changeMotivation: string;
|
|
48
|
+
futureImplications: string;
|
|
49
|
+
suggestedAdrTitle: string;
|
|
50
|
+
priority: 'low' | 'medium' | 'high' | 'critical';
|
|
51
|
+
}
|
|
52
|
+
export interface GeneratedAdr {
|
|
53
|
+
id: string;
|
|
54
|
+
title: string;
|
|
55
|
+
status: string;
|
|
56
|
+
date: string;
|
|
57
|
+
format: string;
|
|
58
|
+
content: string;
|
|
59
|
+
filename: string;
|
|
60
|
+
metadata: {
|
|
61
|
+
category: string;
|
|
62
|
+
tags: string[];
|
|
63
|
+
complexity: string;
|
|
64
|
+
impact: string;
|
|
65
|
+
stakeholders: string[];
|
|
66
|
+
};
|
|
67
|
+
}
|
|
68
|
+
/**
|
|
69
|
+
* Analyze project for implicit architectural decisions
|
|
70
|
+
*/
|
|
71
|
+
export declare function analyzeImplicitDecisions(projectPath: string, existingAdrs?: string[]): Promise<{
|
|
72
|
+
analysisPrompt: string;
|
|
73
|
+
instructions: string;
|
|
74
|
+
}>;
|
|
75
|
+
/**
|
|
76
|
+
* Analyze code changes for architectural decisions
|
|
77
|
+
*/
|
|
78
|
+
export declare function analyzeCodeChanges(beforeCode: string, afterCode: string, changeDescription: string, commitMessages?: string[]): Promise<{
|
|
79
|
+
analysisPrompt: string;
|
|
80
|
+
instructions: string;
|
|
81
|
+
}>;
|
|
82
|
+
/**
|
|
83
|
+
* Generate ADR from decision data
|
|
84
|
+
*/
|
|
85
|
+
export declare function generateAdrFromDecision(decisionData: {
|
|
86
|
+
title: string;
|
|
87
|
+
context: string;
|
|
88
|
+
decision: string;
|
|
89
|
+
consequences: string;
|
|
90
|
+
alternatives?: string[];
|
|
91
|
+
evidence?: string[];
|
|
92
|
+
}, templateFormat?: 'nygard' | 'madr' | 'custom', existingAdrs?: string[]): Promise<{
|
|
93
|
+
generationPrompt: string;
|
|
94
|
+
instructions: string;
|
|
95
|
+
}>;
|
|
96
|
+
/**
|
|
97
|
+
* Generate next ADR number based on existing ADRs
|
|
98
|
+
*/
|
|
99
|
+
export declare function generateNextAdrNumber(existingAdrs: string[]): string;
|
|
100
|
+
/**
|
|
101
|
+
* Suggest ADR filename based on title and number
|
|
102
|
+
*/
|
|
103
|
+
export declare function suggestAdrFilename(title: string, adrNumber?: string): string;
|
|
104
|
+
//# sourceMappingURL=adr-suggestions.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"adr-suggestions.d.ts","sourceRoot":"","sources":["../../../src/utils/adr-suggestions.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,228 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* ADR suggestion utilities using prompt-driven AI analysis
|
|
3
|
+
* Implements intelligent ADR recommendations based on code analysis
|
|
4
|
+
*/
|
|
5
|
+
import { McpAdrError } from '../types/index.js';
|
|
6
|
+
/**
|
|
7
|
+
* Analyze project for implicit architectural decisions
|
|
8
|
+
*/
|
|
9
|
+
export async function analyzeImplicitDecisions(projectPath, existingAdrs) {
|
|
10
|
+
try {
|
|
11
|
+
const { analyzeProjectStructure } = await import('./file-system.js');
|
|
12
|
+
const { generateAnalysisContext } = await import('../prompts/analysis-prompts.js');
|
|
13
|
+
const { generateImplicitDecisionDetectionPrompt } = await import('../prompts/adr-suggestion-prompts.js');
|
|
14
|
+
// Analyze project structure
|
|
15
|
+
const projectStructure = await analyzeProjectStructure(projectPath);
|
|
16
|
+
const analysisContext = generateAnalysisContext(projectStructure);
|
|
17
|
+
// Extract code patterns from project structure
|
|
18
|
+
const codePatterns = extractCodePatterns(projectStructure);
|
|
19
|
+
const analysisPrompt = generateImplicitDecisionDetectionPrompt(analysisContext, codePatterns, existingAdrs);
|
|
20
|
+
const instructions = `
|
|
21
|
+
# Implicit Decision Analysis Instructions
|
|
22
|
+
|
|
23
|
+
This analysis will identify architectural decisions that are implicit in the codebase but not formally documented.
|
|
24
|
+
|
|
25
|
+
## Analysis Scope
|
|
26
|
+
- **Project Path**: ${projectPath}
|
|
27
|
+
- **Files Analyzed**: ${projectStructure.totalFiles} files
|
|
28
|
+
- **Directories**: ${projectStructure.totalDirectories} directories
|
|
29
|
+
- **Existing ADRs**: ${existingAdrs?.length || 0} ADRs
|
|
30
|
+
|
|
31
|
+
## Next Steps
|
|
32
|
+
1. **Submit the analysis prompt** to an AI agent for decision detection
|
|
33
|
+
2. **Parse the JSON response** as ImplicitDecisionAnalysis
|
|
34
|
+
3. **Review suggested decisions** and prioritize for documentation
|
|
35
|
+
4. **Generate ADRs** for high-priority decisions using the ADR generation tool
|
|
36
|
+
|
|
37
|
+
## Expected AI Response Format
|
|
38
|
+
The AI will return a JSON object with:
|
|
39
|
+
- \`implicitDecisions\`: Array of detected implicit decisions
|
|
40
|
+
- \`decisionClusters\`: Related decisions that could be combined
|
|
41
|
+
- \`recommendations\`: Specific recommendations for documentation
|
|
42
|
+
- \`gaps\`: Areas where more investigation is needed
|
|
43
|
+
|
|
44
|
+
## Usage Example
|
|
45
|
+
\`\`\`typescript
|
|
46
|
+
const result = await analyzeImplicitDecisions(projectPath, existingAdrs);
|
|
47
|
+
// Submit result.analysisPrompt to AI agent
|
|
48
|
+
// Parse AI response as ImplicitDecisionAnalysis
|
|
49
|
+
\`\`\`
|
|
50
|
+
`;
|
|
51
|
+
return {
|
|
52
|
+
analysisPrompt,
|
|
53
|
+
instructions,
|
|
54
|
+
};
|
|
55
|
+
}
|
|
56
|
+
catch (error) {
|
|
57
|
+
throw new McpAdrError(`Failed to analyze implicit decisions: ${error instanceof Error ? error.message : String(error)}`, 'ANALYSIS_ERROR');
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
/**
|
|
61
|
+
* Analyze code changes for architectural decisions
|
|
62
|
+
*/
|
|
63
|
+
export async function analyzeCodeChanges(beforeCode, afterCode, changeDescription, commitMessages) {
|
|
64
|
+
try {
|
|
65
|
+
const { generateCodeChangeAnalysisPrompt } = await import('../prompts/adr-suggestion-prompts.js');
|
|
66
|
+
const analysisPrompt = generateCodeChangeAnalysisPrompt(beforeCode, afterCode, changeDescription, commitMessages);
|
|
67
|
+
const instructions = `
|
|
68
|
+
# Code Change Analysis Instructions
|
|
69
|
+
|
|
70
|
+
This analysis will identify architectural decisions reflected in code changes.
|
|
71
|
+
|
|
72
|
+
## Change Analysis
|
|
73
|
+
- **Change Description**: ${changeDescription}
|
|
74
|
+
- **Before Code Length**: ${beforeCode.length} characters
|
|
75
|
+
- **After Code Length**: ${afterCode.length} characters
|
|
76
|
+
- **Commit Messages**: ${commitMessages?.length || 0} messages
|
|
77
|
+
|
|
78
|
+
## Next Steps
|
|
79
|
+
1. **Submit the analysis prompt** to an AI agent for decision detection
|
|
80
|
+
2. **Parse the JSON response** to get identified decisions
|
|
81
|
+
3. **Review change motivations** and architectural implications
|
|
82
|
+
4. **Document significant decisions** as ADRs
|
|
83
|
+
|
|
84
|
+
## Expected AI Response Format
|
|
85
|
+
The AI will return a JSON object with:
|
|
86
|
+
- \`changeAnalysis\`: Overall analysis of the change
|
|
87
|
+
- \`identifiedDecisions\`: Specific decisions reflected in changes
|
|
88
|
+
- \`recommendations\`: Documentation recommendations
|
|
89
|
+
- \`followUpQuestions\`: Questions for the development team
|
|
90
|
+
|
|
91
|
+
## Usage Example
|
|
92
|
+
\`\`\`typescript
|
|
93
|
+
const result = await analyzeCodeChanges(before, after, description, commits);
|
|
94
|
+
// Submit result.analysisPrompt to AI agent
|
|
95
|
+
// Parse AI response for architectural decisions
|
|
96
|
+
\`\`\`
|
|
97
|
+
`;
|
|
98
|
+
return {
|
|
99
|
+
analysisPrompt,
|
|
100
|
+
instructions,
|
|
101
|
+
};
|
|
102
|
+
}
|
|
103
|
+
catch (error) {
|
|
104
|
+
throw new McpAdrError(`Failed to analyze code changes: ${error instanceof Error ? error.message : String(error)}`, 'ANALYSIS_ERROR');
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
/**
|
|
108
|
+
* Generate ADR from decision data
|
|
109
|
+
*/
|
|
110
|
+
export async function generateAdrFromDecision(decisionData, templateFormat = 'nygard', existingAdrs) {
|
|
111
|
+
try {
|
|
112
|
+
const { generateAdrTemplatePrompt } = await import('../prompts/adr-suggestion-prompts.js');
|
|
113
|
+
const generationPrompt = generateAdrTemplatePrompt(decisionData, templateFormat, existingAdrs);
|
|
114
|
+
const instructions = `
|
|
115
|
+
# ADR Generation Instructions
|
|
116
|
+
|
|
117
|
+
This will generate a complete Architectural Decision Record from the provided decision data.
|
|
118
|
+
|
|
119
|
+
## Decision Summary
|
|
120
|
+
- **Title**: ${decisionData.title}
|
|
121
|
+
- **Template Format**: ${templateFormat.toUpperCase()}
|
|
122
|
+
- **Alternatives**: ${decisionData.alternatives?.length || 0} considered
|
|
123
|
+
- **Evidence**: ${decisionData.evidence?.length || 0} pieces
|
|
124
|
+
|
|
125
|
+
## Next Steps
|
|
126
|
+
1. **Submit the generation prompt** to an AI agent for ADR creation
|
|
127
|
+
2. **Parse the JSON response** to get the complete ADR
|
|
128
|
+
3. **Review the generated content** for quality and completeness
|
|
129
|
+
4. **Save the ADR** to the appropriate location with suggested filename
|
|
130
|
+
|
|
131
|
+
## Expected AI Response Format
|
|
132
|
+
The AI will return a JSON object with:
|
|
133
|
+
- \`adr\`: Complete ADR with content, metadata, and filename
|
|
134
|
+
- \`suggestions\`: Placement, numbering, and review suggestions
|
|
135
|
+
- \`qualityChecks\`: Quality assessment and improvement suggestions
|
|
136
|
+
|
|
137
|
+
## Usage Example
|
|
138
|
+
\`\`\`typescript
|
|
139
|
+
const result = await generateAdrFromDecision(decisionData, 'nygard', existingAdrs);
|
|
140
|
+
// Submit result.generationPrompt to AI agent
|
|
141
|
+
// Parse AI response as GeneratedAdr
|
|
142
|
+
\`\`\`
|
|
143
|
+
`;
|
|
144
|
+
return {
|
|
145
|
+
generationPrompt,
|
|
146
|
+
instructions,
|
|
147
|
+
};
|
|
148
|
+
}
|
|
149
|
+
catch (error) {
|
|
150
|
+
throw new McpAdrError(`Failed to generate ADR: ${error instanceof Error ? error.message : String(error)}`, 'GENERATION_ERROR');
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
/**
|
|
154
|
+
* Extract code patterns from project structure for analysis
|
|
155
|
+
*/
|
|
156
|
+
function extractCodePatterns(projectStructure) {
|
|
157
|
+
const patterns = [];
|
|
158
|
+
try {
|
|
159
|
+
// Extract patterns from file structure
|
|
160
|
+
if (projectStructure.filesByType) {
|
|
161
|
+
Object.entries(projectStructure.filesByType).forEach(([type, files]) => {
|
|
162
|
+
if (Array.isArray(files) && files.length > 0) {
|
|
163
|
+
patterns.push(`${type} files: ${files
|
|
164
|
+
.slice(0, 5)
|
|
165
|
+
.map((f) => f.name || f)
|
|
166
|
+
.join(', ')}${files.length > 5 ? ` and ${files.length - 5} more` : ''}`);
|
|
167
|
+
}
|
|
168
|
+
});
|
|
169
|
+
}
|
|
170
|
+
// Extract patterns from directory structure
|
|
171
|
+
if (projectStructure.directories) {
|
|
172
|
+
const dirNames = projectStructure.directories.slice(0, 10).join(', ');
|
|
173
|
+
patterns.push(`Directory structure: ${dirNames}${projectStructure.directories.length > 10 ? ` and ${projectStructure.directories.length - 10} more` : ''}`);
|
|
174
|
+
}
|
|
175
|
+
// Extract patterns from detected technologies
|
|
176
|
+
if (projectStructure.detectedTechnologies) {
|
|
177
|
+
patterns.push(`Technologies: ${projectStructure.detectedTechnologies.join(', ')}`);
|
|
178
|
+
}
|
|
179
|
+
// Add basic project metrics
|
|
180
|
+
patterns.push(`Project metrics: ${projectStructure.totalFiles} files, ${projectStructure.totalDirectories} directories`);
|
|
181
|
+
return patterns;
|
|
182
|
+
}
|
|
183
|
+
catch (error) {
|
|
184
|
+
console.warn('Failed to extract code patterns:', error);
|
|
185
|
+
return ['Unable to extract code patterns from project structure'];
|
|
186
|
+
}
|
|
187
|
+
}
|
|
188
|
+
/**
|
|
189
|
+
* Generate next ADR number based on existing ADRs
|
|
190
|
+
*/
|
|
191
|
+
export function generateNextAdrNumber(existingAdrs) {
|
|
192
|
+
try {
|
|
193
|
+
// Extract numbers from existing ADR filenames/titles
|
|
194
|
+
const numbers = existingAdrs
|
|
195
|
+
.map(adr => {
|
|
196
|
+
const match = adr.match(/ADR[-_]?(\d+)/i) || adr.match(/(\d+)/);
|
|
197
|
+
return match && match[1] ? parseInt(match[1], 10) : 0;
|
|
198
|
+
})
|
|
199
|
+
.filter(num => num > 0);
|
|
200
|
+
const maxNumber = numbers.length > 0 ? Math.max(...numbers) : 0;
|
|
201
|
+
const nextNumber = maxNumber + 1;
|
|
202
|
+
return `ADR-${nextNumber.toString().padStart(4, '0')}`;
|
|
203
|
+
}
|
|
204
|
+
catch (error) {
|
|
205
|
+
console.warn('Failed to generate ADR number:', error);
|
|
206
|
+
return 'ADR-0001';
|
|
207
|
+
}
|
|
208
|
+
}
|
|
209
|
+
/**
|
|
210
|
+
* Suggest ADR filename based on title and number
|
|
211
|
+
*/
|
|
212
|
+
export function suggestAdrFilename(title, adrNumber) {
|
|
213
|
+
try {
|
|
214
|
+
const number = adrNumber || 'XXXX';
|
|
215
|
+
const cleanTitle = title
|
|
216
|
+
.toLowerCase()
|
|
217
|
+
.replace(/[^a-z0-9\s-]/g, '')
|
|
218
|
+
.replace(/\s+/g, '-')
|
|
219
|
+
.replace(/-+/g, '-')
|
|
220
|
+
.replace(/^-|-$/g, '');
|
|
221
|
+
return `${number.toLowerCase()}-${cleanTitle}.md`;
|
|
222
|
+
}
|
|
223
|
+
catch (error) {
|
|
224
|
+
console.warn('Failed to suggest filename:', error);
|
|
225
|
+
return 'adr-new-decision.md';
|
|
226
|
+
}
|
|
227
|
+
}
|
|
228
|
+
//# sourceMappingURL=adr-suggestions.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"adr-suggestions.js","sourceRoot":"","sources":["../../../src/utils/adr-suggestions.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Caching system for MCP resources and expensive operations
|
|
3
|
+
* Implements file-based caching with TTL and invalidation
|
|
4
|
+
*/
|
|
5
|
+
export interface CacheOptions {
|
|
6
|
+
ttl?: number;
|
|
7
|
+
invalidateOnChange?: boolean;
|
|
8
|
+
compression?: boolean;
|
|
9
|
+
}
|
|
10
|
+
/**
|
|
11
|
+
* Initialize cache directory
|
|
12
|
+
*/
|
|
13
|
+
export declare function initializeCache(): Promise<void>;
|
|
14
|
+
/**
|
|
15
|
+
* Store data in cache
|
|
16
|
+
*/
|
|
17
|
+
export declare function setCache<T>(key: string, data: T, options?: CacheOptions): Promise<void>;
|
|
18
|
+
/**
|
|
19
|
+
* Retrieve data from cache
|
|
20
|
+
*/
|
|
21
|
+
export declare function getCache<T>(key: string): Promise<T | null>;
|
|
22
|
+
/**
|
|
23
|
+
* Check if cache entry exists and is valid
|
|
24
|
+
*/
|
|
25
|
+
export declare function hasValidCache(key: string): Promise<boolean>;
|
|
26
|
+
/**
|
|
27
|
+
* Invalidate specific cache entry
|
|
28
|
+
*/
|
|
29
|
+
export declare function invalidateCache(key: string): Promise<void>;
|
|
30
|
+
/**
|
|
31
|
+
* Clear all cache entries
|
|
32
|
+
*/
|
|
33
|
+
export declare function clearCache(): Promise<void>;
|
|
34
|
+
/**
|
|
35
|
+
* Get cache statistics
|
|
36
|
+
*/
|
|
37
|
+
export declare function getCacheStats(): Promise<{
|
|
38
|
+
totalEntries: number;
|
|
39
|
+
totalSize: number;
|
|
40
|
+
oldestEntry: string | null;
|
|
41
|
+
newestEntry: string | null;
|
|
42
|
+
}>;
|
|
43
|
+
/**
|
|
44
|
+
* Cleanup expired cache entries
|
|
45
|
+
*/
|
|
46
|
+
export declare function cleanupCache(): Promise<number>;
|
|
47
|
+
/**
|
|
48
|
+
* Get or set cache with automatic management
|
|
49
|
+
*/
|
|
50
|
+
export declare function getCachedOrGenerate<T>(key: string, generator: () => Promise<T>, options?: CacheOptions): Promise<T>;
|
|
51
|
+
//# sourceMappingURL=cache.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cache.d.ts","sourceRoot":"","sources":["../../../src/utils/cache.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAQH,MAAM,WAAW,YAAY;IAC3B,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,kBAAkB,CAAC,EAAE,OAAO,CAAC;IAC7B,WAAW,CAAC,EAAE,OAAO,CAAC;CACvB;AAED;;GAEG;AACH,wBAAsB,eAAe,IAAI,OAAO,CAAC,IAAI,CAAC,CAsBrD;AAWD;;GAEG;AACH,wBAAsB,QAAQ,CAAC,CAAC,EAAE,GAAG,EAAE,MAAM,EAAE,IAAI,EAAE,CAAC,EAAE,OAAO,GAAE,YAAiB,GAAG,OAAO,CAAC,IAAI,CAAC,CAuBjG;AAED;;GAEG;AACH,wBAAsB,QAAQ,CAAC,CAAC,EAAE,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,CAAC,GAAG,IAAI,CAAC,CA8BhE;AAED;;GAEG;AACH,wBAAsB,aAAa,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CAOjE;AAED;;GAEG;AACH,wBAAsB,eAAe,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAOhE;AAED;;GAEG;AACH,wBAAsB,UAAU,IAAI,OAAO,CAAC,IAAI,CAAC,CAehD;AAED;;GAEG;AACH,wBAAsB,aAAa,IAAI,OAAO,CAAC;IAC7C,YAAY,EAAE,MAAM,CAAC;IACrB,SAAS,EAAE,MAAM,CAAC;IAClB,WAAW,EAAE,MAAM,GAAG,IAAI,CAAC;IAC3B,WAAW,EAAE,MAAM,GAAG,IAAI,CAAC;CAC5B,CAAC,CA6CD;AAED;;GAEG;AACH,wBAAsB,YAAY,IAAI,OAAO,CAAC,MAAM,CAAC,CAsDpD;AAED;;GAEG;AACH,wBAAsB,mBAAmB,CAAC,CAAC,EACzC,GAAG,EAAE,MAAM,EACX,SAAS,EAAE,MAAM,OAAO,CAAC,CAAC,CAAC,EAC3B,OAAO,GAAE,YAAiB,GACzB,OAAO,CAAC,CAAC,CAAC,CAqBZ"}
|
|
@@ -0,0 +1,243 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Caching system for MCP resources and expensive operations
|
|
3
|
+
* Implements file-based caching with TTL and invalidation
|
|
4
|
+
*/
|
|
5
|
+
import { promises as fs } from 'fs';
|
|
6
|
+
import { join } from 'path';
|
|
7
|
+
import { McpAdrError } from '../types/index.js';
|
|
8
|
+
const CACHE_DIR = '.mcp-adr-cache';
|
|
9
|
+
/**
|
|
10
|
+
* Initialize cache directory
|
|
11
|
+
*/
|
|
12
|
+
export async function initializeCache() {
|
|
13
|
+
try {
|
|
14
|
+
await fs.mkdir(CACHE_DIR, { recursive: true });
|
|
15
|
+
// Create cache metadata file
|
|
16
|
+
const metadataPath = join(CACHE_DIR, 'metadata.json');
|
|
17
|
+
try {
|
|
18
|
+
await fs.access(metadataPath);
|
|
19
|
+
}
|
|
20
|
+
catch {
|
|
21
|
+
const metadata = {
|
|
22
|
+
version: '1.0.0',
|
|
23
|
+
created: new Date().toISOString(),
|
|
24
|
+
lastCleanup: new Date().toISOString(),
|
|
25
|
+
};
|
|
26
|
+
await fs.writeFile(metadataPath, JSON.stringify(metadata, null, 2));
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
catch (error) {
|
|
30
|
+
throw new McpAdrError(`Failed to initialize cache: ${error instanceof Error ? error.message : String(error)}`, 'CACHE_ERROR');
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
/**
|
|
34
|
+
* Generate cache file path from key
|
|
35
|
+
*/
|
|
36
|
+
function getCacheFilePath(key) {
|
|
37
|
+
// Create safe filename from cache key
|
|
38
|
+
const safeKey = key.replace(/[^a-zA-Z0-9-_]/g, '_');
|
|
39
|
+
return join(CACHE_DIR, `${safeKey}.json`);
|
|
40
|
+
}
|
|
41
|
+
/**
|
|
42
|
+
* Store data in cache
|
|
43
|
+
*/
|
|
44
|
+
export async function setCache(key, data, options = {}) {
|
|
45
|
+
try {
|
|
46
|
+
await initializeCache();
|
|
47
|
+
const cacheEntry = {
|
|
48
|
+
key,
|
|
49
|
+
data,
|
|
50
|
+
timestamp: new Date().toISOString(),
|
|
51
|
+
ttl: options.ttl || 3600, // Default 1 hour
|
|
52
|
+
metadata: {
|
|
53
|
+
version: '1.0.0',
|
|
54
|
+
compressed: options.compression || false,
|
|
55
|
+
},
|
|
56
|
+
};
|
|
57
|
+
const filePath = getCacheFilePath(key);
|
|
58
|
+
await fs.writeFile(filePath, JSON.stringify(cacheEntry, null, 2));
|
|
59
|
+
}
|
|
60
|
+
catch (error) {
|
|
61
|
+
throw new McpAdrError(`Failed to set cache: ${error instanceof Error ? error.message : String(error)}`, 'CACHE_ERROR');
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
/**
|
|
65
|
+
* Retrieve data from cache
|
|
66
|
+
*/
|
|
67
|
+
export async function getCache(key) {
|
|
68
|
+
try {
|
|
69
|
+
const filePath = getCacheFilePath(key);
|
|
70
|
+
try {
|
|
71
|
+
const content = await fs.readFile(filePath, 'utf-8');
|
|
72
|
+
const cacheEntry = JSON.parse(content);
|
|
73
|
+
// Check if cache entry is expired
|
|
74
|
+
const now = new Date();
|
|
75
|
+
const cacheTime = new Date(cacheEntry.timestamp);
|
|
76
|
+
const ageInSeconds = (now.getTime() - cacheTime.getTime()) / 1000;
|
|
77
|
+
if (ageInSeconds > cacheEntry.ttl) {
|
|
78
|
+
// Cache expired, remove it
|
|
79
|
+
await fs.unlink(filePath);
|
|
80
|
+
return null;
|
|
81
|
+
}
|
|
82
|
+
return cacheEntry.data;
|
|
83
|
+
}
|
|
84
|
+
catch (error) {
|
|
85
|
+
// Cache file doesn't exist or is corrupted
|
|
86
|
+
return null;
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
catch (error) {
|
|
90
|
+
throw new McpAdrError(`Failed to get cache: ${error instanceof Error ? error.message : String(error)}`, 'CACHE_ERROR');
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
/**
|
|
94
|
+
* Check if cache entry exists and is valid
|
|
95
|
+
*/
|
|
96
|
+
export async function hasValidCache(key) {
|
|
97
|
+
try {
|
|
98
|
+
const data = await getCache(key);
|
|
99
|
+
return data !== null;
|
|
100
|
+
}
|
|
101
|
+
catch {
|
|
102
|
+
return false;
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
/**
|
|
106
|
+
* Invalidate specific cache entry
|
|
107
|
+
*/
|
|
108
|
+
export async function invalidateCache(key) {
|
|
109
|
+
try {
|
|
110
|
+
const filePath = getCacheFilePath(key);
|
|
111
|
+
await fs.unlink(filePath);
|
|
112
|
+
}
|
|
113
|
+
catch {
|
|
114
|
+
// File doesn't exist, which is fine
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
/**
|
|
118
|
+
* Clear all cache entries
|
|
119
|
+
*/
|
|
120
|
+
export async function clearCache() {
|
|
121
|
+
try {
|
|
122
|
+
const files = await fs.readdir(CACHE_DIR);
|
|
123
|
+
for (const file of files) {
|
|
124
|
+
if (file.endsWith('.json') && file !== 'metadata.json') {
|
|
125
|
+
await fs.unlink(join(CACHE_DIR, file));
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
catch (error) {
|
|
130
|
+
throw new McpAdrError(`Failed to clear cache: ${error instanceof Error ? error.message : String(error)}`, 'CACHE_ERROR');
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
/**
|
|
134
|
+
* Get cache statistics
|
|
135
|
+
*/
|
|
136
|
+
export async function getCacheStats() {
|
|
137
|
+
try {
|
|
138
|
+
await initializeCache();
|
|
139
|
+
const files = await fs.readdir(CACHE_DIR);
|
|
140
|
+
const cacheFiles = files.filter(f => f.endsWith('.json') && f !== 'metadata.json');
|
|
141
|
+
let totalSize = 0;
|
|
142
|
+
let oldestTime = Infinity;
|
|
143
|
+
let newestTime = 0;
|
|
144
|
+
let oldestEntry = null;
|
|
145
|
+
let newestEntry = null;
|
|
146
|
+
for (const file of cacheFiles) {
|
|
147
|
+
const filePath = join(CACHE_DIR, file);
|
|
148
|
+
const stats = await fs.stat(filePath);
|
|
149
|
+
totalSize += stats.size;
|
|
150
|
+
const content = await fs.readFile(filePath, 'utf-8');
|
|
151
|
+
const cacheEntry = JSON.parse(content);
|
|
152
|
+
const entryTime = new Date(cacheEntry.timestamp).getTime();
|
|
153
|
+
if (entryTime < oldestTime) {
|
|
154
|
+
oldestTime = entryTime;
|
|
155
|
+
oldestEntry = cacheEntry.key;
|
|
156
|
+
}
|
|
157
|
+
if (entryTime > newestTime) {
|
|
158
|
+
newestTime = entryTime;
|
|
159
|
+
newestEntry = cacheEntry.key;
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
return {
|
|
163
|
+
totalEntries: cacheFiles.length,
|
|
164
|
+
totalSize,
|
|
165
|
+
oldestEntry,
|
|
166
|
+
newestEntry,
|
|
167
|
+
};
|
|
168
|
+
}
|
|
169
|
+
catch (error) {
|
|
170
|
+
throw new McpAdrError(`Failed to get cache stats: ${error instanceof Error ? error.message : String(error)}`, 'CACHE_ERROR');
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
/**
|
|
174
|
+
* Cleanup expired cache entries
|
|
175
|
+
*/
|
|
176
|
+
export async function cleanupCache() {
|
|
177
|
+
try {
|
|
178
|
+
await initializeCache();
|
|
179
|
+
const files = await fs.readdir(CACHE_DIR);
|
|
180
|
+
const cacheFiles = files.filter(f => f.endsWith('.json') && f !== 'metadata.json');
|
|
181
|
+
let cleanedCount = 0;
|
|
182
|
+
const now = new Date();
|
|
183
|
+
for (const file of cacheFiles) {
|
|
184
|
+
const filePath = join(CACHE_DIR, file);
|
|
185
|
+
try {
|
|
186
|
+
const content = await fs.readFile(filePath, 'utf-8');
|
|
187
|
+
const cacheEntry = JSON.parse(content);
|
|
188
|
+
const cacheTime = new Date(cacheEntry.timestamp);
|
|
189
|
+
const ageInSeconds = (now.getTime() - cacheTime.getTime()) / 1000;
|
|
190
|
+
if (ageInSeconds > cacheEntry.ttl) {
|
|
191
|
+
await fs.unlink(filePath);
|
|
192
|
+
cleanedCount++;
|
|
193
|
+
}
|
|
194
|
+
}
|
|
195
|
+
catch {
|
|
196
|
+
// Corrupted cache file, remove it
|
|
197
|
+
await fs.unlink(filePath);
|
|
198
|
+
cleanedCount++;
|
|
199
|
+
}
|
|
200
|
+
}
|
|
201
|
+
// Update metadata
|
|
202
|
+
const metadataPath = join(CACHE_DIR, 'metadata.json');
|
|
203
|
+
try {
|
|
204
|
+
const metadata = JSON.parse(await fs.readFile(metadataPath, 'utf-8'));
|
|
205
|
+
metadata.lastCleanup = now.toISOString();
|
|
206
|
+
await fs.writeFile(metadataPath, JSON.stringify(metadata, null, 2));
|
|
207
|
+
}
|
|
208
|
+
catch {
|
|
209
|
+
// Metadata file corrupted, recreate it
|
|
210
|
+
const metadata = {
|
|
211
|
+
version: '1.0.0',
|
|
212
|
+
created: now.toISOString(),
|
|
213
|
+
lastCleanup: now.toISOString(),
|
|
214
|
+
};
|
|
215
|
+
await fs.writeFile(metadataPath, JSON.stringify(metadata, null, 2));
|
|
216
|
+
}
|
|
217
|
+
return cleanedCount;
|
|
218
|
+
}
|
|
219
|
+
catch (error) {
|
|
220
|
+
throw new McpAdrError(`Failed to cleanup cache: ${error instanceof Error ? error.message : String(error)}`, 'CACHE_ERROR');
|
|
221
|
+
}
|
|
222
|
+
}
|
|
223
|
+
/**
|
|
224
|
+
* Get or set cache with automatic management
|
|
225
|
+
*/
|
|
226
|
+
export async function getCachedOrGenerate(key, generator, options = {}) {
|
|
227
|
+
try {
|
|
228
|
+
// Try to get from cache first
|
|
229
|
+
const cached = await getCache(key);
|
|
230
|
+
if (cached !== null) {
|
|
231
|
+
return cached;
|
|
232
|
+
}
|
|
233
|
+
// Generate new data
|
|
234
|
+
const data = await generator();
|
|
235
|
+
// Store in cache
|
|
236
|
+
await setCache(key, data, options);
|
|
237
|
+
return data;
|
|
238
|
+
}
|
|
239
|
+
catch (error) {
|
|
240
|
+
throw new McpAdrError(`Failed to get cached or generate: ${error instanceof Error ? error.message : String(error)}`, 'CACHE_ERROR');
|
|
241
|
+
}
|
|
242
|
+
}
|
|
243
|
+
//# sourceMappingURL=cache.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cache.js","sourceRoot":"","sources":["../../../src/utils/cache.ts"],"names":[],"mappings":"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"}
|