driftdetect-mcp 0.4.0 → 0.4.2
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/bin/server.d.ts +12 -2
- package/dist/bin/server.d.ts.map +1 -1
- package/dist/bin/server.js +25 -5
- package/dist/bin/server.js.map +1 -1
- package/dist/enterprise-server.d.ts +78 -0
- package/dist/enterprise-server.d.ts.map +1 -0
- package/dist/enterprise-server.js +201 -0
- package/dist/enterprise-server.js.map +1 -0
- package/dist/index.d.ts +15 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +17 -1
- package/dist/index.js.map +1 -1
- package/dist/infrastructure/cache.d.ts +86 -0
- package/dist/infrastructure/cache.d.ts.map +1 -0
- package/dist/infrastructure/cache.js +271 -0
- package/dist/infrastructure/cache.js.map +1 -0
- package/dist/infrastructure/cursor-manager.d.ts +86 -0
- package/dist/infrastructure/cursor-manager.d.ts.map +1 -0
- package/dist/infrastructure/cursor-manager.js +175 -0
- package/dist/infrastructure/cursor-manager.js.map +1 -0
- package/dist/infrastructure/error-handler.d.ts +82 -0
- package/dist/infrastructure/error-handler.d.ts.map +1 -0
- package/dist/infrastructure/error-handler.js +226 -0
- package/dist/infrastructure/error-handler.js.map +1 -0
- package/dist/infrastructure/index.d.ts +19 -0
- package/dist/infrastructure/index.d.ts.map +1 -0
- package/dist/infrastructure/index.js +26 -0
- package/dist/infrastructure/index.js.map +1 -0
- package/dist/infrastructure/metrics.d.ts +104 -0
- package/dist/infrastructure/metrics.d.ts.map +1 -0
- package/dist/infrastructure/metrics.js +291 -0
- package/dist/infrastructure/metrics.js.map +1 -0
- package/dist/infrastructure/rate-limiter.d.ts +59 -0
- package/dist/infrastructure/rate-limiter.d.ts.map +1 -0
- package/dist/infrastructure/rate-limiter.js +132 -0
- package/dist/infrastructure/rate-limiter.js.map +1 -0
- package/dist/infrastructure/response-builder.d.ts +104 -0
- package/dist/infrastructure/response-builder.d.ts.map +1 -0
- package/dist/infrastructure/response-builder.js +207 -0
- package/dist/infrastructure/response-builder.js.map +1 -0
- package/dist/infrastructure/token-estimator.d.ts +48 -0
- package/dist/infrastructure/token-estimator.d.ts.map +1 -0
- package/dist/infrastructure/token-estimator.js +131 -0
- package/dist/infrastructure/token-estimator.js.map +1 -0
- package/dist/server.d.ts.map +1 -1
- package/dist/server.js +1074 -17
- package/dist/server.js.map +1 -1
- package/dist/tools/detail/code-examples.d.ts +33 -0
- package/dist/tools/detail/code-examples.d.ts.map +1 -0
- package/dist/tools/detail/code-examples.js +126 -0
- package/dist/tools/detail/code-examples.js.map +1 -0
- package/dist/tools/detail/dna-check.d.ts +32 -0
- package/dist/tools/detail/dna-check.d.ts.map +1 -0
- package/dist/tools/detail/dna-check.js +231 -0
- package/dist/tools/detail/dna-check.js.map +1 -0
- package/dist/tools/detail/dna-profile.d.ts +37 -0
- package/dist/tools/detail/dna-profile.d.ts.map +1 -0
- package/dist/tools/detail/dna-profile.js +101 -0
- package/dist/tools/detail/dna-profile.js.map +1 -0
- package/dist/tools/detail/file-patterns.d.ts +39 -0
- package/dist/tools/detail/file-patterns.d.ts.map +1 -0
- package/dist/tools/detail/file-patterns.js +103 -0
- package/dist/tools/detail/file-patterns.js.map +1 -0
- package/dist/tools/detail/files-list.d.ts +30 -0
- package/dist/tools/detail/files-list.d.ts.map +1 -0
- package/dist/tools/detail/files-list.js +99 -0
- package/dist/tools/detail/files-list.js.map +1 -0
- package/dist/tools/detail/impact-analysis.d.ts +53 -0
- package/dist/tools/detail/impact-analysis.d.ts.map +1 -0
- package/dist/tools/detail/impact-analysis.js +130 -0
- package/dist/tools/detail/impact-analysis.js.map +1 -0
- package/dist/tools/detail/index.d.ts +23 -0
- package/dist/tools/detail/index.d.ts.map +1 -0
- package/dist/tools/detail/index.js +200 -0
- package/dist/tools/detail/index.js.map +1 -0
- package/dist/tools/detail/pattern-get.d.ts +45 -0
- package/dist/tools/detail/pattern-get.d.ts.map +1 -0
- package/dist/tools/detail/pattern-get.js +87 -0
- package/dist/tools/detail/pattern-get.js.map +1 -0
- package/dist/tools/detail/reachability.d.ts +60 -0
- package/dist/tools/detail/reachability.d.ts.map +1 -0
- package/dist/tools/detail/reachability.js +168 -0
- package/dist/tools/detail/reachability.js.map +1 -0
- package/dist/tools/discovery/capabilities.d.ts +28 -0
- package/dist/tools/discovery/capabilities.d.ts.map +1 -0
- package/dist/tools/discovery/capabilities.js +112 -0
- package/dist/tools/discovery/capabilities.js.map +1 -0
- package/dist/tools/discovery/index.d.ts +13 -0
- package/dist/tools/discovery/index.d.ts.map +1 -0
- package/dist/tools/discovery/index.js +30 -0
- package/dist/tools/discovery/index.js.map +1 -0
- package/dist/tools/discovery/projects.d.ts +26 -0
- package/dist/tools/discovery/projects.d.ts.map +1 -0
- package/dist/tools/discovery/projects.js +210 -0
- package/dist/tools/discovery/projects.js.map +1 -0
- package/dist/tools/discovery/status.d.ts +42 -0
- package/dist/tools/discovery/status.d.ts.map +1 -0
- package/dist/tools/discovery/status.js +157 -0
- package/dist/tools/discovery/status.js.map +1 -0
- package/dist/tools/exploration/contracts-list.d.ts +35 -0
- package/dist/tools/exploration/contracts-list.d.ts.map +1 -0
- package/dist/tools/exploration/contracts-list.js +106 -0
- package/dist/tools/exploration/contracts-list.js.map +1 -0
- package/dist/tools/exploration/files-list.d.ts +29 -0
- package/dist/tools/exploration/files-list.d.ts.map +1 -0
- package/dist/tools/exploration/files-list.js +94 -0
- package/dist/tools/exploration/files-list.js.map +1 -0
- package/dist/tools/exploration/index.d.ts +17 -0
- package/dist/tools/exploration/index.d.ts.map +1 -0
- package/dist/tools/exploration/index.js +126 -0
- package/dist/tools/exploration/index.js.map +1 -0
- package/dist/tools/exploration/patterns-list.d.ts +40 -0
- package/dist/tools/exploration/patterns-list.d.ts.map +1 -0
- package/dist/tools/exploration/patterns-list.js +172 -0
- package/dist/tools/exploration/patterns-list.js.map +1 -0
- package/dist/tools/exploration/security-summary.d.ts +49 -0
- package/dist/tools/exploration/security-summary.d.ts.map +1 -0
- package/dist/tools/exploration/security-summary.js +111 -0
- package/dist/tools/exploration/security-summary.js.map +1 -0
- package/dist/tools/exploration/trends.d.ts +49 -0
- package/dist/tools/exploration/trends.d.ts.map +1 -0
- package/dist/tools/exploration/trends.js +147 -0
- package/dist/tools/exploration/trends.js.map +1 -0
- package/dist/tools/index.d.ts +13 -0
- package/dist/tools/index.d.ts.map +1 -0
- package/dist/tools/index.js +13 -0
- package/dist/tools/index.js.map +1 -0
- package/dist/tools/orchestration/context.d.ts +72 -0
- package/dist/tools/orchestration/context.d.ts.map +1 -0
- package/dist/tools/orchestration/context.js +499 -0
- package/dist/tools/orchestration/context.js.map +1 -0
- package/dist/tools/orchestration/index.d.ts +11 -0
- package/dist/tools/orchestration/index.d.ts.map +1 -0
- package/dist/tools/orchestration/index.js +56 -0
- package/dist/tools/orchestration/index.js.map +1 -0
- package/dist/tools/registry.d.ts +41 -0
- package/dist/tools/registry.d.ts.map +1 -0
- package/dist/tools/registry.js +64 -0
- package/dist/tools/registry.js.map +1 -0
- package/package.json +3 -3
|
@@ -0,0 +1,210 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* MCP Tool: drift_projects
|
|
3
|
+
*
|
|
4
|
+
* List and manage registered drift projects.
|
|
5
|
+
* Enables AI agents to work across multiple codebases.
|
|
6
|
+
*/
|
|
7
|
+
import { getProjectRegistry, } from 'driftdetect-core';
|
|
8
|
+
function summarizeProject(project, activeId) {
|
|
9
|
+
return {
|
|
10
|
+
id: project.id,
|
|
11
|
+
name: project.name,
|
|
12
|
+
path: project.path,
|
|
13
|
+
language: project.language,
|
|
14
|
+
framework: project.framework,
|
|
15
|
+
health: project.health,
|
|
16
|
+
healthScore: project.healthScore,
|
|
17
|
+
lastAccessed: project.lastAccessedAt,
|
|
18
|
+
isActive: project.id === activeId,
|
|
19
|
+
isValid: project.isValid !== false,
|
|
20
|
+
};
|
|
21
|
+
}
|
|
22
|
+
export async function handleProjects(args) {
|
|
23
|
+
const action = args.action ?? 'list';
|
|
24
|
+
try {
|
|
25
|
+
const registry = await getProjectRegistry();
|
|
26
|
+
switch (action) {
|
|
27
|
+
case 'list': {
|
|
28
|
+
let projects = registry.getValid();
|
|
29
|
+
// Apply filters
|
|
30
|
+
if (args.language) {
|
|
31
|
+
projects = projects.filter(p => p.language.toLowerCase() === args.language.toLowerCase());
|
|
32
|
+
}
|
|
33
|
+
if (args.framework) {
|
|
34
|
+
projects = projects.filter(p => p.framework.toLowerCase() === args.framework.toLowerCase());
|
|
35
|
+
}
|
|
36
|
+
// Sort by last accessed
|
|
37
|
+
projects.sort((a, b) => new Date(b.lastAccessedAt).getTime() -
|
|
38
|
+
new Date(a.lastAccessedAt).getTime());
|
|
39
|
+
// Apply limit
|
|
40
|
+
if (args.limit) {
|
|
41
|
+
projects = projects.slice(0, args.limit);
|
|
42
|
+
}
|
|
43
|
+
const activeId = registry.getActive()?.id;
|
|
44
|
+
const summaries = projects.map(p => summarizeProject(p, activeId));
|
|
45
|
+
return {
|
|
46
|
+
content: [
|
|
47
|
+
{
|
|
48
|
+
type: 'text',
|
|
49
|
+
text: JSON.stringify({
|
|
50
|
+
totalProjects: registry.count,
|
|
51
|
+
filteredCount: summaries.length,
|
|
52
|
+
activeProject: activeId ? registry.get(activeId)?.name : null,
|
|
53
|
+
projects: summaries,
|
|
54
|
+
}, null, 2),
|
|
55
|
+
},
|
|
56
|
+
],
|
|
57
|
+
};
|
|
58
|
+
}
|
|
59
|
+
case 'info': {
|
|
60
|
+
let project;
|
|
61
|
+
if (args.project) {
|
|
62
|
+
// Find by name or ID
|
|
63
|
+
project =
|
|
64
|
+
registry.findByName(args.project) ??
|
|
65
|
+
registry.get(args.project) ??
|
|
66
|
+
registry.findByPath(args.project);
|
|
67
|
+
}
|
|
68
|
+
else {
|
|
69
|
+
// Use active project
|
|
70
|
+
project = registry.getActive();
|
|
71
|
+
}
|
|
72
|
+
if (!project) {
|
|
73
|
+
return {
|
|
74
|
+
content: [
|
|
75
|
+
{
|
|
76
|
+
type: 'text',
|
|
77
|
+
text: JSON.stringify({
|
|
78
|
+
error: 'Project not found',
|
|
79
|
+
hint: args.project
|
|
80
|
+
? `No project matching "${args.project}"`
|
|
81
|
+
: 'No active project. Use action="switch" to set one.',
|
|
82
|
+
}),
|
|
83
|
+
},
|
|
84
|
+
],
|
|
85
|
+
isError: true,
|
|
86
|
+
};
|
|
87
|
+
}
|
|
88
|
+
const activeId = registry.getActive()?.id;
|
|
89
|
+
return {
|
|
90
|
+
content: [
|
|
91
|
+
{
|
|
92
|
+
type: 'text',
|
|
93
|
+
text: JSON.stringify({
|
|
94
|
+
...project,
|
|
95
|
+
isActive: project.id === activeId,
|
|
96
|
+
}, null, 2),
|
|
97
|
+
},
|
|
98
|
+
],
|
|
99
|
+
};
|
|
100
|
+
}
|
|
101
|
+
case 'switch': {
|
|
102
|
+
if (!args.project) {
|
|
103
|
+
return {
|
|
104
|
+
content: [
|
|
105
|
+
{
|
|
106
|
+
type: 'text',
|
|
107
|
+
text: JSON.stringify({
|
|
108
|
+
error: 'Project name or ID required',
|
|
109
|
+
hint: 'Provide project="<name>" to switch',
|
|
110
|
+
}),
|
|
111
|
+
},
|
|
112
|
+
],
|
|
113
|
+
isError: true,
|
|
114
|
+
};
|
|
115
|
+
}
|
|
116
|
+
// Find project
|
|
117
|
+
const project = registry.findByName(args.project) ??
|
|
118
|
+
registry.get(args.project) ??
|
|
119
|
+
registry.findByPath(args.project);
|
|
120
|
+
if (!project) {
|
|
121
|
+
// Try partial match
|
|
122
|
+
const matches = registry.search(args.project);
|
|
123
|
+
if (matches.length > 0) {
|
|
124
|
+
return {
|
|
125
|
+
content: [
|
|
126
|
+
{
|
|
127
|
+
type: 'text',
|
|
128
|
+
text: JSON.stringify({
|
|
129
|
+
error: 'Ambiguous project name',
|
|
130
|
+
matches: matches.map(m => ({ name: m.name, path: m.path })),
|
|
131
|
+
hint: 'Be more specific or use the project ID',
|
|
132
|
+
}),
|
|
133
|
+
},
|
|
134
|
+
],
|
|
135
|
+
isError: true,
|
|
136
|
+
};
|
|
137
|
+
}
|
|
138
|
+
return {
|
|
139
|
+
content: [
|
|
140
|
+
{
|
|
141
|
+
type: 'text',
|
|
142
|
+
text: JSON.stringify({
|
|
143
|
+
error: `Project not found: ${args.project}`,
|
|
144
|
+
hint: 'Use action="list" to see available projects',
|
|
145
|
+
}),
|
|
146
|
+
},
|
|
147
|
+
],
|
|
148
|
+
isError: true,
|
|
149
|
+
};
|
|
150
|
+
}
|
|
151
|
+
await registry.setActive(project.id);
|
|
152
|
+
return {
|
|
153
|
+
content: [
|
|
154
|
+
{
|
|
155
|
+
type: 'text',
|
|
156
|
+
text: JSON.stringify({
|
|
157
|
+
success: true,
|
|
158
|
+
message: `Switched to ${project.name}`,
|
|
159
|
+
project: summarizeProject(project, project.id),
|
|
160
|
+
}),
|
|
161
|
+
},
|
|
162
|
+
],
|
|
163
|
+
};
|
|
164
|
+
}
|
|
165
|
+
case 'recent': {
|
|
166
|
+
const limit = args.limit ?? 5;
|
|
167
|
+
const recent = registry.getRecent(limit);
|
|
168
|
+
const activeId = registry.getActive()?.id;
|
|
169
|
+
return {
|
|
170
|
+
content: [
|
|
171
|
+
{
|
|
172
|
+
type: 'text',
|
|
173
|
+
text: JSON.stringify({
|
|
174
|
+
recentProjects: recent.map(p => summarizeProject(p, activeId)),
|
|
175
|
+
}, null, 2),
|
|
176
|
+
},
|
|
177
|
+
],
|
|
178
|
+
};
|
|
179
|
+
}
|
|
180
|
+
default:
|
|
181
|
+
return {
|
|
182
|
+
content: [
|
|
183
|
+
{
|
|
184
|
+
type: 'text',
|
|
185
|
+
text: JSON.stringify({
|
|
186
|
+
error: `Unknown action: ${action}`,
|
|
187
|
+
validActions: ['list', 'info', 'switch', 'recent'],
|
|
188
|
+
}),
|
|
189
|
+
},
|
|
190
|
+
],
|
|
191
|
+
isError: true,
|
|
192
|
+
};
|
|
193
|
+
}
|
|
194
|
+
}
|
|
195
|
+
catch (error) {
|
|
196
|
+
return {
|
|
197
|
+
content: [
|
|
198
|
+
{
|
|
199
|
+
type: 'text',
|
|
200
|
+
text: JSON.stringify({
|
|
201
|
+
error: 'Failed to access project registry',
|
|
202
|
+
message: error.message,
|
|
203
|
+
}),
|
|
204
|
+
},
|
|
205
|
+
],
|
|
206
|
+
isError: true,
|
|
207
|
+
};
|
|
208
|
+
}
|
|
209
|
+
}
|
|
210
|
+
//# sourceMappingURL=projects.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"projects.js","sourceRoot":"","sources":["../../../src/tools/discovery/projects.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,EACL,kBAAkB,GAEnB,MAAM,kBAAkB,CAAC;AA4B1B,SAAS,gBAAgB,CACvB,OAA0B,EAC1B,QAAiB;IAEjB,OAAO;QACL,EAAE,EAAE,OAAO,CAAC,EAAE;QACd,IAAI,EAAE,OAAO,CAAC,IAAI;QAClB,IAAI,EAAE,OAAO,CAAC,IAAI;QAClB,QAAQ,EAAE,OAAO,CAAC,QAAQ;QAC1B,SAAS,EAAE,OAAO,CAAC,SAAS;QAC5B,MAAM,EAAE,OAAO,CAAC,MAAM;QACtB,WAAW,EAAE,OAAO,CAAC,WAAW;QAChC,YAAY,EAAE,OAAO,CAAC,cAAc;QACpC,QAAQ,EAAE,OAAO,CAAC,EAAE,KAAK,QAAQ;QACjC,OAAO,EAAE,OAAO,CAAC,OAAO,KAAK,KAAK;KACnC,CAAC;AACJ,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,cAAc,CAClC,IAAkB;IAElB,MAAM,MAAM,GAAG,IAAI,CAAC,MAAM,IAAI,MAAM,CAAC;IAErC,IAAI,CAAC;QACH,MAAM,QAAQ,GAAG,MAAM,kBAAkB,EAAE,CAAC;QAE5C,QAAQ,MAAM,EAAE,CAAC;YACf,KAAK,MAAM,CAAC,CAAC,CAAC;gBACZ,IAAI,QAAQ,GAAG,QAAQ,CAAC,QAAQ,EAAE,CAAC;gBAEnC,gBAAgB;gBAChB,IAAI,IAAI,CAAC,QAAQ,EAAE,CAAC;oBAClB,QAAQ,GAAG,QAAQ,CAAC,MAAM,CACxB,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,QAAQ,CAAC,WAAW,EAAE,KAAK,IAAI,CAAC,QAAS,CAAC,WAAW,EAAE,CAC/D,CAAC;gBACJ,CAAC;gBACD,IAAI,IAAI,CAAC,SAAS,EAAE,CAAC;oBACnB,QAAQ,GAAG,QAAQ,CAAC,MAAM,CACxB,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,SAAS,CAAC,WAAW,EAAE,KAAK,IAAI,CAAC,SAAU,CAAC,WAAW,EAAE,CACjE,CAAC;gBACJ,CAAC;gBAED,wBAAwB;gBACxB,QAAQ,CAAC,IAAI,CACX,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CACP,IAAI,IAAI,CAAC,CAAC,CAAC,cAAc,CAAC,CAAC,OAAO,EAAE;oBACpC,IAAI,IAAI,CAAC,CAAC,CAAC,cAAc,CAAC,CAAC,OAAO,EAAE,CACvC,CAAC;gBAEF,cAAc;gBACd,IAAI,IAAI,CAAC,KAAK,EAAE,CAAC;oBACf,QAAQ,GAAG,QAAQ,CAAC,KAAK,CAAC,CAAC,EAAE,IAAI,CAAC,KAAK,CAAC,CAAC;gBAC3C,CAAC;gBAED,MAAM,QAAQ,GAAG,QAAQ,CAAC,SAAS,EAAE,EAAE,EAAE,CAAC;gBAC1C,MAAM,SAAS,GAAG,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,gBAAgB,CAAC,CAAC,EAAE,QAAQ,CAAC,CAAC,CAAC;gBAEnE,OAAO;oBACL,OAAO,EAAE;wBACP;4BACE,IAAI,EAAE,MAAM;4BACZ,IAAI,EAAE,IAAI,CAAC,SAAS,CAClB;gCACE,aAAa,EAAE,QAAQ,CAAC,KAAK;gCAC7B,aAAa,EAAE,SAAS,CAAC,MAAM;gCAC/B,aAAa,EAAE,QAAQ,CAAC,CAAC,CAAC,QAAQ,CAAC,GAAG,CAAC,QAAQ,CAAC,EAAE,IAAI,CAAC,CAAC,CAAC,IAAI;gCAC7D,QAAQ,EAAE,SAAS;6BACpB,EACD,IAAI,EACJ,CAAC,CACF;yBACF;qBACF;iBACF,CAAC;YACJ,CAAC;YAED,KAAK,MAAM,CAAC,CAAC,CAAC;gBACZ,IAAI,OAAsC,CAAC;gBAE3C,IAAI,IAAI,CAAC,OAAO,EAAE,CAAC;oBACjB,qBAAqB;oBACrB,OAAO;wBACL,QAAQ,CAAC,UAAU,CAAC,IAAI,CAAC,OAAO,CAAC;4BACjC,QAAQ,CAAC,GAAG,CAAC,IAAI,CAAC,OAAO,CAAC;4BAC1B,QAAQ,CAAC,UAAU,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;gBACtC,CAAC;qBAAM,CAAC;oBACN,qBAAqB;oBACrB,OAAO,GAAG,QAAQ,CAAC,SAAS,EAAE,CAAC;gBACjC,CAAC;gBAED,IAAI,CAAC,OAAO,EAAE,CAAC;oBACb,OAAO;wBACL,OAAO,EAAE;4BACP;gCACE,IAAI,EAAE,MAAM;gCACZ,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC;oCACnB,KAAK,EAAE,mBAAmB;oCAC1B,IAAI,EAAE,IAAI,CAAC,OAAO;wCAChB,CAAC,CAAC,wBAAwB,IAAI,CAAC,OAAO,GAAG;wCACzC,CAAC,CAAC,oDAAoD;iCACzD,CAAC;6BACH;yBACF;wBACD,OAAO,EAAE,IAAI;qBACd,CAAC;gBACJ,CAAC;gBAED,MAAM,QAAQ,GAAG,QAAQ,CAAC,SAAS,EAAE,EAAE,EAAE,CAAC;gBAE1C,OAAO;oBACL,OAAO,EAAE;wBACP;4BACE,IAAI,EAAE,MAAM;4BACZ,IAAI,EAAE,IAAI,CAAC,SAAS,CAClB;gCACE,GAAG,OAAO;gCACV,QAAQ,EAAE,OAAO,CAAC,EAAE,KAAK,QAAQ;6BAClC,EACD,IAAI,EACJ,CAAC,CACF;yBACF;qBACF;iBACF,CAAC;YACJ,CAAC;YAED,KAAK,QAAQ,CAAC,CAAC,CAAC;gBACd,IAAI,CAAC,IAAI,CAAC,OAAO,EAAE,CAAC;oBAClB,OAAO;wBACL,OAAO,EAAE;4BACP;gCACE,IAAI,EAAE,MAAM;gCACZ,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC;oCACnB,KAAK,EAAE,6BAA6B;oCACpC,IAAI,EAAE,oCAAoC;iCAC3C,CAAC;6BACH;yBACF;wBACD,OAAO,EAAE,IAAI;qBACd,CAAC;gBACJ,CAAC;gBAED,eAAe;gBACf,MAAM,OAAO,GACX,QAAQ,CAAC,UAAU,CAAC,IAAI,CAAC,OAAO,CAAC;oBACjC,QAAQ,CAAC,GAAG,CAAC,IAAI,CAAC,OAAO,CAAC;oBAC1B,QAAQ,CAAC,UAAU,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;gBAEpC,IAAI,CAAC,OAAO,EAAE,CAAC;oBACb,oBAAoB;oBACpB,MAAM,OAAO,GAAG,QAAQ,CAAC,MAAM,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;oBAC9C,IAAI,OAAO,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;wBACvB,OAAO;4BACL,OAAO,EAAE;gCACP;oCACE,IAAI,EAAE,MAAM;oCACZ,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC;wCACnB,KAAK,EAAE,wBAAwB;wCAC/B,OAAO,EAAE,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,IAAI,EAAE,CAAC,CAAC,IAAI,EAAE,IAAI,EAAE,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC;wCAC3D,IAAI,EAAE,wCAAwC;qCAC/C,CAAC;iCACH;6BACF;4BACD,OAAO,EAAE,IAAI;yBACd,CAAC;oBACJ,CAAC;oBAED,OAAO;wBACL,OAAO,EAAE;4BACP;gCACE,IAAI,EAAE,MAAM;gCACZ,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC;oCACnB,KAAK,EAAE,sBAAsB,IAAI,CAAC,OAAO,EAAE;oCAC3C,IAAI,EAAE,6CAA6C;iCACpD,CAAC;6BACH;yBACF;wBACD,OAAO,EAAE,IAAI;qBACd,CAAC;gBACJ,CAAC;gBAED,MAAM,QAAQ,CAAC,SAAS,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC;gBAErC,OAAO;oBACL,OAAO,EAAE;wBACP;4BACE,IAAI,EAAE,MAAM;4BACZ,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC;gCACnB,OAAO,EAAE,IAAI;gCACb,OAAO,EAAE,eAAe,OAAO,CAAC,IAAI,EAAE;gCACtC,OAAO,EAAE,gBAAgB,CAAC,OAAO,EAAE,OAAO,CAAC,EAAE,CAAC;6BAC/C,CAAC;yBACH;qBACF;iBACF,CAAC;YACJ,CAAC;YAED,KAAK,QAAQ,CAAC,CAAC,CAAC;gBACd,MAAM,KAAK,GAAG,IAAI,CAAC,KAAK,IAAI,CAAC,CAAC;gBAC9B,MAAM,MAAM,GAAG,QAAQ,CAAC,SAAS,CAAC,KAAK,CAAC,CAAC;gBACzC,MAAM,QAAQ,GAAG,QAAQ,CAAC,SAAS,EAAE,EAAE,EAAE,CAAC;gBAE1C,OAAO;oBACL,OAAO,EAAE;wBACP;4BACE,IAAI,EAAE,MAAM;4BACZ,IAAI,EAAE,IAAI,CAAC,SAAS,CAClB;gCACE,cAAc,EAAE,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,gBAAgB,CAAC,CAAC,EAAE,QAAQ,CAAC,CAAC;6BAC/D,EACD,IAAI,EACJ,CAAC,CACF;yBACF;qBACF;iBACF,CAAC;YACJ,CAAC;YAED;gBACE,OAAO;oBACL,OAAO,EAAE;wBACP;4BACE,IAAI,EAAE,MAAM;4BACZ,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC;gCACnB,KAAK,EAAE,mBAAmB,MAAM,EAAE;gCAClC,YAAY,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,QAAQ,EAAE,QAAQ,CAAC;6BACnD,CAAC;yBACH;qBACF;oBACD,OAAO,EAAE,IAAI;iBACd,CAAC;QACN,CAAC;IACH,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,OAAO;YACL,OAAO,EAAE;gBACP;oBACE,IAAI,EAAE,MAAM;oBACZ,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC;wBACnB,KAAK,EAAE,mCAAmC;wBAC1C,OAAO,EAAG,KAAe,CAAC,OAAO;qBAClC,CAAC;iBACH;aACF;YACD,OAAO,EAAE,IAAI;SACd,CAAC;IACJ,CAAC;AACH,CAAC"}
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* drift_status - Codebase Health Snapshot
|
|
3
|
+
*
|
|
4
|
+
* Discovery tool that provides a quick overview of:
|
|
5
|
+
* - Pattern counts by category
|
|
6
|
+
* - Health score
|
|
7
|
+
* - Critical issues requiring attention
|
|
8
|
+
* - Scan status
|
|
9
|
+
*
|
|
10
|
+
* OPTIMIZED: Uses pre-computed views from the data lake for instant response.
|
|
11
|
+
* Falls back to computing from raw data if views are unavailable.
|
|
12
|
+
*/
|
|
13
|
+
import type { PatternStore, DataLake } from 'driftdetect-core';
|
|
14
|
+
export interface StatusData {
|
|
15
|
+
health: {
|
|
16
|
+
score: number;
|
|
17
|
+
trend: 'improving' | 'stable' | 'declining';
|
|
18
|
+
};
|
|
19
|
+
patterns: {
|
|
20
|
+
total: number;
|
|
21
|
+
approved: number;
|
|
22
|
+
discovered: number;
|
|
23
|
+
byCategory: Record<string, number>;
|
|
24
|
+
};
|
|
25
|
+
issues: {
|
|
26
|
+
critical: number;
|
|
27
|
+
warnings: number;
|
|
28
|
+
};
|
|
29
|
+
lastScan?: string | undefined;
|
|
30
|
+
/** Response source for debugging */
|
|
31
|
+
_source?: 'view' | 'computed';
|
|
32
|
+
}
|
|
33
|
+
/**
|
|
34
|
+
* Handle status request - optimized with data lake views
|
|
35
|
+
*/
|
|
36
|
+
export declare function handleStatus(store: PatternStore, _args: Record<string, unknown>, dataLake?: DataLake): Promise<{
|
|
37
|
+
content: Array<{
|
|
38
|
+
type: string;
|
|
39
|
+
text: string;
|
|
40
|
+
}>;
|
|
41
|
+
}>;
|
|
42
|
+
//# sourceMappingURL=status.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"status.d.ts","sourceRoot":"","sources":["../../../src/tools/discovery/status.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAEH,OAAO,KAAK,EAAE,YAAY,EAAE,QAAQ,EAAc,MAAM,kBAAkB,CAAC;AAG3E,MAAM,WAAW,UAAU;IACzB,MAAM,EAAE;QACN,KAAK,EAAE,MAAM,CAAC;QACd,KAAK,EAAE,WAAW,GAAG,QAAQ,GAAG,WAAW,CAAC;KAC7C,CAAC;IACF,QAAQ,EAAE;QACR,KAAK,EAAE,MAAM,CAAC;QACd,QAAQ,EAAE,MAAM,CAAC;QACjB,UAAU,EAAE,MAAM,CAAC;QACnB,UAAU,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;KACpC,CAAC;IACF,MAAM,EAAE;QACN,QAAQ,EAAE,MAAM,CAAC;QACjB,QAAQ,EAAE,MAAM,CAAC;KAClB,CAAC;IACF,QAAQ,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IAC9B,oCAAoC;IACpC,OAAO,CAAC,EAAE,MAAM,GAAG,UAAU,CAAC;CAC/B;AAED;;GAEG;AACH,wBAAsB,YAAY,CAChC,KAAK,EAAE,YAAY,EACnB,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAC9B,QAAQ,CAAC,EAAE,QAAQ,GAClB,OAAO,CAAC;IAAE,OAAO,EAAE,KAAK,CAAC;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAA;KAAE,CAAC,CAAA;CAAE,CAAC,CAwF7D"}
|
|
@@ -0,0 +1,157 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* drift_status - Codebase Health Snapshot
|
|
3
|
+
*
|
|
4
|
+
* Discovery tool that provides a quick overview of:
|
|
5
|
+
* - Pattern counts by category
|
|
6
|
+
* - Health score
|
|
7
|
+
* - Critical issues requiring attention
|
|
8
|
+
* - Scan status
|
|
9
|
+
*
|
|
10
|
+
* OPTIMIZED: Uses pre-computed views from the data lake for instant response.
|
|
11
|
+
* Falls back to computing from raw data if views are unavailable.
|
|
12
|
+
*/
|
|
13
|
+
import { createResponseBuilder } from '../../infrastructure/index.js';
|
|
14
|
+
/**
|
|
15
|
+
* Handle status request - optimized with data lake views
|
|
16
|
+
*/
|
|
17
|
+
export async function handleStatus(store, _args, dataLake) {
|
|
18
|
+
const builder = createResponseBuilder();
|
|
19
|
+
try {
|
|
20
|
+
// OPTIMIZATION: Try data lake view first (instant response)
|
|
21
|
+
if (dataLake) {
|
|
22
|
+
const statusView = await tryGetStatusFromLake(dataLake);
|
|
23
|
+
if (statusView) {
|
|
24
|
+
return buildResponseFromView(builder, statusView);
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
// Fallback: Compute from raw data
|
|
28
|
+
await store.initialize();
|
|
29
|
+
const stats = store.getStats();
|
|
30
|
+
const patterns = store.getAll();
|
|
31
|
+
// Calculate health score (0-100)
|
|
32
|
+
const approvedCount = patterns.filter(p => p.status === 'approved').length;
|
|
33
|
+
const highConfidenceCount = patterns.filter(p => p.confidence.score >= 0.85).length;
|
|
34
|
+
const healthScore = Math.round((approvedCount / Math.max(1, stats.totalPatterns)) * 50 +
|
|
35
|
+
(highConfidenceCount / Math.max(1, stats.totalPatterns)) * 50);
|
|
36
|
+
// Count issues
|
|
37
|
+
const criticalIssues = patterns.filter(p => p.status === 'approved' && p.outliers.length > 5).length;
|
|
38
|
+
const warnings = patterns.filter(p => p.confidence.score < 0.7 && p.locations.length > 3).length;
|
|
39
|
+
const data = {
|
|
40
|
+
health: {
|
|
41
|
+
score: healthScore,
|
|
42
|
+
trend: 'stable', // TODO: Calculate from history
|
|
43
|
+
},
|
|
44
|
+
patterns: {
|
|
45
|
+
total: stats.totalPatterns,
|
|
46
|
+
approved: approvedCount,
|
|
47
|
+
discovered: stats.totalPatterns - approvedCount,
|
|
48
|
+
byCategory: stats.byCategory,
|
|
49
|
+
},
|
|
50
|
+
issues: {
|
|
51
|
+
critical: criticalIssues,
|
|
52
|
+
warnings,
|
|
53
|
+
},
|
|
54
|
+
_source: 'computed',
|
|
55
|
+
};
|
|
56
|
+
// Build summary
|
|
57
|
+
let summary = `Health: ${healthScore}/100. `;
|
|
58
|
+
summary += `${stats.totalPatterns} patterns (${approvedCount} approved). `;
|
|
59
|
+
if (criticalIssues > 0) {
|
|
60
|
+
summary += `⚠️ ${criticalIssues} critical issues.`;
|
|
61
|
+
}
|
|
62
|
+
else {
|
|
63
|
+
summary += 'No critical issues.';
|
|
64
|
+
}
|
|
65
|
+
return builder
|
|
66
|
+
.withSummary(summary)
|
|
67
|
+
.withData(data)
|
|
68
|
+
.withHints({
|
|
69
|
+
nextActions: [
|
|
70
|
+
criticalIssues > 0
|
|
71
|
+
? 'Use drift_patterns_list with status="approved" to see patterns with issues'
|
|
72
|
+
: 'Use drift_patterns_list to explore discovered patterns',
|
|
73
|
+
'Use drift_capabilities to see all available tools',
|
|
74
|
+
],
|
|
75
|
+
...(criticalIssues > 0 ? { warnings: [`${criticalIssues} approved patterns have significant outliers`] } : {}),
|
|
76
|
+
})
|
|
77
|
+
.buildContent();
|
|
78
|
+
}
|
|
79
|
+
catch (error) {
|
|
80
|
+
// No patterns found - likely needs scan
|
|
81
|
+
return builder
|
|
82
|
+
.withSummary('No pattern data found. Run drift scan first.')
|
|
83
|
+
.withData({
|
|
84
|
+
health: { score: 0, trend: 'stable' },
|
|
85
|
+
patterns: { total: 0, approved: 0, discovered: 0, byCategory: {} },
|
|
86
|
+
issues: { critical: 0, warnings: 0 },
|
|
87
|
+
})
|
|
88
|
+
.withHints({
|
|
89
|
+
nextActions: ["Run 'drift scan' in the project root to analyze patterns"],
|
|
90
|
+
})
|
|
91
|
+
.buildContent();
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
/**
|
|
95
|
+
* Try to get status from data lake view (instant)
|
|
96
|
+
*/
|
|
97
|
+
async function tryGetStatusFromLake(dataLake) {
|
|
98
|
+
try {
|
|
99
|
+
await dataLake.initialize();
|
|
100
|
+
return await dataLake.query.getStatus();
|
|
101
|
+
}
|
|
102
|
+
catch {
|
|
103
|
+
return null;
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
/**
|
|
107
|
+
* Build response from pre-computed status view
|
|
108
|
+
*/
|
|
109
|
+
function buildResponseFromView(builder, view) {
|
|
110
|
+
const data = {
|
|
111
|
+
health: {
|
|
112
|
+
score: view.health.score,
|
|
113
|
+
trend: view.health.trend,
|
|
114
|
+
},
|
|
115
|
+
patterns: {
|
|
116
|
+
total: view.patterns.total,
|
|
117
|
+
approved: view.patterns.approved,
|
|
118
|
+
discovered: view.patterns.discovered,
|
|
119
|
+
byCategory: view.patterns.byCategory,
|
|
120
|
+
},
|
|
121
|
+
issues: {
|
|
122
|
+
critical: view.issues.critical,
|
|
123
|
+
warnings: view.issues.warnings,
|
|
124
|
+
},
|
|
125
|
+
lastScan: view.lastScan.timestamp,
|
|
126
|
+
_source: 'view',
|
|
127
|
+
};
|
|
128
|
+
// Build summary
|
|
129
|
+
let summary = `Health: ${view.health.score}/100 (${view.health.trend}). `;
|
|
130
|
+
summary += `${view.patterns.total} patterns (${view.patterns.approved} approved). `;
|
|
131
|
+
if (view.issues.critical > 0) {
|
|
132
|
+
summary += `⚠️ ${view.issues.critical} critical issues.`;
|
|
133
|
+
}
|
|
134
|
+
else {
|
|
135
|
+
summary += 'No critical issues.';
|
|
136
|
+
}
|
|
137
|
+
// Add security info if available
|
|
138
|
+
if (view.security.violations > 0) {
|
|
139
|
+
summary += ` Security: ${view.security.riskLevel} risk, ${view.security.violations} violations.`;
|
|
140
|
+
}
|
|
141
|
+
return builder
|
|
142
|
+
.withSummary(summary)
|
|
143
|
+
.withData(data)
|
|
144
|
+
.withHints({
|
|
145
|
+
nextActions: [
|
|
146
|
+
view.issues.critical > 0
|
|
147
|
+
? 'Use drift_patterns_list with status="approved" to see patterns with issues'
|
|
148
|
+
: 'Use drift_patterns_list to explore discovered patterns',
|
|
149
|
+
view.security.violations > 0
|
|
150
|
+
? 'Use drift_security_summary to review security violations'
|
|
151
|
+
: 'Use drift_capabilities to see all available tools',
|
|
152
|
+
],
|
|
153
|
+
...(view.issues.critical > 0 ? { warnings: [`${view.issues.critical} critical issues detected`] } : {}),
|
|
154
|
+
})
|
|
155
|
+
.buildContent();
|
|
156
|
+
}
|
|
157
|
+
//# sourceMappingURL=status.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"status.js","sourceRoot":"","sources":["../../../src/tools/discovery/status.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAGH,OAAO,EAAE,qBAAqB,EAAE,MAAM,+BAA+B,CAAC;AAsBtE;;GAEG;AACH,MAAM,CAAC,KAAK,UAAU,YAAY,CAChC,KAAmB,EACnB,KAA8B,EAC9B,QAAmB;IAEnB,MAAM,OAAO,GAAG,qBAAqB,EAAc,CAAC;IAEpD,IAAI,CAAC;QACH,4DAA4D;QAC5D,IAAI,QAAQ,EAAE,CAAC;YACb,MAAM,UAAU,GAAG,MAAM,oBAAoB,CAAC,QAAQ,CAAC,CAAC;YACxD,IAAI,UAAU,EAAE,CAAC;gBACf,OAAO,qBAAqB,CAAC,OAAO,EAAE,UAAU,CAAC,CAAC;YACpD,CAAC;QACH,CAAC;QAED,kCAAkC;QAClC,MAAM,KAAK,CAAC,UAAU,EAAE,CAAC;QACzB,MAAM,KAAK,GAAG,KAAK,CAAC,QAAQ,EAAE,CAAC;QAC/B,MAAM,QAAQ,GAAG,KAAK,CAAC,MAAM,EAAE,CAAC;QAEhC,iCAAiC;QACjC,MAAM,aAAa,GAAG,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,MAAM,KAAK,UAAU,CAAC,CAAC,MAAM,CAAC;QAC3E,MAAM,mBAAmB,GAAG,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,UAAU,CAAC,KAAK,IAAI,IAAI,CAAC,CAAC,MAAM,CAAC;QACpF,MAAM,WAAW,GAAG,IAAI,CAAC,KAAK,CAC5B,CAAC,aAAa,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,KAAK,CAAC,aAAa,CAAC,CAAC,GAAG,EAAE;YACvD,CAAC,mBAAmB,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,KAAK,CAAC,aAAa,CAAC,CAAC,GAAG,EAAE,CAC9D,CAAC;QAEF,eAAe;QACf,MAAM,cAAc,GAAG,QAAQ,CAAC,MAAM,CACpC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,MAAM,KAAK,UAAU,IAAI,CAAC,CAAC,QAAQ,CAAC,MAAM,GAAG,CAAC,CACtD,CAAC,MAAM,CAAC;QACT,MAAM,QAAQ,GAAG,QAAQ,CAAC,MAAM,CAC9B,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,UAAU,CAAC,KAAK,GAAG,GAAG,IAAI,CAAC,CAAC,SAAS,CAAC,MAAM,GAAG,CAAC,CACxD,CAAC,MAAM,CAAC;QAET,MAAM,IAAI,GAAe;YACvB,MAAM,EAAE;gBACN,KAAK,EAAE,WAAW;gBAClB,KAAK,EAAE,QAAQ,EAAE,+BAA+B;aACjD;YACD,QAAQ,EAAE;gBACR,KAAK,EAAE,KAAK,CAAC,aAAa;gBAC1B,QAAQ,EAAE,aAAa;gBACvB,UAAU,EAAE,KAAK,CAAC,aAAa,GAAG,aAAa;gBAC/C,UAAU,EAAE,KAAK,CAAC,UAAU;aAC7B;YACD,MAAM,EAAE;gBACN,QAAQ,EAAE,cAAc;gBACxB,QAAQ;aACT;YACD,OAAO,EAAE,UAAU;SACpB,CAAC;QAEF,gBAAgB;QAChB,IAAI,OAAO,GAAG,WAAW,WAAW,QAAQ,CAAC;QAC7C,OAAO,IAAI,GAAG,KAAK,CAAC,aAAa,cAAc,aAAa,cAAc,CAAC;QAC3E,IAAI,cAAc,GAAG,CAAC,EAAE,CAAC;YACvB,OAAO,IAAI,MAAM,cAAc,mBAAmB,CAAC;QACrD,CAAC;aAAM,CAAC;YACN,OAAO,IAAI,qBAAqB,CAAC;QACnC,CAAC;QAED,OAAO,OAAO;aACX,WAAW,CAAC,OAAO,CAAC;aACpB,QAAQ,CAAC,IAAI,CAAC;aACd,SAAS,CAAC;YACT,WAAW,EAAE;gBACX,cAAc,GAAG,CAAC;oBAChB,CAAC,CAAC,4EAA4E;oBAC9E,CAAC,CAAC,wDAAwD;gBAC5D,mDAAmD;aACpD;YACD,GAAG,CAAC,cAAc,GAAG,CAAC,CAAC,CAAC,CAAC,EAAE,QAAQ,EAAE,CAAC,GAAG,cAAc,8CAA8C,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;SAC/G,CAAC;aACD,YAAY,EAAE,CAAC;IAEpB,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,wCAAwC;QACxC,OAAO,OAAO;aACX,WAAW,CAAC,8CAA8C,CAAC;aAC3D,QAAQ,CAAC;YACR,MAAM,EAAE,EAAE,KAAK,EAAE,CAAC,EAAE,KAAK,EAAE,QAAQ,EAAE;YACrC,QAAQ,EAAE,EAAE,KAAK,EAAE,CAAC,EAAE,QAAQ,EAAE,CAAC,EAAE,UAAU,EAAE,CAAC,EAAE,UAAU,EAAE,EAAE,EAAE;YAClE,MAAM,EAAE,EAAE,QAAQ,EAAE,CAAC,EAAE,QAAQ,EAAE,CAAC,EAAE;SACrC,CAAC;aACD,SAAS,CAAC;YACT,WAAW,EAAE,CAAC,0DAA0D,CAAC;SAC1E,CAAC;aACD,YAAY,EAAE,CAAC;IACpB,CAAC;AACH,CAAC;AAED;;GAEG;AACH,KAAK,UAAU,oBAAoB,CAAC,QAAkB;IACpD,IAAI,CAAC;QACH,MAAM,QAAQ,CAAC,UAAU,EAAE,CAAC;QAC5B,OAAO,MAAM,QAAQ,CAAC,KAAK,CAAC,SAAS,EAAE,CAAC;IAC1C,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,IAAI,CAAC;IACd,CAAC;AACH,CAAC;AAED;;GAEG;AACH,SAAS,qBAAqB,CAC5B,OAA6D,EAC7D,IAAgB;IAEhB,MAAM,IAAI,GAAe;QACvB,MAAM,EAAE;YACN,KAAK,EAAE,IAAI,CAAC,MAAM,CAAC,KAAK;YACxB,KAAK,EAAE,IAAI,CAAC,MAAM,CAAC,KAAK;SACzB;QACD,QAAQ,EAAE;YACR,KAAK,EAAE,IAAI,CAAC,QAAQ,CAAC,KAAK;YAC1B,QAAQ,EAAE,IAAI,CAAC,QAAQ,CAAC,QAAQ;YAChC,UAAU,EAAE,IAAI,CAAC,QAAQ,CAAC,UAAU;YACpC,UAAU,EAAE,IAAI,CAAC,QAAQ,CAAC,UAAU;SACrC;QACD,MAAM,EAAE;YACN,QAAQ,EAAE,IAAI,CAAC,MAAM,CAAC,QAAQ;YAC9B,QAAQ,EAAE,IAAI,CAAC,MAAM,CAAC,QAAQ;SAC/B;QACD,QAAQ,EAAE,IAAI,CAAC,QAAQ,CAAC,SAAS;QACjC,OAAO,EAAE,MAAM;KAChB,CAAC;IAEF,gBAAgB;IAChB,IAAI,OAAO,GAAG,WAAW,IAAI,CAAC,MAAM,CAAC,KAAK,SAAS,IAAI,CAAC,MAAM,CAAC,KAAK,KAAK,CAAC;IAC1E,OAAO,IAAI,GAAG,IAAI,CAAC,QAAQ,CAAC,KAAK,cAAc,IAAI,CAAC,QAAQ,CAAC,QAAQ,cAAc,CAAC;IACpF,IAAI,IAAI,CAAC,MAAM,CAAC,QAAQ,GAAG,CAAC,EAAE,CAAC;QAC7B,OAAO,IAAI,MAAM,IAAI,CAAC,MAAM,CAAC,QAAQ,mBAAmB,CAAC;IAC3D,CAAC;SAAM,CAAC;QACN,OAAO,IAAI,qBAAqB,CAAC;IACnC,CAAC;IAED,iCAAiC;IACjC,IAAI,IAAI,CAAC,QAAQ,CAAC,UAAU,GAAG,CAAC,EAAE,CAAC;QACjC,OAAO,IAAI,cAAc,IAAI,CAAC,QAAQ,CAAC,SAAS,UAAU,IAAI,CAAC,QAAQ,CAAC,UAAU,cAAc,CAAC;IACnG,CAAC;IAED,OAAO,OAAO;SACX,WAAW,CAAC,OAAO,CAAC;SACpB,QAAQ,CAAC,IAAI,CAAC;SACd,SAAS,CAAC;QACT,WAAW,EAAE;YACX,IAAI,CAAC,MAAM,CAAC,QAAQ,GAAG,CAAC;gBACtB,CAAC,CAAC,4EAA4E;gBAC9E,CAAC,CAAC,wDAAwD;YAC5D,IAAI,CAAC,QAAQ,CAAC,UAAU,GAAG,CAAC;gBAC1B,CAAC,CAAC,0DAA0D;gBAC5D,CAAC,CAAC,mDAAmD;SACxD;QACD,GAAG,CAAC,IAAI,CAAC,MAAM,CAAC,QAAQ,GAAG,CAAC,CAAC,CAAC,CAAC,EAAE,QAAQ,EAAE,CAAC,GAAG,IAAI,CAAC,MAAM,CAAC,QAAQ,2BAA2B,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;KACxG,CAAC;SACD,YAAY,EAAE,CAAC;AACpB,CAAC"}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* drift_contracts_list - API Contract Listing
|
|
3
|
+
*
|
|
4
|
+
* Exploration tool that lists API contracts between frontend and backend.
|
|
5
|
+
* Shows verified contracts, mismatches, and discovered endpoints.
|
|
6
|
+
*/
|
|
7
|
+
import type { ContractStore } from 'driftdetect-core';
|
|
8
|
+
export interface ContractSummary {
|
|
9
|
+
id: string;
|
|
10
|
+
endpoint: string;
|
|
11
|
+
method: string;
|
|
12
|
+
status: 'verified' | 'mismatch' | 'discovered';
|
|
13
|
+
frontendFile: string | undefined;
|
|
14
|
+
backendFile: string;
|
|
15
|
+
mismatchCount: number;
|
|
16
|
+
}
|
|
17
|
+
export interface ContractsListData {
|
|
18
|
+
contracts: ContractSummary[];
|
|
19
|
+
stats: {
|
|
20
|
+
verified: number;
|
|
21
|
+
mismatch: number;
|
|
22
|
+
discovered: number;
|
|
23
|
+
};
|
|
24
|
+
}
|
|
25
|
+
export declare function handleContractsList(store: ContractStore, args: {
|
|
26
|
+
status?: string;
|
|
27
|
+
limit?: number;
|
|
28
|
+
cursor?: string;
|
|
29
|
+
}): Promise<{
|
|
30
|
+
content: Array<{
|
|
31
|
+
type: string;
|
|
32
|
+
text: string;
|
|
33
|
+
}>;
|
|
34
|
+
}>;
|
|
35
|
+
//# sourceMappingURL=contracts-list.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"contracts-list.d.ts","sourceRoot":"","sources":["../../../src/tools/exploration/contracts-list.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,KAAK,EAAE,aAAa,EAAY,MAAM,kBAAkB,CAAC;AAQhE,MAAM,WAAW,eAAe;IAC9B,EAAE,EAAE,MAAM,CAAC;IACX,QAAQ,EAAE,MAAM,CAAC;IACjB,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,UAAU,GAAG,UAAU,GAAG,YAAY,CAAC;IAC/C,YAAY,EAAE,MAAM,GAAG,SAAS,CAAC;IACjC,WAAW,EAAE,MAAM,CAAC;IACpB,aAAa,EAAE,MAAM,CAAC;CACvB;AAED,MAAM,WAAW,iBAAiB;IAChC,SAAS,EAAE,eAAe,EAAE,CAAC;IAC7B,KAAK,EAAE;QACL,QAAQ,EAAE,MAAM,CAAC;QACjB,QAAQ,EAAE,MAAM,CAAC;QACjB,UAAU,EAAE,MAAM,CAAC;KACpB,CAAC;CACH;AAKD,wBAAsB,mBAAmB,CACvC,KAAK,EAAE,aAAa,EACpB,IAAI,EAAE;IACJ,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB,GACA,OAAO,CAAC;IAAE,OAAO,EAAE,KAAK,CAAC;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAA;KAAE,CAAC,CAAA;CAAE,CAAC,CA+G7D"}
|
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* drift_contracts_list - API Contract Listing
|
|
3
|
+
*
|
|
4
|
+
* Exploration tool that lists API contracts between frontend and backend.
|
|
5
|
+
* Shows verified contracts, mismatches, and discovered endpoints.
|
|
6
|
+
*/
|
|
7
|
+
import { createResponseBuilder, cursorManager, Errors, } from '../../infrastructure/index.js';
|
|
8
|
+
const DEFAULT_LIMIT = 20;
|
|
9
|
+
const MAX_LIMIT = 50;
|
|
10
|
+
export async function handleContractsList(store, args) {
|
|
11
|
+
const builder = createResponseBuilder();
|
|
12
|
+
await store.initialize();
|
|
13
|
+
// Parse cursor if provided
|
|
14
|
+
let startOffset = 0;
|
|
15
|
+
if (args.cursor) {
|
|
16
|
+
const cursorData = cursorManager.decode(args.cursor);
|
|
17
|
+
if (!cursorData) {
|
|
18
|
+
throw Errors.invalidCursor();
|
|
19
|
+
}
|
|
20
|
+
startOffset = cursorData.offset ?? 0;
|
|
21
|
+
}
|
|
22
|
+
// Get contracts by status
|
|
23
|
+
const verified = store.getVerified();
|
|
24
|
+
const mismatches = store.getMismatched();
|
|
25
|
+
const discovered = store.getDiscovered();
|
|
26
|
+
// Build contract summaries
|
|
27
|
+
let allContracts = [];
|
|
28
|
+
const mapContract = (contract, status) => ({
|
|
29
|
+
id: contract.id,
|
|
30
|
+
endpoint: contract.endpoint,
|
|
31
|
+
method: contract.method,
|
|
32
|
+
status,
|
|
33
|
+
frontendFile: contract.frontend[0]?.file,
|
|
34
|
+
backendFile: contract.backend.file,
|
|
35
|
+
mismatchCount: contract.mismatches.length,
|
|
36
|
+
});
|
|
37
|
+
// Add verified contracts
|
|
38
|
+
for (const contract of verified) {
|
|
39
|
+
allContracts.push(mapContract(contract, 'verified'));
|
|
40
|
+
}
|
|
41
|
+
// Add mismatches
|
|
42
|
+
for (const contract of mismatches) {
|
|
43
|
+
allContracts.push(mapContract(contract, 'mismatch'));
|
|
44
|
+
}
|
|
45
|
+
// Add discovered
|
|
46
|
+
for (const contract of discovered) {
|
|
47
|
+
allContracts.push(mapContract(contract, 'discovered'));
|
|
48
|
+
}
|
|
49
|
+
// Filter by status
|
|
50
|
+
if (args.status && args.status !== 'all') {
|
|
51
|
+
allContracts = allContracts.filter(c => c.status === args.status);
|
|
52
|
+
}
|
|
53
|
+
// Sort: mismatches first, then by endpoint
|
|
54
|
+
allContracts.sort((a, b) => {
|
|
55
|
+
if (a.status === 'mismatch' && b.status !== 'mismatch')
|
|
56
|
+
return -1;
|
|
57
|
+
if (b.status === 'mismatch' && a.status !== 'mismatch')
|
|
58
|
+
return 1;
|
|
59
|
+
return a.endpoint.localeCompare(b.endpoint);
|
|
60
|
+
});
|
|
61
|
+
const totalCount = allContracts.length;
|
|
62
|
+
const limit = Math.min(args.limit ?? DEFAULT_LIMIT, MAX_LIMIT);
|
|
63
|
+
// Apply pagination
|
|
64
|
+
const paginatedContracts = allContracts.slice(startOffset, startOffset + limit);
|
|
65
|
+
// Build pagination info
|
|
66
|
+
const hasMore = startOffset + limit < totalCount;
|
|
67
|
+
const pagination = {
|
|
68
|
+
hasMore,
|
|
69
|
+
totalCount,
|
|
70
|
+
pageSize: limit,
|
|
71
|
+
cursor: hasMore
|
|
72
|
+
? cursorManager.createOffsetCursor(startOffset + limit, args)
|
|
73
|
+
: undefined,
|
|
74
|
+
};
|
|
75
|
+
const stats = {
|
|
76
|
+
verified: verified.length,
|
|
77
|
+
mismatch: mismatches.length,
|
|
78
|
+
discovered: discovered.length,
|
|
79
|
+
};
|
|
80
|
+
// Build summary
|
|
81
|
+
let summary = `${totalCount} contracts: ${stats.verified} verified, ${stats.mismatch} mismatches, ${stats.discovered} discovered.`;
|
|
82
|
+
if (stats.mismatch > 0) {
|
|
83
|
+
summary += ` ⚠️ ${stats.mismatch} need attention.`;
|
|
84
|
+
}
|
|
85
|
+
const hints = {
|
|
86
|
+
nextActions: stats.mismatch > 0
|
|
87
|
+
? [
|
|
88
|
+
'Review mismatch contracts to fix API inconsistencies',
|
|
89
|
+
'Use drift_patterns_list to see API patterns',
|
|
90
|
+
]
|
|
91
|
+
: [
|
|
92
|
+
'Use drift_patterns_list to see API patterns',
|
|
93
|
+
],
|
|
94
|
+
relatedTools: ['drift_patterns_list'],
|
|
95
|
+
};
|
|
96
|
+
if (stats.mismatch > 0) {
|
|
97
|
+
hints.warnings = [`${stats.mismatch} API contracts have mismatches between frontend and backend`];
|
|
98
|
+
}
|
|
99
|
+
return builder
|
|
100
|
+
.withSummary(summary)
|
|
101
|
+
.withData({ contracts: paginatedContracts, stats })
|
|
102
|
+
.withPagination(pagination)
|
|
103
|
+
.withHints(hints)
|
|
104
|
+
.buildContent();
|
|
105
|
+
}
|
|
106
|
+
//# sourceMappingURL=contracts-list.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"contracts-list.js","sourceRoot":"","sources":["../../../src/tools/exploration/contracts-list.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* drift_files_list - File Listing
|
|
3
|
+
*
|
|
4
|
+
* Exploration tool that lists files with pattern counts.
|
|
5
|
+
* Helps find files relevant to a task.
|
|
6
|
+
*/
|
|
7
|
+
import type { ManifestStore } from 'driftdetect-core';
|
|
8
|
+
export interface FileSummary {
|
|
9
|
+
file: string;
|
|
10
|
+
patternCount: number;
|
|
11
|
+
categories: string[];
|
|
12
|
+
hasOutliers: boolean;
|
|
13
|
+
}
|
|
14
|
+
export interface FilesListData {
|
|
15
|
+
files: FileSummary[];
|
|
16
|
+
}
|
|
17
|
+
export declare function handleFilesList(store: ManifestStore, args: {
|
|
18
|
+
path?: string;
|
|
19
|
+
category?: string;
|
|
20
|
+
minPatterns?: number;
|
|
21
|
+
limit?: number;
|
|
22
|
+
cursor?: string;
|
|
23
|
+
}): Promise<{
|
|
24
|
+
content: Array<{
|
|
25
|
+
type: string;
|
|
26
|
+
text: string;
|
|
27
|
+
}>;
|
|
28
|
+
}>;
|
|
29
|
+
//# sourceMappingURL=files-list.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"files-list.d.ts","sourceRoot":"","sources":["../../../src/tools/exploration/files-list.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,KAAK,EAAE,aAAa,EAAmB,MAAM,kBAAkB,CAAC;AASvE,MAAM,WAAW,WAAW;IAC1B,IAAI,EAAE,MAAM,CAAC;IACb,YAAY,EAAE,MAAM,CAAC;IACrB,UAAU,EAAE,MAAM,EAAE,CAAC;IACrB,WAAW,EAAE,OAAO,CAAC;CACtB;AAED,MAAM,WAAW,aAAa;IAC5B,KAAK,EAAE,WAAW,EAAE,CAAC;CACtB;AAKD,wBAAsB,eAAe,CACnC,KAAK,EAAE,aAAa,EACpB,IAAI,EAAE;IACJ,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB,GACA,OAAO,CAAC;IAAE,OAAO,EAAE,KAAK,CAAC;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAA;KAAE,CAAC,CAAA;CAAE,CAAC,CAqG7D"}
|