awesome-slash 2.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 (95) hide show
  1. package/.claude-plugin/marketplace.json +54 -0
  2. package/.claude-plugin/plugin.json +11 -0
  3. package/.mcp.json +8 -0
  4. package/CHANGELOG.md +261 -0
  5. package/LICENSE +21 -0
  6. package/README.md +363 -0
  7. package/SECURITY.md +101 -0
  8. package/adapters/README.md +256 -0
  9. package/adapters/codex/README.md +272 -0
  10. package/adapters/codex/install.sh +179 -0
  11. package/adapters/opencode/README.md +301 -0
  12. package/adapters/opencode/install.sh +223 -0
  13. package/lib/patterns/review-patterns.js +511 -0
  14. package/lib/patterns/slop-patterns.js +647 -0
  15. package/lib/platform/detect-platform.js +535 -0
  16. package/lib/platform/verify-tools.js +235 -0
  17. package/lib/state/workflow-state.js +635 -0
  18. package/lib/state/workflow-state.schema.json +282 -0
  19. package/lib/utils/context-optimizer.js +227 -0
  20. package/mcp-server/index.js +303 -0
  21. package/mcp-server/package.json +23 -0
  22. package/package.json +63 -0
  23. package/plugins/deslop-around/.claude-plugin/plugin.json +20 -0
  24. package/plugins/deslop-around/commands/deslop-around.md +220 -0
  25. package/plugins/deslop-around/lib/patterns/review-patterns.js +511 -0
  26. package/plugins/deslop-around/lib/patterns/slop-patterns.js +641 -0
  27. package/plugins/deslop-around/lib/platform/detect-platform.js +514 -0
  28. package/plugins/deslop-around/lib/platform/verify-tools.js +235 -0
  29. package/plugins/deslop-around/lib/state/workflow-state.js +635 -0
  30. package/plugins/deslop-around/lib/state/workflow-state.schema.json +282 -0
  31. package/plugins/deslop-around/lib/utils/context-optimizer.js +222 -0
  32. package/plugins/next-task/.claude-plugin/plugin.json +24 -0
  33. package/plugins/next-task/agents/ci-fixer.md +236 -0
  34. package/plugins/next-task/agents/ci-monitor.md +291 -0
  35. package/plugins/next-task/agents/delivery-validator.md +451 -0
  36. package/plugins/next-task/agents/deslop-work.md +272 -0
  37. package/plugins/next-task/agents/docs-updater.md +506 -0
  38. package/plugins/next-task/agents/exploration-agent.md +277 -0
  39. package/plugins/next-task/agents/implementation-agent.md +427 -0
  40. package/plugins/next-task/agents/planning-agent.md +236 -0
  41. package/plugins/next-task/agents/policy-selector.md +248 -0
  42. package/plugins/next-task/agents/review-orchestrator.md +521 -0
  43. package/plugins/next-task/agents/simple-fixer.md +136 -0
  44. package/plugins/next-task/agents/task-discoverer.md +357 -0
  45. package/plugins/next-task/agents/test-coverage-checker.md +447 -0
  46. package/plugins/next-task/agents/worktree-manager.md +419 -0
  47. package/plugins/next-task/commands/delivery-approval.md +331 -0
  48. package/plugins/next-task/commands/next-task.md +627 -0
  49. package/plugins/next-task/commands/update-docs-around.md +418 -0
  50. package/plugins/next-task/hooks/hooks.json +14 -0
  51. package/plugins/next-task/lib/patterns/review-patterns.js +511 -0
  52. package/plugins/next-task/lib/patterns/slop-patterns.js +641 -0
  53. package/plugins/next-task/lib/platform/detect-platform.js +514 -0
  54. package/plugins/next-task/lib/platform/verify-tools.js +235 -0
  55. package/plugins/next-task/lib/state/tasks-registry.schema.json +85 -0
  56. package/plugins/next-task/lib/state/workflow-state.js +635 -0
  57. package/plugins/next-task/lib/state/workflow-state.schema.json +282 -0
  58. package/plugins/next-task/lib/state/worktree-status.schema.json +219 -0
  59. package/plugins/next-task/lib/utils/context-optimizer.js +222 -0
  60. package/plugins/project-review/.claude-plugin/plugin.json +20 -0
  61. package/plugins/project-review/commands/project-review-agents.md +286 -0
  62. package/plugins/project-review/commands/project-review-github.md +142 -0
  63. package/plugins/project-review/commands/project-review.md +273 -0
  64. package/plugins/project-review/lib/patterns/review-patterns.js +511 -0
  65. package/plugins/project-review/lib/patterns/slop-patterns.js +641 -0
  66. package/plugins/project-review/lib/platform/detect-platform.js +514 -0
  67. package/plugins/project-review/lib/platform/verify-tools.js +235 -0
  68. package/plugins/project-review/lib/state/workflow-state.js +635 -0
  69. package/plugins/project-review/lib/state/workflow-state.schema.json +282 -0
  70. package/plugins/project-review/lib/utils/context-optimizer.js +222 -0
  71. package/plugins/reality-check/.claude-plugin/plugin.json +23 -0
  72. package/plugins/reality-check/README.md +156 -0
  73. package/plugins/reality-check/agents/code-explorer.md +353 -0
  74. package/plugins/reality-check/agents/doc-analyzer.md +337 -0
  75. package/plugins/reality-check/agents/issue-scanner.md +231 -0
  76. package/plugins/reality-check/agents/plan-synthesizer.md +479 -0
  77. package/plugins/reality-check/commands/scan.md +242 -0
  78. package/plugins/reality-check/commands/set.md +203 -0
  79. package/plugins/reality-check/lib/state/reality-check-state.js +509 -0
  80. package/plugins/reality-check/skills/reality-analysis/SKILL.md +317 -0
  81. package/plugins/ship/.claude-plugin/plugin.json +21 -0
  82. package/plugins/ship/commands/ship-ci-review-loop.md +443 -0
  83. package/plugins/ship/commands/ship-deployment.md +330 -0
  84. package/plugins/ship/commands/ship-error-handling.md +254 -0
  85. package/plugins/ship/commands/ship.md +370 -0
  86. package/plugins/ship/lib/patterns/review-patterns.js +511 -0
  87. package/plugins/ship/lib/patterns/slop-patterns.js +641 -0
  88. package/plugins/ship/lib/platform/detect-platform.js +514 -0
  89. package/plugins/ship/lib/platform/verify-tools.js +235 -0
  90. package/plugins/ship/lib/state/workflow-state.js +635 -0
  91. package/plugins/ship/lib/state/workflow-state.schema.json +282 -0
  92. package/plugins/ship/lib/utils/context-optimizer.js +222 -0
  93. package/scripts/install/claude.sh +50 -0
  94. package/scripts/install/codex.sh +181 -0
  95. package/scripts/install/opencode.sh +211 -0
@@ -0,0 +1,511 @@
1
+ /**
2
+ * Review Patterns Library
3
+ * Framework-specific code review patterns for intelligent code review
4
+ *
5
+ * These patterns guide AI agents to look for tech-stack-specific issues
6
+ *
7
+ * @author Avi Fenesh
8
+ * @license MIT
9
+ */
10
+
11
+ /**
12
+ * Deep freeze an object for V8 optimization and immutability
13
+ * @param {Object} obj - Object to freeze
14
+ * @returns {Object} Frozen object
15
+ */
16
+ function deepFreeze(obj) {
17
+ Object.keys(obj).forEach(key => {
18
+ if (typeof obj[key] === 'object' && obj[key] !== null && !(obj[key] instanceof RegExp)) {
19
+ deepFreeze(obj[key]);
20
+ }
21
+ });
22
+ return Object.freeze(obj);
23
+ }
24
+
25
+ const reviewPatterns = {
26
+ /**
27
+ * React framework patterns
28
+ */
29
+ react: {
30
+ hooks_rules: [
31
+ 'useEffect with missing dependencies in dependency array',
32
+ 'useState called inside loops or conditionally',
33
+ 'Hooks called conditionally (violates Rules of Hooks)',
34
+ 'useCallback without proper dependency array',
35
+ 'useMemo overused on cheap calculations',
36
+ 'useEffect cleanup function missing for subscriptions',
37
+ 'Stale closure bugs in useEffect/useCallback'
38
+ ],
39
+ state_management: [
40
+ 'Prop drilling deeper than 3 levels (consider Context)',
41
+ 'Redundant state that can be derived from props',
42
+ 'State updates not using functional form when depending on previous state',
43
+ 'Too many useState hooks (consider useReducer)',
44
+ 'State lifted too high in component tree',
45
+ 'Missing key prop in list rendering',
46
+ 'Mutating state directly instead of using setState'
47
+ ],
48
+ performance: [
49
+ 'Missing React.memo on expensive components',
50
+ 'Inline function/object props causing unnecessary re-renders',
51
+ 'Large objects/arrays in Context causing frequent re-renders',
52
+ 'Expensive calculations not wrapped in useMemo',
53
+ 'Component re-rendering too frequently (check React DevTools)',
54
+ 'Bundle size issues from importing entire libraries',
55
+ 'Lazy loading not used for code splitting'
56
+ ],
57
+ common_mistakes: [
58
+ 'Comparing objects/arrays in useEffect dependencies',
59
+ 'Using index as key in dynamic lists',
60
+ 'Conditional rendering with && that shows 0 instead of nothing',
61
+ 'Not handling loading and error states',
62
+ 'Forgetting to cleanup effects (memory leaks)',
63
+ 'Using findDOMNode or string refs (deprecated)'
64
+ ]
65
+ },
66
+
67
+ /**
68
+ * Vue.js framework patterns
69
+ */
70
+ vue: {
71
+ reactivity: [
72
+ 'Mutating props directly instead of emitting events',
73
+ 'Not using computed properties for derived state',
74
+ 'Reactive data not declared in data() function',
75
+ 'Using wrong reactivity API (Vue 2 vs Vue 3)',
76
+ 'Missing deep watchers when needed',
77
+ 'Overusing watchers instead of computed properties'
78
+ ],
79
+ composition_api: [
80
+ 'Ref vs reactive usage inconsistencies',
81
+ 'Forgetting .value when accessing refs',
82
+ 'Creating refs/reactive objects outside setup()',
83
+ 'Not destructuring reactive objects properly',
84
+ 'Missing proper TypeScript types for refs'
85
+ ],
86
+ performance: [
87
+ 'v-for without proper key binding',
88
+ 'Using v-for and v-if on same element',
89
+ 'Not using v-once for static content',
90
+ 'Missing keep-alive for cached components',
91
+ 'Watchers running on every keystroke without debounce'
92
+ ]
93
+ },
94
+
95
+ /**
96
+ * Angular framework patterns
97
+ */
98
+ angular: {
99
+ change_detection: [
100
+ 'Not using OnPush change detection strategy',
101
+ 'Calling functions in templates (runs on every change detection)',
102
+ 'Not using trackBy in ngFor for large lists',
103
+ 'Subscriptions not unsubscribed (memory leaks)',
104
+ 'Manual change detection triggers overused'
105
+ ],
106
+ rxjs: [
107
+ 'Not unsubscribing from observables',
108
+ 'Using subscribe() instead of async pipe in templates',
109
+ 'Not using switchMap/mergeMap/concatMap correctly',
110
+ 'Nested subscriptions (callback hell)',
111
+ 'Missing error handling in subscribe()',
112
+ 'Not using takeUntil for cleanup'
113
+ ],
114
+ dependency_injection: [
115
+ 'Services not marked with @Injectable()',
116
+ 'Injecting in constructors instead of using inject() function',
117
+ 'Missing providedIn metadata for tree-shaking',
118
+ 'Circular dependencies between services'
119
+ ]
120
+ },
121
+
122
+ /**
123
+ * Python/Django framework patterns
124
+ */
125
+ django: {
126
+ orm: [
127
+ 'Raw SQL without parameterization (SQL injection risk)',
128
+ 'N+1 queries (missing select_related/prefetch_related)',
129
+ 'Synchronous database calls in async views',
130
+ 'Using filter().count() instead of exists()',
131
+ 'Not using bulk_create for multiple inserts',
132
+ 'Missing database indexes on frequently queried fields',
133
+ 'Using get() without DoesNotExist exception handling'
134
+ ],
135
+ views: [
136
+ 'Missing CSRF protection on forms',
137
+ 'Not validating form data properly',
138
+ 'Using GET requests for state-changing operations',
139
+ 'Missing permission checks on views',
140
+ 'Returning raw HTML instead of using templates',
141
+ 'Not handling common HTTP status codes properly'
142
+ ],
143
+ models: [
144
+ 'Missing __str__ method on models',
145
+ 'Not setting related_name on ForeignKey',
146
+ 'Mutable default arguments (default=[] or default={})',
147
+ 'Missing unique_together or Meta options',
148
+ 'Using TextField instead of CharField with max_length',
149
+ 'Missing choices for status fields'
150
+ ],
151
+ security: [
152
+ 'DEBUG=True in production',
153
+ 'SECRET_KEY hardcoded or in version control',
154
+ 'Missing ALLOWED_HOSTS configuration',
155
+ 'Using eval() or exec() with user input',
156
+ 'Not using Django ORM parameterization',
157
+ 'Missing rate limiting on sensitive endpoints'
158
+ ]
159
+ },
160
+
161
+ /**
162
+ * FastAPI framework patterns
163
+ */
164
+ fastapi: {
165
+ async_patterns: [
166
+ 'Mixing async and sync operations incorrectly',
167
+ 'Using blocking I/O in async endpoints',
168
+ 'Not using await with async database calls',
169
+ 'Creating sync database sessions in async context',
170
+ 'Missing async database driver'
171
+ ],
172
+ validation: [
173
+ 'Not using Pydantic models for request validation',
174
+ 'Missing response models',
175
+ 'Not validating query parameters',
176
+ 'Returning raw dictionaries instead of models',
177
+ 'Missing field validators for complex validation'
178
+ ],
179
+ dependencies: [
180
+ 'Dependency injection not used for database sessions',
181
+ 'Not using Depends() for authentication',
182
+ 'Missing dependency override for testing',
183
+ 'Expensive operations in dependencies without caching'
184
+ ]
185
+ },
186
+
187
+ /**
188
+ * Rust patterns
189
+ */
190
+ rust: {
191
+ safety: [
192
+ 'Unsafe blocks without clear justification comment',
193
+ 'Excessive use of unwrap() or expect() (prefer error handling)',
194
+ 'Clone used when reference borrowing would work',
195
+ 'Manual memory management when safe abstractions available',
196
+ 'Transmute usage without clear safety invariants',
197
+ 'Raw pointer dereferencing without bounds checking'
198
+ ],
199
+ error_handling: [
200
+ 'Using panic! in library code',
201
+ 'Not implementing Error trait for custom errors',
202
+ 'Ignoring Result types with underscore',
203
+ 'Using unwrap() in production code paths',
204
+ 'Missing ? operator for error propagation',
205
+ 'Not providing context in error messages'
206
+ ],
207
+ performance: [
208
+ 'Unnecessary Vec allocations (use slices or arrays)',
209
+ 'String concatenation in loops (use String::with_capacity)',
210
+ 'Missing #[inline] on small hot functions',
211
+ 'Not using iterators (manual loops)',
212
+ 'Cloning when into() would transfer ownership',
213
+ 'Not using Cow for conditional copying'
214
+ ],
215
+ async_rust: [
216
+ 'Blocking operations in async functions',
217
+ 'Not using tokio::spawn for CPU-intensive work',
218
+ 'Missing Send bounds on async trait methods',
219
+ 'Holding locks across await points',
220
+ 'Not using async-friendly versions of std types'
221
+ ]
222
+ },
223
+
224
+ /**
225
+ * Go patterns
226
+ */
227
+ go: {
228
+ concurrency: [
229
+ 'Goroutines without context cancellation',
230
+ 'Mutex not unlocked in defer',
231
+ 'Channels not closed properly',
232
+ 'Race conditions in tests',
233
+ 'WaitGroup.Add() called in wrong goroutine',
234
+ 'Goroutine leaks (no cleanup mechanism)',
235
+ 'Using global variables in concurrent code'
236
+ ],
237
+ error_handling: [
238
+ 'Ignored errors (using _ for error returns)',
239
+ 'Error strings start with capital letter (go convention)',
240
+ 'Not using fmt.Errorf with %w for error wrapping',
241
+ 'Panic instead of returning error',
242
+ 'Not checking errors from Close() or Flush()',
243
+ 'Using panic/recover for control flow'
244
+ ],
245
+ performance: [
246
+ 'String concatenation in loops (use strings.Builder)',
247
+ 'Not reusing buffers for repeated operations',
248
+ 'Inefficient JSON marshaling in hot paths',
249
+ 'Missing connection pooling for databases',
250
+ 'Reflection used unnecessarily',
251
+ 'Not using sync.Pool for frequent allocations'
252
+ ],
253
+ best_practices: [
254
+ 'Not using go fmt / go vet',
255
+ 'Accepting interfaces, returning structs violation',
256
+ 'Not embedding errors context',
257
+ 'Using init() function unnecessarily',
258
+ 'Exporting more than necessary',
259
+ 'Not following effective Go guidelines'
260
+ ]
261
+ },
262
+
263
+ /**
264
+ * Express.js (Node.js) patterns
265
+ */
266
+ express: {
267
+ async_handling: [
268
+ 'Async route handlers not wrapped in try-catch',
269
+ 'Not using async error handling middleware',
270
+ 'Promises not awaited properly',
271
+ 'Missing error handling in Promise chains',
272
+ 'Sync code blocking event loop'
273
+ ],
274
+ security: [
275
+ 'Missing helmet middleware',
276
+ 'No rate limiting on sensitive endpoints',
277
+ 'CORS configured too permissively',
278
+ 'User input not sanitized',
279
+ 'SQL queries not parameterized',
280
+ 'Passwords not hashed with bcrypt',
281
+ 'Missing HTTPS in production',
282
+ 'Exposing stack traces in production'
283
+ ],
284
+ middleware: [
285
+ 'Middleware order issues (e.g., body-parser position)',
286
+ 'Not calling next() in middleware',
287
+ 'Error middleware not having 4 parameters',
288
+ 'Missing catch-all error handler',
289
+ 'Middleware not handling async errors'
290
+ ]
291
+ }
292
+ };
293
+
294
+ // Freeze the patterns object for V8 optimization
295
+ deepFreeze(reviewPatterns);
296
+
297
+ // ============================================================================
298
+ // Pre-indexed Maps for O(1) lookup performance (#18)
299
+ // Built once at module load time, avoiding iteration on every lookup
300
+ // ============================================================================
301
+
302
+ /**
303
+ * Pre-indexed patterns by category across all frameworks
304
+ * Key: category name (e.g., 'security', 'performance', 'error_handling')
305
+ * Value: Map of framework -> array of patterns
306
+ */
307
+ const _patternsByCategory = new Map();
308
+
309
+ /**
310
+ * Set of all frameworks for O(1) existence check
311
+ */
312
+ const _frameworksSet = new Set(Object.keys(reviewPatterns));
313
+
314
+ /**
315
+ * Set of all categories across all frameworks
316
+ */
317
+ const _categoriesSet = new Set();
318
+
319
+ /**
320
+ * Count of patterns per framework for quick stats
321
+ */
322
+ const _patternCountByFramework = new Map();
323
+
324
+ /**
325
+ * Flattened pattern index for full-text search
326
+ * Key: framework
327
+ * Value: array of { category, pattern } for all patterns
328
+ */
329
+ const _flattenedPatterns = new Map();
330
+
331
+ // Build indexes at module load time
332
+ (function buildIndexes() {
333
+ for (const [framework, categories] of Object.entries(reviewPatterns)) {
334
+ let totalPatterns = 0;
335
+ const flattened = [];
336
+
337
+ for (const [category, patterns] of Object.entries(categories)) {
338
+ _categoriesSet.add(category);
339
+
340
+ // Index by category
341
+ if (!_patternsByCategory.has(category)) {
342
+ _patternsByCategory.set(category, new Map());
343
+ }
344
+ _patternsByCategory.get(category).set(framework, patterns);
345
+
346
+ // Count patterns
347
+ totalPatterns += patterns.length;
348
+
349
+ // Flatten for search
350
+ for (const pattern of patterns) {
351
+ flattened.push({ category, pattern });
352
+ }
353
+ }
354
+
355
+ _patternCountByFramework.set(framework, totalPatterns);
356
+ _flattenedPatterns.set(framework, flattened);
357
+ }
358
+ })();
359
+
360
+ // Freeze the index Sets
361
+ Object.freeze(_frameworksSet);
362
+ Object.freeze(_categoriesSet);
363
+
364
+ /**
365
+ * Get review patterns for a detected framework (O(1) lookup)
366
+ * @param {string} framework - Framework name
367
+ * @returns {Object|null} Patterns for framework or null if not found
368
+ */
369
+ function getPatternsForFramework(framework) {
370
+ if (typeof framework !== 'string') return null;
371
+ return reviewPatterns[framework.toLowerCase()] || null;
372
+ }
373
+
374
+ /**
375
+ * Get patterns for a specific category across all frameworks
376
+ * @param {string} category - Category name (e.g., 'security', 'performance')
377
+ * @returns {Map<string, Array>} Map of framework -> patterns for that category
378
+ */
379
+ function getPatternsByCategory(category) {
380
+ return _patternsByCategory.get(category) || new Map();
381
+ }
382
+
383
+ /**
384
+ * Get patterns for a framework and category combination (O(1) lookup)
385
+ * @param {string} framework - Framework name
386
+ * @param {string} category - Category name
387
+ * @returns {Array|null} Array of pattern strings or null
388
+ */
389
+ function getPatternsForFrameworkCategory(framework, category) {
390
+ const frameworkPatterns = reviewPatterns[framework.toLowerCase()];
391
+ if (!frameworkPatterns) return null;
392
+ return frameworkPatterns[category] || null;
393
+ }
394
+
395
+ /**
396
+ * Get all available frameworks (O(1) via pre-computed Set)
397
+ * @returns {Array<string>} List of framework names
398
+ */
399
+ function getAvailableFrameworks() {
400
+ return Array.from(_frameworksSet);
401
+ }
402
+
403
+ /**
404
+ * Get all available categories across all frameworks
405
+ * @returns {Array<string>} List of category names
406
+ */
407
+ function getAvailableCategories() {
408
+ return Array.from(_categoriesSet);
409
+ }
410
+
411
+ /**
412
+ * Get categories available for a specific framework
413
+ * @param {string} framework - Framework name
414
+ * @returns {Array<string>} List of category names for the framework
415
+ */
416
+ function getCategoriesForFramework(framework) {
417
+ const frameworkPatterns = reviewPatterns[framework.toLowerCase()];
418
+ if (!frameworkPatterns) return [];
419
+ return Object.keys(frameworkPatterns);
420
+ }
421
+
422
+ /**
423
+ * Check if patterns exist for a framework (O(1) lookup)
424
+ * @param {string} framework - Framework name
425
+ * @returns {boolean} True if patterns available
426
+ */
427
+ function hasPatternsFor(framework) {
428
+ if (typeof framework !== 'string') return false;
429
+ return _frameworksSet.has(framework.toLowerCase());
430
+ }
431
+
432
+ /**
433
+ * Check if a category exists across any framework (O(1) lookup)
434
+ * @param {string} category - Category name
435
+ * @returns {boolean} True if category exists
436
+ */
437
+ function hasCategory(category) {
438
+ return _categoriesSet.has(category);
439
+ }
440
+
441
+ /**
442
+ * Get pattern count for a framework
443
+ * @param {string} framework - Framework name
444
+ * @returns {number} Number of patterns
445
+ */
446
+ function getPatternCount(framework) {
447
+ return _patternCountByFramework.get(framework.toLowerCase()) || 0;
448
+ }
449
+
450
+ /**
451
+ * Get total pattern count across all frameworks
452
+ * @returns {number} Total pattern count
453
+ */
454
+ function getTotalPatternCount() {
455
+ let total = 0;
456
+ for (const count of _patternCountByFramework.values()) {
457
+ total += count;
458
+ }
459
+ return total;
460
+ }
461
+
462
+ /**
463
+ * Search patterns by keyword across all frameworks
464
+ * @param {string} keyword - Search term (case-insensitive)
465
+ * @returns {Array<{framework: string, category: string, pattern: string}>} Matching patterns
466
+ */
467
+ function searchPatterns(keyword) {
468
+ const lowerKeyword = keyword.toLowerCase();
469
+ const results = [];
470
+
471
+ for (const [framework, patterns] of _flattenedPatterns) {
472
+ for (const { category, pattern } of patterns) {
473
+ if (pattern.toLowerCase().includes(lowerKeyword)) {
474
+ results.push({ framework, category, pattern });
475
+ }
476
+ }
477
+ }
478
+
479
+ return results;
480
+ }
481
+
482
+ /**
483
+ * Get frameworks that have a specific category
484
+ * @param {string} category - Category name
485
+ * @returns {Array<string>} List of frameworks with this category
486
+ */
487
+ function getFrameworksWithCategory(category) {
488
+ const categoryMap = _patternsByCategory.get(category);
489
+ if (!categoryMap) return [];
490
+ return Array.from(categoryMap.keys());
491
+ }
492
+
493
+ module.exports = {
494
+ reviewPatterns,
495
+ // Pre-indexed lookup functions (O(1) performance)
496
+ getPatternsForFramework,
497
+ getPatternsByCategory,
498
+ getPatternsForFrameworkCategory,
499
+ // Metadata functions
500
+ getAvailableFrameworks,
501
+ getAvailableCategories,
502
+ getCategoriesForFramework,
503
+ hasPatternsFor,
504
+ hasCategory,
505
+ // Stats functions
506
+ getPatternCount,
507
+ getTotalPatternCount,
508
+ // Search functions
509
+ searchPatterns,
510
+ getFrameworksWithCategory
511
+ };