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.
Files changed (140) hide show
  1. package/dist/bin/server.d.ts +12 -2
  2. package/dist/bin/server.d.ts.map +1 -1
  3. package/dist/bin/server.js +25 -5
  4. package/dist/bin/server.js.map +1 -1
  5. package/dist/enterprise-server.d.ts +78 -0
  6. package/dist/enterprise-server.d.ts.map +1 -0
  7. package/dist/enterprise-server.js +201 -0
  8. package/dist/enterprise-server.js.map +1 -0
  9. package/dist/index.d.ts +15 -2
  10. package/dist/index.d.ts.map +1 -1
  11. package/dist/index.js +17 -1
  12. package/dist/index.js.map +1 -1
  13. package/dist/infrastructure/cache.d.ts +86 -0
  14. package/dist/infrastructure/cache.d.ts.map +1 -0
  15. package/dist/infrastructure/cache.js +271 -0
  16. package/dist/infrastructure/cache.js.map +1 -0
  17. package/dist/infrastructure/cursor-manager.d.ts +86 -0
  18. package/dist/infrastructure/cursor-manager.d.ts.map +1 -0
  19. package/dist/infrastructure/cursor-manager.js +175 -0
  20. package/dist/infrastructure/cursor-manager.js.map +1 -0
  21. package/dist/infrastructure/error-handler.d.ts +82 -0
  22. package/dist/infrastructure/error-handler.d.ts.map +1 -0
  23. package/dist/infrastructure/error-handler.js +226 -0
  24. package/dist/infrastructure/error-handler.js.map +1 -0
  25. package/dist/infrastructure/index.d.ts +19 -0
  26. package/dist/infrastructure/index.d.ts.map +1 -0
  27. package/dist/infrastructure/index.js +26 -0
  28. package/dist/infrastructure/index.js.map +1 -0
  29. package/dist/infrastructure/metrics.d.ts +104 -0
  30. package/dist/infrastructure/metrics.d.ts.map +1 -0
  31. package/dist/infrastructure/metrics.js +291 -0
  32. package/dist/infrastructure/metrics.js.map +1 -0
  33. package/dist/infrastructure/rate-limiter.d.ts +59 -0
  34. package/dist/infrastructure/rate-limiter.d.ts.map +1 -0
  35. package/dist/infrastructure/rate-limiter.js +132 -0
  36. package/dist/infrastructure/rate-limiter.js.map +1 -0
  37. package/dist/infrastructure/response-builder.d.ts +104 -0
  38. package/dist/infrastructure/response-builder.d.ts.map +1 -0
  39. package/dist/infrastructure/response-builder.js +207 -0
  40. package/dist/infrastructure/response-builder.js.map +1 -0
  41. package/dist/infrastructure/token-estimator.d.ts +48 -0
  42. package/dist/infrastructure/token-estimator.d.ts.map +1 -0
  43. package/dist/infrastructure/token-estimator.js +131 -0
  44. package/dist/infrastructure/token-estimator.js.map +1 -0
  45. package/dist/server.d.ts.map +1 -1
  46. package/dist/server.js +1074 -17
  47. package/dist/server.js.map +1 -1
  48. package/dist/tools/detail/code-examples.d.ts +33 -0
  49. package/dist/tools/detail/code-examples.d.ts.map +1 -0
  50. package/dist/tools/detail/code-examples.js +126 -0
  51. package/dist/tools/detail/code-examples.js.map +1 -0
  52. package/dist/tools/detail/dna-check.d.ts +32 -0
  53. package/dist/tools/detail/dna-check.d.ts.map +1 -0
  54. package/dist/tools/detail/dna-check.js +231 -0
  55. package/dist/tools/detail/dna-check.js.map +1 -0
  56. package/dist/tools/detail/dna-profile.d.ts +37 -0
  57. package/dist/tools/detail/dna-profile.d.ts.map +1 -0
  58. package/dist/tools/detail/dna-profile.js +101 -0
  59. package/dist/tools/detail/dna-profile.js.map +1 -0
  60. package/dist/tools/detail/file-patterns.d.ts +39 -0
  61. package/dist/tools/detail/file-patterns.d.ts.map +1 -0
  62. package/dist/tools/detail/file-patterns.js +103 -0
  63. package/dist/tools/detail/file-patterns.js.map +1 -0
  64. package/dist/tools/detail/files-list.d.ts +30 -0
  65. package/dist/tools/detail/files-list.d.ts.map +1 -0
  66. package/dist/tools/detail/files-list.js +99 -0
  67. package/dist/tools/detail/files-list.js.map +1 -0
  68. package/dist/tools/detail/impact-analysis.d.ts +53 -0
  69. package/dist/tools/detail/impact-analysis.d.ts.map +1 -0
  70. package/dist/tools/detail/impact-analysis.js +130 -0
  71. package/dist/tools/detail/impact-analysis.js.map +1 -0
  72. package/dist/tools/detail/index.d.ts +23 -0
  73. package/dist/tools/detail/index.d.ts.map +1 -0
  74. package/dist/tools/detail/index.js +200 -0
  75. package/dist/tools/detail/index.js.map +1 -0
  76. package/dist/tools/detail/pattern-get.d.ts +45 -0
  77. package/dist/tools/detail/pattern-get.d.ts.map +1 -0
  78. package/dist/tools/detail/pattern-get.js +87 -0
  79. package/dist/tools/detail/pattern-get.js.map +1 -0
  80. package/dist/tools/detail/reachability.d.ts +60 -0
  81. package/dist/tools/detail/reachability.d.ts.map +1 -0
  82. package/dist/tools/detail/reachability.js +168 -0
  83. package/dist/tools/detail/reachability.js.map +1 -0
  84. package/dist/tools/discovery/capabilities.d.ts +28 -0
  85. package/dist/tools/discovery/capabilities.d.ts.map +1 -0
  86. package/dist/tools/discovery/capabilities.js +112 -0
  87. package/dist/tools/discovery/capabilities.js.map +1 -0
  88. package/dist/tools/discovery/index.d.ts +13 -0
  89. package/dist/tools/discovery/index.d.ts.map +1 -0
  90. package/dist/tools/discovery/index.js +30 -0
  91. package/dist/tools/discovery/index.js.map +1 -0
  92. package/dist/tools/discovery/projects.d.ts +26 -0
  93. package/dist/tools/discovery/projects.d.ts.map +1 -0
  94. package/dist/tools/discovery/projects.js +210 -0
  95. package/dist/tools/discovery/projects.js.map +1 -0
  96. package/dist/tools/discovery/status.d.ts +42 -0
  97. package/dist/tools/discovery/status.d.ts.map +1 -0
  98. package/dist/tools/discovery/status.js +157 -0
  99. package/dist/tools/discovery/status.js.map +1 -0
  100. package/dist/tools/exploration/contracts-list.d.ts +35 -0
  101. package/dist/tools/exploration/contracts-list.d.ts.map +1 -0
  102. package/dist/tools/exploration/contracts-list.js +106 -0
  103. package/dist/tools/exploration/contracts-list.js.map +1 -0
  104. package/dist/tools/exploration/files-list.d.ts +29 -0
  105. package/dist/tools/exploration/files-list.d.ts.map +1 -0
  106. package/dist/tools/exploration/files-list.js +94 -0
  107. package/dist/tools/exploration/files-list.js.map +1 -0
  108. package/dist/tools/exploration/index.d.ts +17 -0
  109. package/dist/tools/exploration/index.d.ts.map +1 -0
  110. package/dist/tools/exploration/index.js +126 -0
  111. package/dist/tools/exploration/index.js.map +1 -0
  112. package/dist/tools/exploration/patterns-list.d.ts +40 -0
  113. package/dist/tools/exploration/patterns-list.d.ts.map +1 -0
  114. package/dist/tools/exploration/patterns-list.js +172 -0
  115. package/dist/tools/exploration/patterns-list.js.map +1 -0
  116. package/dist/tools/exploration/security-summary.d.ts +49 -0
  117. package/dist/tools/exploration/security-summary.d.ts.map +1 -0
  118. package/dist/tools/exploration/security-summary.js +111 -0
  119. package/dist/tools/exploration/security-summary.js.map +1 -0
  120. package/dist/tools/exploration/trends.d.ts +49 -0
  121. package/dist/tools/exploration/trends.d.ts.map +1 -0
  122. package/dist/tools/exploration/trends.js +147 -0
  123. package/dist/tools/exploration/trends.js.map +1 -0
  124. package/dist/tools/index.d.ts +13 -0
  125. package/dist/tools/index.d.ts.map +1 -0
  126. package/dist/tools/index.js +13 -0
  127. package/dist/tools/index.js.map +1 -0
  128. package/dist/tools/orchestration/context.d.ts +72 -0
  129. package/dist/tools/orchestration/context.d.ts.map +1 -0
  130. package/dist/tools/orchestration/context.js +499 -0
  131. package/dist/tools/orchestration/context.js.map +1 -0
  132. package/dist/tools/orchestration/index.d.ts +11 -0
  133. package/dist/tools/orchestration/index.d.ts.map +1 -0
  134. package/dist/tools/orchestration/index.js +56 -0
  135. package/dist/tools/orchestration/index.js.map +1 -0
  136. package/dist/tools/registry.d.ts +41 -0
  137. package/dist/tools/registry.d.ts.map +1 -0
  138. package/dist/tools/registry.js +64 -0
  139. package/dist/tools/registry.js.map +1 -0
  140. package/package.json +3 -3
@@ -0,0 +1,271 @@
1
+ /**
2
+ * Response Cache
3
+ *
4
+ * Multi-level caching for MCP responses:
5
+ * - L1: In-memory LRU cache (fast, limited size)
6
+ * - L2: File-based cache (slower, larger, persistent)
7
+ *
8
+ * Features:
9
+ * - Automatic invalidation on pattern changes
10
+ * - TTL-based expiration
11
+ * - Cache key generation from tool + args
12
+ */
13
+ import { createHash } from 'crypto';
14
+ import * as fs from 'fs/promises';
15
+ import * as path from 'path';
16
+ const DEFAULT_CONFIG = {
17
+ l1MaxSize: 100,
18
+ l1TtlMs: 300000, // 5 minutes
19
+ l2Enabled: false,
20
+ l2TtlMs: 3600000, // 1 hour
21
+ };
22
+ /**
23
+ * Simple LRU Cache implementation
24
+ */
25
+ class LRUCache {
26
+ maxSize;
27
+ cache = new Map();
28
+ constructor(maxSize) {
29
+ this.maxSize = maxSize;
30
+ }
31
+ get(key) {
32
+ const value = this.cache.get(key);
33
+ if (value !== undefined) {
34
+ // Move to end (most recently used)
35
+ this.cache.delete(key);
36
+ this.cache.set(key, value);
37
+ }
38
+ return value;
39
+ }
40
+ set(key, value) {
41
+ // Delete if exists to update position
42
+ this.cache.delete(key);
43
+ // Evict oldest if at capacity
44
+ if (this.cache.size >= this.maxSize) {
45
+ const firstKey = this.cache.keys().next().value;
46
+ if (firstKey !== undefined) {
47
+ this.cache.delete(firstKey);
48
+ }
49
+ }
50
+ this.cache.set(key, value);
51
+ }
52
+ delete(key) {
53
+ return this.cache.delete(key);
54
+ }
55
+ clear() {
56
+ this.cache.clear();
57
+ }
58
+ has(key) {
59
+ return this.cache.has(key);
60
+ }
61
+ *entries() {
62
+ yield* this.cache.entries();
63
+ }
64
+ get size() {
65
+ return this.cache.size;
66
+ }
67
+ }
68
+ export class ResponseCache {
69
+ l1;
70
+ config;
71
+ invalidationIndex = new Map();
72
+ constructor(config = {}) {
73
+ this.config = { ...DEFAULT_CONFIG, ...config };
74
+ this.l1 = new LRUCache(this.config.l1MaxSize);
75
+ }
76
+ /**
77
+ * Get cached response
78
+ */
79
+ async get(key) {
80
+ // Try L1 first
81
+ const l1Result = this.l1.get(key);
82
+ if (l1Result && !this.isExpired(l1Result)) {
83
+ return { ...l1Result, source: 'l1' };
84
+ }
85
+ // Try L2 if enabled
86
+ if (this.config.l2Enabled && this.config.l2CacheDir) {
87
+ const l2Result = await this.getFromL2(key);
88
+ if (l2Result && !this.isExpired(l2Result)) {
89
+ // Promote to L1
90
+ this.l1.set(key, l2Result);
91
+ return { ...l2Result, source: 'l2' };
92
+ }
93
+ }
94
+ return null;
95
+ }
96
+ /**
97
+ * Set cached response
98
+ */
99
+ async set(key, data, options = {}) {
100
+ const ttlMs = options.ttlMs ?? this.config.l1TtlMs;
101
+ const now = Date.now();
102
+ const cached = {
103
+ data,
104
+ createdAt: now,
105
+ expiresAt: now + ttlMs,
106
+ invalidationKeys: options.invalidationKeys,
107
+ };
108
+ // Store in L1
109
+ this.l1.set(key, cached);
110
+ // Update invalidation index
111
+ if (options.invalidationKeys) {
112
+ for (const invKey of options.invalidationKeys) {
113
+ if (!this.invalidationIndex.has(invKey)) {
114
+ this.invalidationIndex.set(invKey, new Set());
115
+ }
116
+ this.invalidationIndex.get(invKey).add(key);
117
+ }
118
+ }
119
+ // Store in L2 if enabled
120
+ if (this.config.l2Enabled && this.config.l2CacheDir) {
121
+ await this.setToL2(key, {
122
+ ...cached,
123
+ expiresAt: now + this.config.l2TtlMs,
124
+ });
125
+ }
126
+ }
127
+ /**
128
+ * Delete cached response
129
+ */
130
+ async delete(key) {
131
+ this.l1.delete(key);
132
+ if (this.config.l2Enabled && this.config.l2CacheDir) {
133
+ await this.deleteFromL2(key);
134
+ }
135
+ }
136
+ /**
137
+ * Invalidate all caches matching an invalidation key
138
+ */
139
+ async invalidate(invalidationKey) {
140
+ const cacheKeys = this.invalidationIndex.get(invalidationKey);
141
+ if (!cacheKeys) {
142
+ return 0;
143
+ }
144
+ let count = 0;
145
+ for (const key of cacheKeys) {
146
+ await this.delete(key);
147
+ count++;
148
+ }
149
+ this.invalidationIndex.delete(invalidationKey);
150
+ return count;
151
+ }
152
+ /**
153
+ * Invalidate caches for specific categories
154
+ */
155
+ async invalidateCategories(categories) {
156
+ let count = 0;
157
+ for (const category of categories) {
158
+ count += await this.invalidate(`category:${category}`);
159
+ }
160
+ return count;
161
+ }
162
+ /**
163
+ * Invalidate all pattern-related caches
164
+ */
165
+ async invalidatePatterns() {
166
+ return this.invalidate('patterns');
167
+ }
168
+ /**
169
+ * Clear all caches
170
+ */
171
+ async clear() {
172
+ this.l1.clear();
173
+ this.invalidationIndex.clear();
174
+ if (this.config.l2Enabled && this.config.l2CacheDir) {
175
+ await this.clearL2();
176
+ }
177
+ }
178
+ /**
179
+ * Generate cache key from tool name and arguments
180
+ */
181
+ generateKey(tool, args) {
182
+ // Remove undefined values and sort keys for consistency
183
+ const normalized = Object.keys(args)
184
+ .filter(k => args[k] !== undefined)
185
+ .sort()
186
+ .reduce((acc, key) => {
187
+ acc[key] = args[key];
188
+ return acc;
189
+ }, {});
190
+ const hash = createHash('sha256')
191
+ .update(`${tool}:${JSON.stringify(normalized)}`)
192
+ .digest('hex')
193
+ .slice(0, 16);
194
+ return `drift:${tool}:${hash}`;
195
+ }
196
+ /**
197
+ * Get cache statistics
198
+ */
199
+ getStats() {
200
+ return {
201
+ l1Size: this.l1.size,
202
+ l1MaxSize: this.config.l1MaxSize,
203
+ invalidationKeys: this.invalidationIndex.size,
204
+ };
205
+ }
206
+ // Private methods
207
+ isExpired(cached) {
208
+ return Date.now() > cached.expiresAt;
209
+ }
210
+ async getFromL2(key) {
211
+ if (!this.config.l2CacheDir)
212
+ return null;
213
+ try {
214
+ const filePath = this.getL2Path(key);
215
+ const content = await fs.readFile(filePath, 'utf-8');
216
+ return JSON.parse(content);
217
+ }
218
+ catch {
219
+ return null;
220
+ }
221
+ }
222
+ async setToL2(key, cached) {
223
+ if (!this.config.l2CacheDir)
224
+ return;
225
+ try {
226
+ const filePath = this.getL2Path(key);
227
+ await fs.mkdir(path.dirname(filePath), { recursive: true });
228
+ await fs.writeFile(filePath, JSON.stringify(cached));
229
+ }
230
+ catch {
231
+ // Ignore L2 write errors
232
+ }
233
+ }
234
+ async deleteFromL2(key) {
235
+ if (!this.config.l2CacheDir)
236
+ return;
237
+ try {
238
+ const filePath = this.getL2Path(key);
239
+ await fs.unlink(filePath);
240
+ }
241
+ catch {
242
+ // Ignore if file doesn't exist
243
+ }
244
+ }
245
+ async clearL2() {
246
+ if (!this.config.l2CacheDir)
247
+ return;
248
+ try {
249
+ await fs.rm(this.config.l2CacheDir, { recursive: true, force: true });
250
+ }
251
+ catch {
252
+ // Ignore errors
253
+ }
254
+ }
255
+ getL2Path(key) {
256
+ const hash = createHash('sha256').update(key).digest('hex');
257
+ return path.join(this.config.l2CacheDir, hash.slice(0, 2), `${hash}.json`);
258
+ }
259
+ }
260
+ /**
261
+ * Create a cache instance with project-specific L2 directory
262
+ */
263
+ export function createCache(projectRoot, config = {}) {
264
+ return new ResponseCache({
265
+ ...config,
266
+ l2CacheDir: config.l2Enabled
267
+ ? path.join(projectRoot, '.drift', 'cache', 'mcp')
268
+ : undefined,
269
+ });
270
+ }
271
+ //# sourceMappingURL=cache.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cache.js","sourceRoot":"","sources":["../../src/infrastructure/cache.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,86 @@
1
+ /**
2
+ * Cursor Manager
3
+ *
4
+ * Provides stable, opaque cursor-based pagination.
5
+ * Cursors are:
6
+ * - Base64url encoded for URL safety
7
+ * - Versioned for forward compatibility
8
+ * - Time-limited to prevent stale pagination
9
+ * - Query-bound to prevent misuse
10
+ */
11
+ export interface CursorData {
12
+ lastId?: string;
13
+ lastScore?: number;
14
+ lastTimestamp?: string;
15
+ offset?: number;
16
+ queryHash: string;
17
+ createdAt: number;
18
+ version: number;
19
+ }
20
+ export interface CursorConfig {
21
+ version: number;
22
+ maxAgeMs: number;
23
+ secret?: string;
24
+ }
25
+ export declare class CursorManager {
26
+ private readonly config;
27
+ constructor(config?: Partial<CursorConfig>);
28
+ /**
29
+ * Encode cursor data to opaque string
30
+ */
31
+ encode(data: Omit<CursorData, 'createdAt' | 'version'>): string;
32
+ /**
33
+ * Decode cursor string to data
34
+ */
35
+ decode(cursor: string): CursorData | null;
36
+ /**
37
+ * Create a query hash for cursor validation
38
+ */
39
+ createQueryHash(params: Record<string, unknown>): string;
40
+ /**
41
+ * Validate that a cursor matches the current query
42
+ */
43
+ validateQueryMatch(cursor: CursorData, params: Record<string, unknown>): boolean;
44
+ /**
45
+ * Create cursor for pattern-based pagination
46
+ */
47
+ createPatternCursor(lastPattern: {
48
+ id: string;
49
+ confidence: {
50
+ score: number;
51
+ };
52
+ }, queryParams: Record<string, unknown>): string;
53
+ /**
54
+ * Create cursor for offset-based pagination (fallback)
55
+ */
56
+ createOffsetCursor(offset: number, queryParams: Record<string, unknown>): string;
57
+ /**
58
+ * Create cursor for timestamp-based pagination
59
+ */
60
+ createTimestampCursor(lastTimestamp: string | Date, lastId: string, queryParams: Record<string, unknown>): string;
61
+ /**
62
+ * Sign data with HMAC
63
+ */
64
+ private sign;
65
+ /**
66
+ * Verify HMAC signature
67
+ */
68
+ private verify;
69
+ }
70
+ /**
71
+ * Singleton instance for convenience
72
+ */
73
+ export declare const cursorManager: CursorManager;
74
+ /**
75
+ * Simple cursor creation for offset-based pagination
76
+ * Creates a lightweight cursor without query validation
77
+ */
78
+ export declare function createCursor(offset: number, limit: number): string;
79
+ /**
80
+ * Parse a simple cursor
81
+ */
82
+ export declare function parseCursor(cursor: string): {
83
+ offset: number;
84
+ limit: number;
85
+ };
86
+ //# sourceMappingURL=cursor-manager.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cursor-manager.d.ts","sourceRoot":"","sources":["../../src/infrastructure/cursor-manager.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAIH,MAAM,WAAW,UAAU;IAEzB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,MAAM,CAAC,EAAE,MAAM,CAAC;IAGhB,SAAS,EAAE,MAAM,CAAC;IAGlB,SAAS,EAAE,MAAM,CAAC;IAClB,OAAO,EAAE,MAAM,CAAC;CACjB;AAED,MAAM,WAAW,YAAY;IAC3B,OAAO,EAAE,MAAM,CAAC;IAChB,QAAQ,EAAE,MAAM,CAAC;IACjB,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAOD,qBAAa,aAAa;IACxB,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAe;gBAE1B,MAAM,GAAE,OAAO,CAAC,YAAY,CAAM;IAI9C;;OAEG;IACH,MAAM,CAAC,IAAI,EAAE,IAAI,CAAC,UAAU,EAAE,WAAW,GAAG,SAAS,CAAC,GAAG,MAAM;IAmB/D;;OAEG;IACH,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,UAAU,GAAG,IAAI;IAsCzC;;OAEG;IACH,eAAe,CAAC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,MAAM;IAexD;;OAEG;IACH,kBAAkB,CAAC,MAAM,EAAE,UAAU,EAAE,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,OAAO;IAKhF;;OAEG;IACH,mBAAmB,CACjB,WAAW,EAAE;QAAE,EAAE,EAAE,MAAM,CAAC;QAAC,UAAU,EAAE;YAAE,KAAK,EAAE,MAAM,CAAA;SAAE,CAAA;KAAE,EAC1D,WAAW,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GACnC,MAAM;IAQT;;OAEG;IACH,kBAAkB,CAChB,MAAM,EAAE,MAAM,EACd,WAAW,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GACnC,MAAM;IAOT;;OAEG;IACH,qBAAqB,CACnB,aAAa,EAAE,MAAM,GAAG,IAAI,EAC5B,MAAM,EAAE,MAAM,EACd,WAAW,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GACnC,MAAM;IAUT;;OAEG;IACH,OAAO,CAAC,IAAI;IAWZ;;OAEG;IACH,OAAO,CAAC,MAAM;CAIf;AAED;;GAEG;AACH,eAAO,MAAM,aAAa,eAAsB,CAAC;AAEjD;;;GAGG;AACH,wBAAgB,YAAY,CAAC,MAAM,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,MAAM,CAGlE;AAED;;GAEG;AACH,wBAAgB,WAAW,CAAC,MAAM,EAAE,MAAM,GAAG;IAAE,MAAM,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE,CAW7E"}
@@ -0,0 +1,175 @@
1
+ /**
2
+ * Cursor Manager
3
+ *
4
+ * Provides stable, opaque cursor-based pagination.
5
+ * Cursors are:
6
+ * - Base64url encoded for URL safety
7
+ * - Versioned for forward compatibility
8
+ * - Time-limited to prevent stale pagination
9
+ * - Query-bound to prevent misuse
10
+ */
11
+ import { createHash } from 'crypto';
12
+ const DEFAULT_CONFIG = {
13
+ version: 1,
14
+ maxAgeMs: 3600000, // 1 hour
15
+ };
16
+ export class CursorManager {
17
+ config;
18
+ constructor(config = {}) {
19
+ this.config = { ...DEFAULT_CONFIG, ...config };
20
+ }
21
+ /**
22
+ * Encode cursor data to opaque string
23
+ */
24
+ encode(data) {
25
+ const fullData = {
26
+ ...data,
27
+ createdAt: Date.now(),
28
+ version: this.config.version,
29
+ };
30
+ const json = JSON.stringify(fullData);
31
+ const encoded = Buffer.from(json).toString('base64url');
32
+ // Optionally add HMAC signature
33
+ if (this.config.secret) {
34
+ const signature = this.sign(encoded);
35
+ return `${encoded}.${signature}`;
36
+ }
37
+ return encoded;
38
+ }
39
+ /**
40
+ * Decode cursor string to data
41
+ */
42
+ decode(cursor) {
43
+ try {
44
+ let encoded = cursor;
45
+ // Verify signature if secret is configured
46
+ if (this.config.secret) {
47
+ const parts = cursor.split('.');
48
+ if (parts.length !== 2) {
49
+ return null;
50
+ }
51
+ const [data, signature] = parts;
52
+ if (!data || !signature || !this.verify(data, signature)) {
53
+ return null;
54
+ }
55
+ encoded = data;
56
+ }
57
+ const json = Buffer.from(encoded, 'base64url').toString();
58
+ const data = JSON.parse(json);
59
+ // Validate version
60
+ if (data.version !== this.config.version) {
61
+ return null;
62
+ }
63
+ // Validate age
64
+ if (Date.now() - data.createdAt > this.config.maxAgeMs) {
65
+ return null;
66
+ }
67
+ return data;
68
+ }
69
+ catch {
70
+ return null;
71
+ }
72
+ }
73
+ /**
74
+ * Create a query hash for cursor validation
75
+ */
76
+ createQueryHash(params) {
77
+ // Sort keys for consistent hashing
78
+ const sorted = Object.keys(params)
79
+ .sort()
80
+ .reduce((acc, key) => {
81
+ acc[key] = params[key];
82
+ return acc;
83
+ }, {});
84
+ return createHash('sha256')
85
+ .update(JSON.stringify(sorted))
86
+ .digest('hex')
87
+ .slice(0, 16);
88
+ }
89
+ /**
90
+ * Validate that a cursor matches the current query
91
+ */
92
+ validateQueryMatch(cursor, params) {
93
+ const currentHash = this.createQueryHash(params);
94
+ return cursor.queryHash === currentHash;
95
+ }
96
+ /**
97
+ * Create cursor for pattern-based pagination
98
+ */
99
+ createPatternCursor(lastPattern, queryParams) {
100
+ return this.encode({
101
+ lastId: lastPattern.id,
102
+ lastScore: lastPattern.confidence.score,
103
+ queryHash: this.createQueryHash(queryParams),
104
+ });
105
+ }
106
+ /**
107
+ * Create cursor for offset-based pagination (fallback)
108
+ */
109
+ createOffsetCursor(offset, queryParams) {
110
+ return this.encode({
111
+ offset,
112
+ queryHash: this.createQueryHash(queryParams),
113
+ });
114
+ }
115
+ /**
116
+ * Create cursor for timestamp-based pagination
117
+ */
118
+ createTimestampCursor(lastTimestamp, lastId, queryParams) {
119
+ return this.encode({
120
+ lastTimestamp: typeof lastTimestamp === 'string'
121
+ ? lastTimestamp
122
+ : lastTimestamp.toISOString(),
123
+ lastId,
124
+ queryHash: this.createQueryHash(queryParams),
125
+ });
126
+ }
127
+ /**
128
+ * Sign data with HMAC
129
+ */
130
+ sign(data) {
131
+ if (!this.config.secret) {
132
+ throw new Error('Secret required for signing');
133
+ }
134
+ return createHash('sha256')
135
+ .update(data + this.config.secret)
136
+ .digest('hex')
137
+ .slice(0, 16);
138
+ }
139
+ /**
140
+ * Verify HMAC signature
141
+ */
142
+ verify(data, signature) {
143
+ const expected = this.sign(data);
144
+ return expected === signature;
145
+ }
146
+ }
147
+ /**
148
+ * Singleton instance for convenience
149
+ */
150
+ export const cursorManager = new CursorManager();
151
+ /**
152
+ * Simple cursor creation for offset-based pagination
153
+ * Creates a lightweight cursor without query validation
154
+ */
155
+ export function createCursor(offset, limit) {
156
+ const data = { offset, limit, v: 1 };
157
+ return Buffer.from(JSON.stringify(data)).toString('base64url');
158
+ }
159
+ /**
160
+ * Parse a simple cursor
161
+ */
162
+ export function parseCursor(cursor) {
163
+ try {
164
+ const json = Buffer.from(cursor, 'base64url').toString();
165
+ const data = JSON.parse(json);
166
+ return {
167
+ offset: data.offset ?? 0,
168
+ limit: data.limit ?? 20,
169
+ };
170
+ }
171
+ catch {
172
+ return { offset: 0, limit: 20 };
173
+ }
174
+ }
175
+ //# sourceMappingURL=cursor-manager.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cursor-manager.js","sourceRoot":"","sources":["../../src/infrastructure/cursor-manager.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,82 @@
1
+ /**
2
+ * Enterprise Error Handler
3
+ *
4
+ * Provides structured error responses with:
5
+ * - Consistent error codes
6
+ * - Recovery suggestions for AI
7
+ * - Request tracking
8
+ */
9
+ export declare enum DriftErrorCode {
10
+ INVALID_ARGUMENT = "INVALID_ARGUMENT",
11
+ PATTERN_NOT_FOUND = "PATTERN_NOT_FOUND",
12
+ FILE_NOT_FOUND = "FILE_NOT_FOUND",
13
+ INVALID_CURSOR = "INVALID_CURSOR",
14
+ INVALID_CATEGORY = "INVALID_CATEGORY",
15
+ MISSING_REQUIRED_PARAM = "MISSING_REQUIRED_PARAM",
16
+ SCAN_REQUIRED = "SCAN_REQUIRED",
17
+ STORE_UNAVAILABLE = "STORE_UNAVAILABLE",
18
+ ANALYSIS_FAILED = "ANALYSIS_FAILED",
19
+ INTERNAL_ERROR = "INTERNAL_ERROR",
20
+ RATE_LIMITED = "RATE_LIMITED",
21
+ CALLGRAPH_NOT_BUILT = "CALLGRAPH_NOT_BUILT",
22
+ DNA_NOT_ANALYZED = "DNA_NOT_ANALYZED"
23
+ }
24
+ export interface RecoveryHint {
25
+ suggestion: string;
26
+ alternativeTools?: string[];
27
+ retryAfterMs?: number;
28
+ command?: string;
29
+ }
30
+ export interface DriftErrorDetails {
31
+ code: DriftErrorCode;
32
+ message: string;
33
+ details?: Record<string, unknown> | undefined;
34
+ recovery?: RecoveryHint | undefined;
35
+ }
36
+ export declare class DriftError extends Error {
37
+ readonly code: DriftErrorCode;
38
+ readonly details?: Record<string, unknown> | undefined;
39
+ readonly recovery?: RecoveryHint | undefined;
40
+ constructor(errorDetails: DriftErrorDetails);
41
+ /**
42
+ * Convert to MCP error response format
43
+ */
44
+ toMCPResponse(requestId?: string): {
45
+ content: Array<{
46
+ type: string;
47
+ text: string;
48
+ }>;
49
+ isError: true;
50
+ };
51
+ }
52
+ /**
53
+ * Error factory functions for common errors
54
+ */
55
+ export declare const Errors: {
56
+ invalidArgument(param: string, reason: string, suggestion?: string): DriftError;
57
+ missingRequired(param: string): DriftError;
58
+ missingParameter(param: string): DriftError;
59
+ notFound(type: string, id: string): DriftError;
60
+ invalidParameter(param: string, reason: string): DriftError;
61
+ patternNotFound(patternId: string): DriftError;
62
+ fileNotFound(path: string): DriftError;
63
+ invalidCursor(): DriftError;
64
+ invalidCategory(category: string, validCategories: string[]): DriftError;
65
+ scanRequired(): DriftError;
66
+ callgraphNotBuilt(): DriftError;
67
+ dnaNotAnalyzed(): DriftError;
68
+ rateLimited(retryAfterMs: number): DriftError;
69
+ internal(message: string, details?: Record<string, unknown>): DriftError;
70
+ custom(code: string, message: string, alternativeTools?: string[]): DriftError;
71
+ };
72
+ /**
73
+ * Error handler middleware
74
+ */
75
+ export declare function handleError(error: unknown, requestId?: string): {
76
+ content: Array<{
77
+ type: string;
78
+ text: string;
79
+ }>;
80
+ isError: true;
81
+ };
82
+ //# sourceMappingURL=error-handler.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"error-handler.d.ts","sourceRoot":"","sources":["../../src/infrastructure/error-handler.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,oBAAY,cAAc;IAExB,gBAAgB,qBAAqB;IACrC,iBAAiB,sBAAsB;IACvC,cAAc,mBAAmB;IACjC,cAAc,mBAAmB;IACjC,gBAAgB,qBAAqB;IACrC,sBAAsB,2BAA2B;IAGjD,aAAa,kBAAkB;IAC/B,iBAAiB,sBAAsB;IACvC,eAAe,oBAAoB;IACnC,cAAc,mBAAmB;IAGjC,YAAY,iBAAiB;IAG7B,mBAAmB,wBAAwB;IAC3C,gBAAgB,qBAAqB;CACtC;AAED,MAAM,WAAW,YAAY;IAC3B,UAAU,EAAE,MAAM,CAAC;IACnB,gBAAgB,CAAC,EAAE,MAAM,EAAE,CAAC;IAC5B,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAED,MAAM,WAAW,iBAAiB;IAChC,IAAI,EAAE,cAAc,CAAC;IACrB,OAAO,EAAE,MAAM,CAAC;IAChB,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,SAAS,CAAC;IAC9C,QAAQ,CAAC,EAAE,YAAY,GAAG,SAAS,CAAC;CACrC;AAED,qBAAa,UAAW,SAAQ,KAAK;IACnC,SAAgB,IAAI,EAAE,cAAc,CAAC;IACrC,SAAgB,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,SAAS,CAAC;IAC9D,SAAgB,QAAQ,CAAC,EAAE,YAAY,GAAG,SAAS,CAAC;gBAExC,YAAY,EAAE,iBAAiB;IAQ3C;;OAEG;IACH,aAAa,CAAC,SAAS,CAAC,EAAE,MAAM,GAAG;QACjC,OAAO,EAAE,KAAK,CAAC;YAAE,IAAI,EAAE,MAAM,CAAC;YAAC,IAAI,EAAE,MAAM,CAAA;SAAE,CAAC,CAAC;QAC/C,OAAO,EAAE,IAAI,CAAC;KACf;CAsBF;AAED;;GAEG;AACH,eAAO,MAAM,MAAM;2BACM,MAAM,UAAU,MAAM,eAAe,MAAM,GAAG,UAAU;2BASxD,MAAM,GAAG,UAAU;4BAWlB,MAAM,GAAG,UAAU;mBAI5B,MAAM,MAAM,MAAM,GAAG,UAAU;4BAiBtB,MAAM,UAAU,MAAM,GAAG,UAAU;+BAIhC,MAAM,GAAG,UAAU;uBAY3B,MAAM,GAAG,UAAU;qBAYrB,UAAU;8BAUD,MAAM,mBAAmB,MAAM,EAAE,GAAG,UAAU;oBAcxD,UAAU;yBAYL,UAAU;sBAWb,UAAU;8BAWF,MAAM,GAAG,UAAU;sBAW3B,MAAM,YAAY,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,UAAU;iBAW3D,MAAM,WAAW,MAAM,qBAAqB,MAAM,EAAE,GAAG,UAAU;CAU/E,CAAC;AAEF;;GAEG;AACH,wBAAgB,WAAW,CAAC,KAAK,EAAE,OAAO,EAAE,SAAS,CAAC,EAAE,MAAM,GAAG;IAC/D,OAAO,EAAE,KAAK,CAAC;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;IAC/C,OAAO,EAAE,IAAI,CAAC;CACf,CAQA"}