mcp-adr-analysis-server 2.1.22 → 2.1.27

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (40) hide show
  1. package/README.md +63 -1
  2. package/dist/.tsbuildinfo +1 -1
  3. package/dist/src/index.d.ts.map +1 -1
  4. package/dist/src/index.js +370 -0
  5. package/dist/src/index.js.map +1 -1
  6. package/dist/src/tools/adr-aggregator-tools.d.ts +185 -0
  7. package/dist/src/tools/adr-aggregator-tools.d.ts.map +1 -0
  8. package/dist/src/tools/adr-aggregator-tools.js +872 -0
  9. package/dist/src/tools/adr-aggregator-tools.js.map +1 -0
  10. package/dist/src/tools/analyze-gaps-tool.d.ts +57 -0
  11. package/dist/src/tools/analyze-gaps-tool.d.ts.map +1 -0
  12. package/dist/src/tools/analyze-gaps-tool.js +727 -0
  13. package/dist/src/tools/analyze-gaps-tool.js.map +1 -0
  14. package/dist/src/tools/tool-catalog.d.ts +1 -1
  15. package/dist/src/tools/tool-catalog.d.ts.map +1 -1
  16. package/dist/src/tools/tool-catalog.js +382 -0
  17. package/dist/src/tools/tool-catalog.js.map +1 -1
  18. package/dist/src/tools/tool-dispatcher.d.ts.map +1 -1
  19. package/dist/src/tools/tool-dispatcher.js +4 -0
  20. package/dist/src/tools/tool-dispatcher.js.map +1 -1
  21. package/dist/src/types/adr-aggregator.d.ts +692 -0
  22. package/dist/src/types/adr-aggregator.d.ts.map +1 -0
  23. package/dist/src/types/adr-aggregator.js +8 -0
  24. package/dist/src/types/adr-aggregator.js.map +1 -0
  25. package/dist/src/types/index.d.ts +3 -2
  26. package/dist/src/types/index.d.ts.map +1 -1
  27. package/dist/src/types/memory-entities.d.ts +48 -48
  28. package/dist/src/utils/adr-aggregator-client.d.ts +177 -0
  29. package/dist/src/utils/adr-aggregator-client.d.ts.map +1 -0
  30. package/dist/src/utils/adr-aggregator-client.js +396 -0
  31. package/dist/src/utils/adr-aggregator-client.js.map +1 -0
  32. package/dist/src/utils/config.d.ts +3 -0
  33. package/dist/src/utils/config.d.ts.map +1 -1
  34. package/dist/src/utils/config.js +13 -0
  35. package/dist/src/utils/config.js.map +1 -1
  36. package/dist/src/utils/git-remote-detector.d.ts +67 -0
  37. package/dist/src/utils/git-remote-detector.d.ts.map +1 -0
  38. package/dist/src/utils/git-remote-detector.js +194 -0
  39. package/dist/src/utils/git-remote-detector.js.map +1 -0
  40. package/package.json +1 -1
@@ -0,0 +1,872 @@
1
+ /**
2
+ * ADR Aggregator Integration Tools
3
+ * MCP tools for bidirectional sync with https://adraggregator.com
4
+ *
5
+ * @see NEW_FEATURE.md for API documentation
6
+ */
7
+ import { McpAdrError } from '../types/index.js';
8
+ import { getAdrAggregatorClient, } from '../utils/adr-aggregator-client.js';
9
+ import { loadConfig } from '../utils/config.js';
10
+ import { isGitRepository } from '../utils/git-remote-detector.js';
11
+ import { promises as fs } from 'fs';
12
+ import path from 'path';
13
+ // ============================================================================
14
+ // Helper Functions
15
+ // ============================================================================
16
+ /**
17
+ * Discover existing ADRs in the project
18
+ */
19
+ async function discoverAdrs(projectPath, adrDirectory) {
20
+ const adrPath = path.resolve(projectPath, adrDirectory);
21
+ const adrFiles = [];
22
+ try {
23
+ const files = await fs.readdir(adrPath);
24
+ for (const file of files) {
25
+ if (file.endsWith('.md')) {
26
+ adrFiles.push(path.join(adrPath, file));
27
+ }
28
+ }
29
+ }
30
+ catch {
31
+ // Directory doesn't exist or not readable
32
+ }
33
+ return adrFiles;
34
+ }
35
+ /**
36
+ * Parse ADR content to extract metadata
37
+ */
38
+ function parseAdrContent(content, filePath) {
39
+ const lines = content.split('\n');
40
+ let title = '';
41
+ let status = 'proposed';
42
+ for (const line of lines) {
43
+ // Extract title from first H1
44
+ if (line.startsWith('# ') && !title) {
45
+ title = line.slice(2).trim();
46
+ }
47
+ // Extract status
48
+ const statusMatch = line.match(/^\*?\*?Status\*?\*?:\s*(.+)/i);
49
+ if (statusMatch && statusMatch[1]) {
50
+ const statusValue = statusMatch[1].toLowerCase().trim();
51
+ if (statusValue.includes('accepted'))
52
+ status = 'accepted';
53
+ else if (statusValue.includes('deprecated'))
54
+ status = 'deprecated';
55
+ else if (statusValue.includes('superseded'))
56
+ status = 'superseded';
57
+ else if (statusValue.includes('proposed'))
58
+ status = 'proposed';
59
+ }
60
+ }
61
+ return {
62
+ title: title || path.basename(filePath, '.md'),
63
+ status,
64
+ filePath,
65
+ };
66
+ }
67
+ /**
68
+ * Build ADR payloads for sync
69
+ */
70
+ async function buildAdrPayloads(adrPaths, projectPath, includeMetadata) {
71
+ const payloads = [];
72
+ for (const adrPath of adrPaths) {
73
+ try {
74
+ const content = await fs.readFile(adrPath, 'utf-8');
75
+ const relativePath = path.relative(projectPath, adrPath);
76
+ const parsed = parseAdrContent(content, adrPath);
77
+ const payload = {
78
+ path: relativePath,
79
+ title: parsed.title || path.basename(adrPath, '.md'),
80
+ status: parsed.status || 'proposed',
81
+ content,
82
+ };
83
+ if (includeMetadata) {
84
+ payload.analysis_metadata = {
85
+ last_analyzed: new Date().toISOString(),
86
+ };
87
+ }
88
+ payloads.push(payload);
89
+ }
90
+ catch (error) {
91
+ // Skip files that can't be read
92
+ console.error(`Failed to read ADR: ${adrPath}`, error);
93
+ }
94
+ }
95
+ return payloads;
96
+ }
97
+ /**
98
+ * Ensure client is configured
99
+ */
100
+ function ensureConfigured(client) {
101
+ if (!client.isConfigured()) {
102
+ throw new McpAdrError('ADR Aggregator API key not configured. Set ADR_AGGREGATOR_API_KEY environment variable.', 'NOT_CONFIGURED');
103
+ }
104
+ }
105
+ /**
106
+ * Ensure git repository
107
+ */
108
+ function ensureGitRepo(projectPath) {
109
+ if (!isGitRepository(projectPath)) {
110
+ throw new McpAdrError('Not a git repository. ADR Aggregator requires a git repository to auto-detect the repository name.', 'NOT_GIT_REPO');
111
+ }
112
+ }
113
+ // ============================================================================
114
+ // Tool Implementations
115
+ // ============================================================================
116
+ /**
117
+ * Sync ADRs to ADR Aggregator platform
118
+ *
119
+ * POST /functions/v1/mcp-sync-adr
120
+ */
121
+ export async function syncToAggregator(args, context) {
122
+ const { full_sync = false, include_metadata = true, adr_paths, projectPath } = args;
123
+ const client = getAdrAggregatorClient();
124
+ ensureConfigured(client);
125
+ const config = loadConfig();
126
+ const resolvedProjectPath = projectPath || config.projectPath;
127
+ ensureGitRepo(resolvedProjectPath);
128
+ try {
129
+ context?.info('Starting ADR sync to aggregator...');
130
+ context?.report_progress(10, 100);
131
+ // Auto-detect repository name
132
+ const repositoryName = client.getRepositoryName(resolvedProjectPath);
133
+ context?.info(`Repository: ${repositoryName}`);
134
+ // Discover ADRs
135
+ context?.report_progress(20, 100);
136
+ let adrFilePaths;
137
+ if (adr_paths && adr_paths.length > 0) {
138
+ // Use specified paths
139
+ adrFilePaths = adr_paths.map(p => path.resolve(resolvedProjectPath, p));
140
+ }
141
+ else {
142
+ // Discover all ADRs
143
+ adrFilePaths = await discoverAdrs(resolvedProjectPath, config.adrDirectory);
144
+ }
145
+ context?.info(`Found ${adrFilePaths.length} ADRs to sync`);
146
+ context?.report_progress(40, 100);
147
+ if (adrFilePaths.length === 0) {
148
+ return {
149
+ content: [
150
+ {
151
+ type: 'text',
152
+ text: `# ADR Aggregator Sync
153
+
154
+ No ADRs found in ${config.adrDirectory}. Create ADRs first using \`suggest_adrs\` or \`generate_adr_from_decision\` tools.`,
155
+ },
156
+ ],
157
+ };
158
+ }
159
+ // Build payloads
160
+ const adrs = await buildAdrPayloads(adrFilePaths, resolvedProjectPath, include_metadata);
161
+ context?.report_progress(60, 100);
162
+ // Send to aggregator
163
+ const request = {
164
+ repository_name: repositoryName,
165
+ adrs,
166
+ full_sync,
167
+ include_metadata,
168
+ };
169
+ const response = await client.syncAdrs(request);
170
+ context?.report_progress(100, 100);
171
+ context?.info(`Synced ${response.synced_count} ADRs successfully`);
172
+ return {
173
+ content: [
174
+ {
175
+ type: 'text',
176
+ text: `# ADR Aggregator Sync Complete
177
+
178
+ ## Summary
179
+ - **Repository:** ${response.repository}
180
+ - **ADRs Synced:** ${response.synced_count}
181
+ - **Sync ID:** ${response.sync_id}
182
+ - **Timestamp:** ${response.timestamp}
183
+ ${response.tier ? `- **Tier:** ${response.tier}` : ''}
184
+ ${response.truncated ? `\n**Warning:** Some ADRs were truncated due to tier limits. Upgrade at /pricing to sync more.` : ''}
185
+
186
+ ${response.errors && response.errors.length > 0
187
+ ? `## Errors
188
+ ${response.errors.map(e => `- ${e.code}: ${e.message}`).join('\n')}`
189
+ : ''}
190
+
191
+ ## Synced ADRs
192
+ ${adrs.map(adr => `- ${adr.path} (${adr.status})`).join('\n')}
193
+
194
+ ## Options
195
+ - Full Sync: ${full_sync}
196
+ - Include Metadata: ${include_metadata}
197
+
198
+ View in dashboard: ${client.getBaseUrl()}/mcp-dashboard`,
199
+ },
200
+ ],
201
+ };
202
+ }
203
+ catch (error) {
204
+ const errorMessage = error instanceof McpAdrError ? error.message : String(error);
205
+ return {
206
+ content: [
207
+ {
208
+ type: 'text',
209
+ text: `# ADR Sync Failed
210
+
211
+ **Error:** ${errorMessage}
212
+
213
+ Please check:
214
+ 1. ADR_AGGREGATOR_API_KEY is set correctly
215
+ 2. You have an active internet connection
216
+ 3. The ADR Aggregator service is available`,
217
+ },
218
+ ],
219
+ isError: true,
220
+ };
221
+ }
222
+ }
223
+ /**
224
+ * Get ADR context from aggregator
225
+ *
226
+ * GET /functions/v1/mcp-get-context
227
+ */
228
+ export async function getAdrContext(args, context) {
229
+ const client = getAdrAggregatorClient();
230
+ ensureConfigured(client);
231
+ const config = loadConfig();
232
+ const resolvedProjectPath = args.projectPath || config.projectPath;
233
+ ensureGitRepo(resolvedProjectPath);
234
+ try {
235
+ const repositoryName = client.getRepositoryName(resolvedProjectPath);
236
+ context?.info(`Fetching ADR context for ${repositoryName}...`);
237
+ context?.report_progress(30, 100);
238
+ const request = {
239
+ repository_name: repositoryName,
240
+ include_timeline: args.include_timeline ?? true,
241
+ ...(args.include_diagrams !== undefined && { include_diagrams: args.include_diagrams }),
242
+ ...(args.include_code_links !== undefined && { include_code_links: args.include_code_links }),
243
+ ...(args.include_research !== undefined && { include_research: args.include_research }),
244
+ ...(args.staleness_filter !== undefined && { staleness_filter: args.staleness_filter }),
245
+ ...(args.graph_depth !== undefined && { graph_depth: args.graph_depth }),
246
+ };
247
+ const response = await client.getContext(request);
248
+ context?.report_progress(100, 100);
249
+ return {
250
+ content: [
251
+ {
252
+ type: 'text',
253
+ text: `# ADR Context for ${response.repository}
254
+
255
+ ## Summary
256
+ - **Total ADRs:** ${response.summary.total_adrs}
257
+ - **By Status:** ${JSON.stringify(response.summary.by_status)}
258
+ - **Average Staleness:** ${response.summary.average_staleness.toFixed(2)}
259
+
260
+ ## ADRs
261
+ ${response.adrs
262
+ .map(adr => `
263
+ ### ${adr.title}
264
+ - **Path:** ${adr.path}
265
+ - **Status:** ${adr.status}
266
+ ${adr.timeline ? `- **Staleness:** ${adr.timeline.staleness} (${adr.timeline.days_since_modified} days)` : ''}
267
+ ${adr.summary ? `- **Summary:** ${adr.summary}` : ''}
268
+ `)
269
+ .join('\n')}
270
+ `,
271
+ },
272
+ ],
273
+ };
274
+ }
275
+ catch (error) {
276
+ const errorMessage = error instanceof McpAdrError ? error.message : String(error);
277
+ return {
278
+ content: [
279
+ { type: 'text', text: `# Failed to Get ADR Context\n\n**Error:** ${errorMessage}` },
280
+ ],
281
+ isError: true,
282
+ };
283
+ }
284
+ }
285
+ /**
286
+ * Get staleness report from aggregator
287
+ *
288
+ * GET /functions/v1/mcp-staleness-report
289
+ */
290
+ export async function getStalenessReport(args, context) {
291
+ const client = getAdrAggregatorClient();
292
+ ensureConfigured(client);
293
+ const config = loadConfig();
294
+ const resolvedProjectPath = args.projectPath || config.projectPath;
295
+ ensureGitRepo(resolvedProjectPath);
296
+ try {
297
+ const repositoryName = client.getRepositoryName(resolvedProjectPath);
298
+ context?.info(`Fetching staleness report for ${repositoryName}...`);
299
+ context?.report_progress(30, 100);
300
+ const request = {
301
+ repository_name: repositoryName,
302
+ threshold: args.threshold ?? 90,
303
+ };
304
+ const response = await client.getStalenessReport(request);
305
+ context?.report_progress(100, 100);
306
+ return {
307
+ content: [
308
+ {
309
+ type: 'text',
310
+ text: `# ADR Staleness Report
311
+
312
+ ## Repository: ${response.repository}
313
+ **Report Date:** ${response.report_date}
314
+
315
+ ## Summary
316
+ | Status | Count |
317
+ |--------|-------|
318
+ | Fresh | ${response.summary.fresh} |
319
+ | Recent | ${response.summary.recent} |
320
+ | Stale | ${response.summary.stale} |
321
+ | Very Stale | ${response.summary.very_stale} |
322
+ | **Total** | **${response.summary.total_adrs}** |
323
+
324
+ ## Governance
325
+ - **Review Cycle Compliance:** ${(response.governance.review_cycle_compliance * 100).toFixed(1)}%
326
+ - **Overdue Reviews:** ${response.governance.overdue_reviews}
327
+
328
+ ${response.stale_adrs.length > 0
329
+ ? `## Stale ADRs Requiring Attention
330
+ ${response.stale_adrs
331
+ .map(adr => `
332
+ ### ${adr.title}
333
+ - **Path:** ${adr.path}
334
+ - **Days Since Modified:** ${adr.days_since_modified}
335
+ - **Staleness Level:** ${adr.staleness}
336
+ - **Recommended Action:** ${adr.recommended_action}
337
+ `)
338
+ .join('\n')}`
339
+ : '## All ADRs are Fresh! ✓'}
340
+ `,
341
+ },
342
+ ],
343
+ };
344
+ }
345
+ catch (error) {
346
+ const errorMessage = error instanceof McpAdrError ? error.message : String(error);
347
+ return {
348
+ content: [
349
+ { type: 'text', text: `# Failed to Get Staleness Report\n\n**Error:** ${errorMessage}` },
350
+ ],
351
+ isError: true,
352
+ };
353
+ }
354
+ }
355
+ /**
356
+ * Get ADR templates from aggregator
357
+ *
358
+ * GET /functions/v1/mcp-get-templates
359
+ */
360
+ export async function getAdrTemplates(args, context) {
361
+ const client = getAdrAggregatorClient();
362
+ // Templates don't require authentication
363
+ // ensureConfigured(client);
364
+ try {
365
+ context?.info(`Fetching ADR templates${args.domain ? ` for domain: ${args.domain}` : ''}...`);
366
+ context?.report_progress(30, 100);
367
+ const request = {
368
+ ...(args.domain !== undefined && { domain: args.domain }),
369
+ };
370
+ const response = await client.getTemplates(request);
371
+ context?.report_progress(100, 100);
372
+ const templateSections = Object.entries(response.templates)
373
+ .map(([domain, template]) => `
374
+ ## ${domain.replace(/_/g, ' ').toUpperCase()}
375
+
376
+ ### Best Practices
377
+ ${template.best_practices
378
+ .map(bp => `
379
+ #### ${bp.name}
380
+ - **ID:** ${bp.id}
381
+ - **Description:** ${bp.description}
382
+
383
+ <details>
384
+ <summary>ADR Template</summary>
385
+
386
+ \`\`\`markdown
387
+ ${bp.adr_template}
388
+ \`\`\`
389
+
390
+ </details>
391
+ `)
392
+ .join('\n')}
393
+
394
+ ### Anti-Patterns to Avoid
395
+ ${template.anti_patterns
396
+ .map(ap => `
397
+ #### ${ap.name}
398
+ - **ID:** ${ap.id}
399
+ - **Description:** ${ap.description}
400
+ - **Detection Hints:** ${ap.detection_hints.join(', ')}
401
+ - **Recommendation:** ${ap.recommendation}
402
+ `)
403
+ .join('\n')}
404
+ `)
405
+ .join('\n---\n');
406
+ return {
407
+ content: [
408
+ {
409
+ type: 'text',
410
+ text: `# ADR Templates from ADR Aggregator
411
+
412
+ ${templateSections}
413
+ `,
414
+ },
415
+ ],
416
+ };
417
+ }
418
+ catch (error) {
419
+ const errorMessage = error instanceof McpAdrError ? error.message : String(error);
420
+ return {
421
+ content: [{ type: 'text', text: `# Failed to Get Templates\n\n**Error:** ${errorMessage}` }],
422
+ isError: true,
423
+ };
424
+ }
425
+ }
426
+ /**
427
+ * Get Mermaid diagrams from aggregator (Pro+ tier)
428
+ *
429
+ * GET /functions/v1/mcp-get-diagrams
430
+ */
431
+ export async function getAdrDiagrams(args, context) {
432
+ const client = getAdrAggregatorClient();
433
+ ensureConfigured(client);
434
+ const config = loadConfig();
435
+ const resolvedProjectPath = args.projectPath || config.projectPath;
436
+ ensureGitRepo(resolvedProjectPath);
437
+ try {
438
+ const repositoryName = client.getRepositoryName(resolvedProjectPath);
439
+ context?.info(`Fetching Mermaid diagrams for ${repositoryName}...`);
440
+ context?.report_progress(30, 100);
441
+ const request = {
442
+ repository_name: repositoryName,
443
+ ...(args.adr_path !== undefined && { adr_path: args.adr_path }),
444
+ };
445
+ const response = await client.getDiagrams(request);
446
+ context?.report_progress(100, 100);
447
+ return {
448
+ content: [
449
+ {
450
+ type: 'text',
451
+ text: `# ADR Diagrams for ${response.repository}
452
+
453
+ ${response.diagrams
454
+ .map(diagram => `
455
+ ## ${diagram.adr_path}
456
+ **Generated:** ${diagram.generated_at}
457
+
458
+ ${diagram.workflow_diagram
459
+ ? `### Workflow Diagram
460
+ \`\`\`mermaid
461
+ ${diagram.workflow_diagram}
462
+ \`\`\`
463
+ `
464
+ : ''}
465
+
466
+ ${diagram.relationship_diagram
467
+ ? `### Relationship Diagram
468
+ \`\`\`mermaid
469
+ ${diagram.relationship_diagram}
470
+ \`\`\`
471
+ `
472
+ : ''}
473
+
474
+ ${diagram.impact_diagram
475
+ ? `### Impact Flow Diagram
476
+ \`\`\`mermaid
477
+ ${diagram.impact_diagram}
478
+ \`\`\`
479
+ `
480
+ : ''}
481
+ `)
482
+ .join('\n---\n')}
483
+ `,
484
+ },
485
+ ],
486
+ };
487
+ }
488
+ catch (error) {
489
+ const errorMessage = error instanceof McpAdrError ? error.message : String(error);
490
+ const tierRequired = error instanceof McpAdrError && error.details?.['tier_required'];
491
+ return {
492
+ content: [
493
+ {
494
+ type: 'text',
495
+ text: `# Failed to Get Diagrams
496
+
497
+ **Error:** ${errorMessage}
498
+ ${tierRequired ? `\n**Note:** This feature requires ${tierRequired} tier. Upgrade at /pricing` : ''}`,
499
+ },
500
+ ],
501
+ isError: true,
502
+ };
503
+ }
504
+ }
505
+ /**
506
+ * Validate ADR compliance via aggregator (Pro+ tier)
507
+ *
508
+ * POST /functions/v1/mcp-validate-compliance
509
+ */
510
+ export async function validateAdrCompliance(args, context) {
511
+ const client = getAdrAggregatorClient();
512
+ ensureConfigured(client);
513
+ const config = loadConfig();
514
+ const resolvedProjectPath = args.projectPath || config.projectPath;
515
+ ensureGitRepo(resolvedProjectPath);
516
+ try {
517
+ const repositoryName = client.getRepositoryName(resolvedProjectPath);
518
+ context?.info(`Validating ADR compliance for ${repositoryName}...`);
519
+ context?.report_progress(30, 100);
520
+ const request = {
521
+ repository_name: repositoryName,
522
+ validation_type: args.validation_type ?? 'all',
523
+ ...(args.adr_paths !== undefined && { adr_paths: args.adr_paths }),
524
+ };
525
+ const response = await client.validateCompliance(request);
526
+ context?.report_progress(100, 100);
527
+ return {
528
+ content: [
529
+ {
530
+ type: 'text',
531
+ text: `# ADR Compliance Validation Results
532
+
533
+ ## Repository: ${response.repository}
534
+
535
+ ${response.validation_results
536
+ .map(result => `
537
+ ## ${result.adr_path}
538
+
539
+ | Metric | Value |
540
+ |--------|-------|
541
+ | Compliance Score | **${result.compliance_score}%** |
542
+ | Status | ${result.status === 'compliant' ? '✅' : result.status === 'partial' ? '⚠️' : '❌'} ${result.status} |
543
+ | Files Validated | ${result.linked_files_validated} |
544
+
545
+ ### Findings
546
+ ${result.findings.map(f => `- ${f.type === 'success' ? '✅' : f.type === 'warning' ? '⚠️' : '❌'} ${f.description}`).join('\n')}
547
+
548
+ ### Recommendations
549
+ ${result.recommendations.map(r => `- ${r}`).join('\n')}
550
+ `)
551
+ .join('\n---\n')}
552
+ `,
553
+ },
554
+ ],
555
+ };
556
+ }
557
+ catch (error) {
558
+ const errorMessage = error instanceof McpAdrError ? error.message : String(error);
559
+ const tierRequired = error instanceof McpAdrError && error.details?.['tier_required'];
560
+ return {
561
+ content: [
562
+ {
563
+ type: 'text',
564
+ text: `# Failed to Validate Compliance
565
+
566
+ **Error:** ${errorMessage}
567
+ ${tierRequired ? `\n**Note:** This feature requires ${tierRequired} tier. Upgrade at /pricing` : ''}`,
568
+ },
569
+ ],
570
+ isError: true,
571
+ };
572
+ }
573
+ }
574
+ /**
575
+ * Get knowledge graph from aggregator (Team tier)
576
+ *
577
+ * GET /functions/v1/mcp-get-knowledge-graph
578
+ */
579
+ export async function getKnowledgeGraph(args, context) {
580
+ const client = getAdrAggregatorClient();
581
+ ensureConfigured(client);
582
+ try {
583
+ const request = {
584
+ scope: args.scope ?? 'repository',
585
+ include_analytics: args.include_analytics ?? true,
586
+ };
587
+ // Only need repository name for repository scope
588
+ if (args.scope !== 'organization') {
589
+ const config = loadConfig();
590
+ const resolvedProjectPath = args.projectPath || config.projectPath;
591
+ ensureGitRepo(resolvedProjectPath);
592
+ request.repository_name = client.getRepositoryName(resolvedProjectPath);
593
+ }
594
+ context?.info(`Fetching knowledge graph (scope: ${request.scope})...`);
595
+ context?.report_progress(30, 100);
596
+ const response = await client.getKnowledgeGraph(request);
597
+ context?.report_progress(100, 100);
598
+ return {
599
+ content: [
600
+ {
601
+ type: 'text',
602
+ text: `# Knowledge Graph
603
+
604
+ ${response.organization_id ? `**Organization:** ${response.organization_id}` : ''}
605
+ ${response.repository ? `**Repository:** ${response.repository}` : ''}
606
+ ${response.total_repositories ? `**Total Repositories:** ${response.total_repositories}` : ''}
607
+
608
+ ## Graph Statistics
609
+ - **Nodes:** ${response.graph.nodes.length}
610
+ - **Relationships:** ${response.graph.relationships.length}
611
+
612
+ ${response.graph.cross_repo_patterns && response.graph.cross_repo_patterns.length > 0
613
+ ? `## Cross-Repository Patterns
614
+ ${response.graph.cross_repo_patterns
615
+ .map(p => `
616
+ ### ${p.pattern}
617
+ - **Repositories:** ${p.repositories.join(', ')}
618
+ - **ADR Count:** ${p.adr_count}
619
+ `)
620
+ .join('\n')}`
621
+ : ''}
622
+
623
+ ${response.insights
624
+ ? `## Insights
625
+
626
+ ### Most Connected ADRs
627
+ ${response.insights.most_connected_adrs.map(a => `- ${a}`).join('\n')}
628
+
629
+ ### Orphan Decisions (No Links)
630
+ ${response.insights.orphan_decisions.length > 0 ? response.insights.orphan_decisions.map(d => `- ${d}`).join('\n') : '- None detected'}
631
+
632
+ ### Pattern Trends
633
+ ${response.insights.pattern_trends.map(t => `- ${t.pattern}: ${t.trend} (${t.count})`).join('\n')}`
634
+ : ''}
635
+ `,
636
+ },
637
+ ],
638
+ };
639
+ }
640
+ catch (error) {
641
+ const errorMessage = error instanceof McpAdrError ? error.message : String(error);
642
+ const tierRequired = error instanceof McpAdrError && error.details?.['tier_required'];
643
+ return {
644
+ content: [
645
+ {
646
+ type: 'text',
647
+ text: `# Failed to Get Knowledge Graph
648
+
649
+ **Error:** ${errorMessage}
650
+ ${tierRequired ? `\n**Note:** This feature requires ${tierRequired} tier. Upgrade at /pricing` : ''}`,
651
+ },
652
+ ],
653
+ isError: true,
654
+ };
655
+ }
656
+ }
657
+ /**
658
+ * Update implementation status of synced ADRs (Pro+ tier)
659
+ *
660
+ * POST /functions/v1/mcp-update-implementation-status
661
+ */
662
+ export async function updateAdrImplementationStatus(args, context) {
663
+ const client = getAdrAggregatorClient();
664
+ ensureConfigured(client);
665
+ const config = loadConfig();
666
+ const resolvedProjectPath = args.projectPath || config.projectPath;
667
+ ensureGitRepo(resolvedProjectPath);
668
+ try {
669
+ const repositoryName = client.getRepositoryName(resolvedProjectPath);
670
+ context?.info(`Updating implementation status for ${repositoryName}...`);
671
+ context?.report_progress(30, 100);
672
+ // Validate updates array
673
+ if (!args.updates || args.updates.length === 0) {
674
+ return {
675
+ content: [
676
+ {
677
+ type: 'text',
678
+ text: `# Update Implementation Status
679
+
680
+ **Error:** No updates provided. Please specify at least one ADR path and status to update.
681
+
682
+ ## Example Usage
683
+ \`\`\`json
684
+ {
685
+ "updates": [
686
+ {
687
+ "adr_path": "docs/adrs/001-use-typescript.md",
688
+ "implementation_status": "implemented",
689
+ "notes": "Completed migration"
690
+ }
691
+ ]
692
+ }
693
+ \`\`\`
694
+
695
+ **Valid Status Values:**
696
+ - \`not_started\` - Implementation has not begun
697
+ - \`in_progress\` - Implementation is underway
698
+ - \`implemented\` - Decision has been fully implemented
699
+ - \`deprecated\` - Decision is no longer relevant
700
+ - \`blocked\` - Implementation is blocked`,
701
+ },
702
+ ],
703
+ isError: true,
704
+ };
705
+ }
706
+ const request = {
707
+ repository_name: repositoryName,
708
+ updates: args.updates,
709
+ };
710
+ const response = await client.updateImplementationStatus(request);
711
+ context?.report_progress(100, 100);
712
+ context?.info(`Updated ${response.updated_count} ADR status(es) successfully`);
713
+ return {
714
+ content: [
715
+ {
716
+ type: 'text',
717
+ text: `# ADR Implementation Status Updated
718
+
719
+ ## Summary
720
+ - **Repository:** ${response.repository}
721
+ - **Updates Applied:** ${response.updated_count}
722
+ - **Timestamp:** ${response.timestamp}
723
+ ${response.tier ? `- **Tier:** ${response.tier}` : ''}
724
+
725
+ ## Updated ADRs
726
+ ${args.updates.map(u => `- **${u.adr_path}**: ${u.implementation_status}${u.notes ? ` (${u.notes})` : ''}`).join('\n')}
727
+
728
+ ${response.errors && response.errors.length > 0
729
+ ? `## Errors
730
+ ${response.errors.map(e => `- ${e.code}: ${e.message}`).join('\n')}`
731
+ : ''}
732
+
733
+ View in dashboard: ${client.getBaseUrl()}/mcp-dashboard`,
734
+ },
735
+ ],
736
+ };
737
+ }
738
+ catch (error) {
739
+ const errorMessage = error instanceof McpAdrError ? error.message : String(error);
740
+ const tierRequired = error instanceof McpAdrError && error.details?.['tier_required'];
741
+ return {
742
+ content: [
743
+ {
744
+ type: 'text',
745
+ text: `# Failed to Update Implementation Status
746
+
747
+ **Error:** ${errorMessage}
748
+ ${tierRequired ? `\n**Note:** This feature requires ${tierRequired} tier. Upgrade at /pricing` : ''}
749
+
750
+ ## Troubleshooting
751
+ 1. Ensure ADR_AGGREGATOR_API_KEY is set correctly
752
+ 2. Verify you have Pro+ tier subscription
753
+ 3. Check that the ADR paths are valid and synced`,
754
+ },
755
+ ],
756
+ isError: true,
757
+ };
758
+ }
759
+ }
760
+ /**
761
+ * Get ADR priorities for roadmap/backlog planning
762
+ *
763
+ * GET /functions/v1/mcp-get-priorities
764
+ */
765
+ export async function getAdrPriorities(args, context) {
766
+ const client = getAdrAggregatorClient();
767
+ ensureConfigured(client);
768
+ const config = loadConfig();
769
+ const resolvedProjectPath = args.projectPath || config.projectPath;
770
+ ensureGitRepo(resolvedProjectPath);
771
+ try {
772
+ const repositoryName = client.getRepositoryName(resolvedProjectPath);
773
+ context?.info(`Fetching ADR priorities for ${repositoryName}...`);
774
+ context?.report_progress(30, 100);
775
+ const request = {
776
+ repository_name: repositoryName,
777
+ ...(args.include_ai !== undefined && { include_ai: args.include_ai }),
778
+ };
779
+ const response = await client.getPriorities(request);
780
+ context?.report_progress(100, 100);
781
+ // Sort priorities by score (highest first)
782
+ const sortedPriorities = [...response.priorities].sort((a, b) => b.priority_score - a.priority_score);
783
+ return {
784
+ content: [
785
+ {
786
+ type: 'text',
787
+ text: `# ADR Priorities for ${response.repository}
788
+
789
+ ## Summary
790
+ - **Total ADRs:** ${response.summary.total_adrs}
791
+ - **Implemented:** ${response.summary.implemented}
792
+ - **In Progress:** ${response.summary.in_progress}
793
+ - **Not Started:** ${response.summary.not_started}
794
+ - **Blocked:** ${response.summary.blocked}
795
+ - **Total Gaps:** ${response.summary.total_gaps}
796
+ ${response.tier ? `- **Tier:** ${response.tier}` : ''}
797
+
798
+ ---
799
+
800
+ ## Prioritized Roadmap
801
+
802
+ ${sortedPriorities.length > 0
803
+ ? sortedPriorities
804
+ .map((p, index) => `
805
+ ### ${index + 1}. ${p.title}
806
+ - **Path:** ${p.adr_path}
807
+ - **Priority Score:** ${p.priority_score}/100 ${p.ai_prioritized ? '(AI)' : ''}
808
+ - **Status:** ${p.implementation_status === 'implemented' ? '✅' : p.implementation_status === 'in_progress' ? '🔄' : p.implementation_status === 'blocked' ? '🚫' : '⏳'} ${p.implementation_status}
809
+ - **Dependencies:** ${p.dependencies.length > 0 ? p.dependencies.join(', ') : 'None'}
810
+ - **Blockers:** ${p.blockers.length > 0 ? p.blockers.join(', ') : 'None'}
811
+ - **Gap Count:** ${p.gap_count}
812
+ `)
813
+ .join('\n')
814
+ : '*No ADRs found in this repository*'}
815
+
816
+ ---
817
+
818
+ ## Recommendations
819
+
820
+ ${sortedPriorities.length === 0
821
+ ? 'Sync ADRs to the aggregator first using `sync_to_aggregator` to get priority analysis.'
822
+ : `
823
+ ### High Priority Items
824
+ ${sortedPriorities
825
+ .filter(p => p.priority_score >= 70 && p.implementation_status !== 'implemented')
826
+ .map(p => `- **${p.title}** (Score: ${p.priority_score}) - ${p.blockers.length > 0 ? 'Blocked by: ' + p.blockers.join(', ') : 'Ready to implement'}`)
827
+ .join('\n') || '- No high-priority items pending'}
828
+
829
+ ### Blocked Items
830
+ ${sortedPriorities
831
+ .filter(p => p.implementation_status === 'blocked' || p.blockers.length > 0)
832
+ .map(p => `- **${p.title}** blocked by: ${p.blockers.join(', ')}`)
833
+ .join('\n') || '- No blocked items'}
834
+
835
+ ### Items with Gaps
836
+ ${sortedPriorities
837
+ .filter(p => p.gap_count > 0)
838
+ .map(p => `- **${p.title}** has ${p.gap_count} gap(s) to address`)
839
+ .join('\n') || '- No items with gaps'}
840
+ `}
841
+
842
+ ---
843
+
844
+ *Priority analysis performed at ${new Date().toISOString()}*
845
+ View in dashboard: ${client.getBaseUrl()}/mcp-dashboard`,
846
+ },
847
+ ],
848
+ };
849
+ }
850
+ catch (error) {
851
+ const errorMessage = error instanceof McpAdrError ? error.message : String(error);
852
+ const tierRequired = error instanceof McpAdrError && error.details?.['tier_required'];
853
+ return {
854
+ content: [
855
+ {
856
+ type: 'text',
857
+ text: `# Failed to Get ADR Priorities
858
+
859
+ **Error:** ${errorMessage}
860
+ ${tierRequired ? `\n**Note:** This feature requires ${tierRequired} tier. Upgrade at /pricing` : ''}
861
+
862
+ ## Troubleshooting
863
+ 1. Ensure ADR_AGGREGATOR_API_KEY is set correctly
864
+ 2. Verify you have an active internet connection
865
+ 3. Check that ADRs have been synced to the aggregator`,
866
+ },
867
+ ],
868
+ isError: true,
869
+ };
870
+ }
871
+ }
872
+ //# sourceMappingURL=adr-aggregator-tools.js.map