@loxia-labs/loxia-autopilot-one 1.0.1 → 1.0.4

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 (120) hide show
  1. package/README.md +44 -54
  2. package/bin/cli.js +1 -115
  3. package/bin/loxia-terminal-v2.js +3 -0
  4. package/bin/loxia-terminal.js +3 -0
  5. package/bin/start-with-terminal.js +3 -0
  6. package/package.json +15 -15
  7. package/scripts/install-scanners.js +1 -235
  8. package/src/analyzers/CSSAnalyzer.js +1 -297
  9. package/src/analyzers/ConfigValidator.js +1 -690
  10. package/src/analyzers/ESLintAnalyzer.js +1 -320
  11. package/src/analyzers/JavaScriptAnalyzer.js +1 -261
  12. package/src/analyzers/PrettierFormatter.js +1 -247
  13. package/src/analyzers/PythonAnalyzer.js +1 -266
  14. package/src/analyzers/SecurityAnalyzer.js +1 -729
  15. package/src/analyzers/TypeScriptAnalyzer.js +1 -247
  16. package/src/analyzers/codeCloneDetector/analyzer.js +1 -344
  17. package/src/analyzers/codeCloneDetector/detector.js +1 -203
  18. package/src/analyzers/codeCloneDetector/index.js +1 -160
  19. package/src/analyzers/codeCloneDetector/parser.js +1 -199
  20. package/src/analyzers/codeCloneDetector/reporter.js +1 -148
  21. package/src/analyzers/codeCloneDetector/scanner.js +1 -59
  22. package/src/core/agentPool.js +1 -1474
  23. package/src/core/agentScheduler.js +1 -2147
  24. package/src/core/contextManager.js +1 -709
  25. package/src/core/messageProcessor.js +1 -732
  26. package/src/core/orchestrator.js +1 -548
  27. package/src/core/stateManager.js +1 -877
  28. package/src/index.js +1 -631
  29. package/src/interfaces/cli.js +1 -549
  30. package/src/interfaces/terminal/__tests__/smoke/advancedFeatures.test.js +1 -0
  31. package/src/interfaces/terminal/__tests__/smoke/agentControl.test.js +1 -0
  32. package/src/interfaces/terminal/__tests__/smoke/agents.test.js +1 -0
  33. package/src/interfaces/terminal/__tests__/smoke/components.test.js +1 -0
  34. package/src/interfaces/terminal/__tests__/smoke/connection.test.js +1 -0
  35. package/src/interfaces/terminal/__tests__/smoke/enhancements.test.js +1 -0
  36. package/src/interfaces/terminal/__tests__/smoke/imports.test.js +1 -0
  37. package/src/interfaces/terminal/__tests__/smoke/messages.test.js +1 -0
  38. package/src/interfaces/terminal/__tests__/smoke/tools.test.js +1 -0
  39. package/src/interfaces/terminal/api/apiClient.js +1 -0
  40. package/src/interfaces/terminal/api/messageRouter.js +1 -0
  41. package/src/interfaces/terminal/api/session.js +1 -0
  42. package/src/interfaces/terminal/api/websocket.js +1 -0
  43. package/src/interfaces/terminal/components/AgentCreator.js +1 -0
  44. package/src/interfaces/terminal/components/AgentEditor.js +1 -0
  45. package/src/interfaces/terminal/components/AgentSwitcher.js +1 -0
  46. package/src/interfaces/terminal/components/ErrorBoundary.js +1 -0
  47. package/src/interfaces/terminal/components/ErrorPanel.js +1 -0
  48. package/src/interfaces/terminal/components/Header.js +1 -0
  49. package/src/interfaces/terminal/components/HelpPanel.js +1 -0
  50. package/src/interfaces/terminal/components/InputBox.js +1 -0
  51. package/src/interfaces/terminal/components/Layout.js +1 -0
  52. package/src/interfaces/terminal/components/LoadingSpinner.js +1 -0
  53. package/src/interfaces/terminal/components/MessageList.js +1 -0
  54. package/src/interfaces/terminal/components/MultilineTextInput.js +1 -0
  55. package/src/interfaces/terminal/components/SearchPanel.js +1 -0
  56. package/src/interfaces/terminal/components/SettingsPanel.js +1 -0
  57. package/src/interfaces/terminal/components/StatusBar.js +1 -0
  58. package/src/interfaces/terminal/components/TextInput.js +1 -0
  59. package/src/interfaces/terminal/config/agentEditorConstants.js +1 -0
  60. package/src/interfaces/terminal/config/constants.js +1 -0
  61. package/src/interfaces/terminal/index.js +1 -0
  62. package/src/interfaces/terminal/state/useAgentControl.js +1 -0
  63. package/src/interfaces/terminal/state/useAgents.js +1 -0
  64. package/src/interfaces/terminal/state/useConnection.js +1 -0
  65. package/src/interfaces/terminal/state/useMessages.js +1 -0
  66. package/src/interfaces/terminal/state/useTools.js +1 -0
  67. package/src/interfaces/terminal/utils/debugLogger.js +1 -0
  68. package/src/interfaces/terminal/utils/settingsStorage.js +1 -0
  69. package/src/interfaces/terminal/utils/theme.js +1 -0
  70. package/src/interfaces/webServer.js +1 -2162
  71. package/src/modules/fileExplorer/controller.js +1 -280
  72. package/src/modules/fileExplorer/index.js +1 -37
  73. package/src/modules/fileExplorer/middleware.js +1 -92
  74. package/src/modules/fileExplorer/routes.js +1 -125
  75. package/src/modules/fileExplorer/types.js +1 -44
  76. package/src/services/aiService.js +1 -1232
  77. package/src/services/apiKeyManager.js +1 -164
  78. package/src/services/benchmarkService.js +1 -366
  79. package/src/services/budgetService.js +1 -539
  80. package/src/services/contextInjectionService.js +1 -247
  81. package/src/services/conversationCompactionService.js +1 -637
  82. package/src/services/errorHandler.js +1 -810
  83. package/src/services/fileAttachmentService.js +1 -544
  84. package/src/services/modelRouterService.js +1 -366
  85. package/src/services/modelsService.js +1 -322
  86. package/src/services/qualityInspector.js +1 -796
  87. package/src/services/tokenCountingService.js +1 -536
  88. package/src/tools/agentCommunicationTool.js +1 -1344
  89. package/src/tools/agentDelayTool.js +1 -485
  90. package/src/tools/asyncToolManager.js +1 -604
  91. package/src/tools/baseTool.js +1 -800
  92. package/src/tools/browserTool.js +1 -920
  93. package/src/tools/cloneDetectionTool.js +1 -621
  94. package/src/tools/dependencyResolverTool.js +1 -1215
  95. package/src/tools/fileContentReplaceTool.js +1 -875
  96. package/src/tools/fileSystemTool.js +1 -1107
  97. package/src/tools/fileTreeTool.js +1 -853
  98. package/src/tools/imageTool.js +1 -901
  99. package/src/tools/importAnalyzerTool.js +1 -1060
  100. package/src/tools/jobDoneTool.js +1 -248
  101. package/src/tools/seekTool.js +1 -956
  102. package/src/tools/staticAnalysisTool.js +1 -1778
  103. package/src/tools/taskManagerTool.js +1 -2873
  104. package/src/tools/terminalTool.js +1 -2304
  105. package/src/tools/webTool.js +1 -1430
  106. package/src/types/agent.js +1 -519
  107. package/src/types/contextReference.js +1 -972
  108. package/src/types/conversation.js +1 -730
  109. package/src/types/toolCommand.js +1 -747
  110. package/src/utilities/attachmentValidator.js +1 -292
  111. package/src/utilities/configManager.js +1 -582
  112. package/src/utilities/constants.js +1 -722
  113. package/src/utilities/directoryAccessManager.js +1 -535
  114. package/src/utilities/fileProcessor.js +1 -307
  115. package/src/utilities/logger.js +1 -436
  116. package/src/utilities/tagParser.js +1 -1246
  117. package/src/utilities/toolConstants.js +1 -317
  118. package/web-ui/build/index.html +2 -2
  119. package/web-ui/build/static/{index-Dy2bYbOa.css → index-CClD1090.css} +1 -1
  120. package/web-ui/build/static/{index-CjkkcnFA.js → index-lCBai6dX.js} +66 -67
@@ -1,621 +1 @@
1
- /**
2
- * CloneDetectionTool - Detect duplicated code (code clones) for refactoring
3
- *
4
- * Purpose:
5
- * - Identify exact and similar code clones across the codebase
6
- * - Provide refactoring recommendations with priorities
7
- * - Help reduce technical debt and improve maintainability
8
- * - Support JavaScript, TypeScript, JSX, TSX, Vue files
9
- */
10
-
11
- import { BaseTool } from './baseTool.js';
12
- import TagParser from '../utilities/tagParser.js';
13
- import DirectoryAccessManager from '../utilities/directoryAccessManager.js';
14
- import path from 'path';
15
-
16
- import {
17
- TOOL_STATUS,
18
- SYSTEM_DEFAULTS
19
- } from '../utilities/constants.js';
20
-
21
- class CloneDetectionTool extends BaseTool {
22
- constructor(config = {}, logger = null) {
23
- super(config, logger);
24
-
25
- // Tool metadata
26
- this.requiresProject = true;
27
- this.isAsync = false;
28
- this.timeout = config.timeout || 120000; // 2 minutes default
29
- this.maxConcurrentOperations = config.maxConcurrentOperations || 1;
30
-
31
- // Clone detection settings
32
- this.defaultMinTokens = config.defaultMinTokens || 50;
33
- this.defaultMinLines = config.defaultMinLines || 5;
34
- this.defaultSimilarityThreshold = config.defaultSimilarityThreshold || 0.85;
35
- this.maxFileSize = config.maxFileSize || 500000; // 500KB per file
36
-
37
- // Directory access manager
38
- this.directoryAccessManager = new DirectoryAccessManager(config, logger);
39
-
40
- // Clone detector will be initialized lazily when needed
41
- this.cloneDetector = null;
42
- }
43
-
44
- /**
45
- * Get tool description for LLM consumption
46
- * @returns {string} Tool description
47
- */
48
- getDescription() {
49
- return `
50
- Code Clone Detection Tool: Find duplicated code for refactoring opportunities
51
-
52
- This tool identifies exact and similar code patterns (code clones) across your codebase to help reduce duplication, improve maintainability, and identify refactoring opportunities.
53
-
54
- WHAT IT DETECTS:
55
- - Exact Clones (Type 1): Identical code with different formatting/comments
56
- - Similar Clones (Type 2/3): Structurally similar code with minor variations
57
-
58
- SUPPORTED LANGUAGES:
59
- - JavaScript (.js, .jsx, .mjs, .cjs)
60
- - TypeScript (.ts, .tsx)
61
- - Vue (.vue)
62
-
63
- USAGE - XML FORMAT:
64
-
65
- Detect clones in entire directory:
66
- [tool id="clonedetection"]
67
- <detect-clones directory="." />
68
- [/tool]
69
-
70
- Detect clones in specific directory:
71
- [tool id="clonedetection"]
72
- <detect-clones directory="src/services" />
73
- [/tool]
74
-
75
- Custom sensitivity (lower minTokens = more sensitive):
76
- [tool id="clonedetection"]
77
- <detect-clones directory="src" min-tokens="30" min-lines="5" />
78
- [/tool]
79
-
80
- Filter by priority:
81
- [tool id="clonedetection"]
82
- <detect-clones directory="." priority-filter="high" max-results="5" />
83
- [/tool]
84
-
85
- Get summary only:
86
- [tool id="clonedetection"]
87
- <detect-clones directory="." output-mode="summary" />
88
- [/tool]
89
-
90
- USAGE - JSON FORMAT:
91
-
92
- \`\`\`json
93
- {
94
- "toolId": "clonedetection",
95
- "actions": [
96
- {
97
- "type": "detect-clones",
98
- "directory": "src",
99
- "minTokens": 50,
100
- "minLines": 5,
101
- "similarityThreshold": 0.85,
102
- "priorityFilter": "high",
103
- "maxResults": 10,
104
- "outputMode": "summary"
105
- }
106
- ]
107
- }
108
- \`\`\`
109
-
110
- PARAMETERS:
111
- - directory: Directory to analyze (required)
112
- - min-tokens: Minimum token count (default: 50, lower = more sensitive)
113
- - min-lines: Minimum line count (default: 5)
114
- - similarity-threshold: 0-1 similarity threshold (default: 0.85)
115
- - priority-filter: Filter by priority (high/medium/low, optional)
116
- - max-results: Maximum number of clones to return (optional)
117
- - output-mode: summary|detailed|recommendations (default: detailed)
118
-
119
- OUTPUT FORMAT:
120
- Returns clone detection results with:
121
- - summary: Overall statistics (total clones, duplication %, priority breakdown)
122
- - clones: Array of detected clone groups
123
- - id: Clone identifier
124
- - type: exact | similar
125
- - confidence: Detection confidence (0-1)
126
- - instances: Array of code locations with file paths and line numbers
127
- - metrics: tokenCount, lineCount, instanceCount, impactScore, filesCovered
128
- - refactoringAdvice:
129
- - priority: high | medium | low
130
- - strategy: extract-function | extract-class | extract-module | extract-constant
131
- - suggestedName: Recommended name for extracted code
132
- - reasoning: Why this refactoring is recommended
133
- - estimatedEffort: low | medium | high
134
- - benefits: Array of benefits
135
- - actionableSteps: Step-by-step refactoring instructions
136
-
137
- OUTPUT MODES:
138
- - summary: High-level overview only (duplication %, top 5 clones)
139
- - detailed: Full clone details with code snippets (default)
140
- - recommendations: Refactoring priorities with actionable steps
141
-
142
- DETECTION ALGORITHM:
143
- - Uses AST (Abstract Syntax Tree) parsing via Babel
144
- - Token-based similarity with normalization
145
- - Longest Common Subsequence (LCS) algorithm for similarity
146
- - Configurable sensitivity and thresholds
147
-
148
- EXAMPLES:
149
-
150
- Find all clones in project:
151
- [tool id="clonedetection"]
152
- <detect-clones directory="." />
153
- [/tool]
154
-
155
- High-priority refactoring opportunities only:
156
- [tool id="clonedetection"]
157
- <detect-clones directory="src" priority-filter="high" max-results="10" />
158
- [/tool]
159
-
160
- More sensitive detection (finds smaller clones):
161
- [tool id="clonedetection"]
162
- <detect-clones directory="." min-tokens="30" similarity-threshold="0.80" />
163
- [/tool]
164
-
165
- Quick overview:
166
- [tool id="clonedetection"]
167
- <detect-clones directory="." output-mode="summary" />
168
- [/tool]
169
-
170
- LIMITATIONS:
171
- - Analyzes JavaScript/TypeScript family only
172
- - Performance depends on codebase size (500ms per file typical)
173
- - Maximum file size: ${Math.round(this.maxFileSize / 1024)}KB per file
174
- - Analysis timeout: ${this.timeout / 1000} seconds
175
-
176
- USE CASES:
177
- - Identify refactoring opportunities before code review
178
- - Track technical debt and code duplication metrics
179
- - Find candidates for DRY (Don't Repeat Yourself) refactoring
180
- - Prioritize maintenance work by impact score
181
- `;
182
- }
183
-
184
- /**
185
- * Parse parameters from tool command content
186
- * @param {string} content - Raw tool command content
187
- * @returns {Object} Parsed parameters
188
- */
189
- parseParameters(content) {
190
- try {
191
- const params = {};
192
- const actions = [];
193
-
194
- this.logger?.debug('CloneDetection tool parsing parameters', {
195
- contentLength: content.length,
196
- contentPreview: content.substring(0, 200)
197
- });
198
-
199
- // Extract self-closing <detect-clones> tags
200
- const detectClonesPattern = /<detect-clones\s+(.+?)\/>/g;
201
- let match;
202
-
203
- while ((match = detectClonesPattern.exec(content)) !== null) {
204
- const attributeString = match[1].trim();
205
- const parser = new TagParser();
206
- const attributes = parser.parseAttributes(attributeString);
207
-
208
- const action = {
209
- type: 'detect-clones',
210
- ...attributes
211
- };
212
-
213
- // Normalize attribute names
214
- if (action['min-tokens']) {
215
- action.minTokens = parseInt(action['min-tokens'], 10);
216
- delete action['min-tokens'];
217
- }
218
- if (action['min-lines']) {
219
- action.minLines = parseInt(action['min-lines'], 10);
220
- delete action['min-lines'];
221
- }
222
- if (action['similarity-threshold']) {
223
- action.similarityThreshold = parseFloat(action['similarity-threshold']);
224
- delete action['similarity-threshold'];
225
- }
226
- if (action['priority-filter']) {
227
- action.priorityFilter = action['priority-filter'];
228
- delete action['priority-filter'];
229
- }
230
- if (action['max-results']) {
231
- action.maxResults = parseInt(action['max-results'], 10);
232
- delete action['max-results'];
233
- }
234
- if (action['output-mode']) {
235
- action.outputMode = action['output-mode'];
236
- delete action['output-mode'];
237
- }
238
-
239
- actions.push(action);
240
- }
241
-
242
- params.actions = actions;
243
- params.rawContent = content.trim();
244
-
245
- this.logger?.debug('Parsed CloneDetection tool parameters', {
246
- totalActions: actions.length,
247
- actionTypes: actions.map(a => a.type)
248
- });
249
-
250
- return params;
251
-
252
- } catch (error) {
253
- throw new Error(`Failed to parse clone detection parameters: ${error.message}`);
254
- }
255
- }
256
-
257
- /**
258
- * Get required parameters
259
- * @returns {Array<string>} Array of required parameter names
260
- */
261
- getRequiredParameters() {
262
- return ['actions'];
263
- }
264
-
265
- /**
266
- * Custom parameter validation
267
- * @param {Object} params - Parameters to validate
268
- * @returns {Object} Validation result
269
- */
270
- customValidateParameters(params) {
271
- const errors = [];
272
-
273
- if (!params.actions || !Array.isArray(params.actions) || params.actions.length === 0) {
274
- errors.push('At least one action is required');
275
- } else {
276
- // Validate each action
277
- for (const [index, action] of params.actions.entries()) {
278
- if (!action.type) {
279
- errors.push(`Action ${index + 1}: type is required`);
280
- continue;
281
- }
282
-
283
- if (action.type === 'detect-clones') {
284
- if (!action.directory) {
285
- errors.push(`Action ${index + 1}: directory is required for detect-clones`);
286
- }
287
-
288
- // Validate numeric parameters
289
- if (action.minTokens !== undefined && (action.minTokens < 10 || action.minTokens > 1000)) {
290
- errors.push(`Action ${index + 1}: min-tokens must be between 10 and 1000`);
291
- }
292
-
293
- if (action.minLines !== undefined && (action.minLines < 1 || action.minLines > 100)) {
294
- errors.push(`Action ${index + 1}: min-lines must be between 1 and 100`);
295
- }
296
-
297
- if (action.similarityThreshold !== undefined &&
298
- (action.similarityThreshold < 0.5 || action.similarityThreshold > 1.0)) {
299
- errors.push(`Action ${index + 1}: similarity-threshold must be between 0.5 and 1.0`);
300
- }
301
-
302
- // Validate enum parameters
303
- if (action.priorityFilter && !['high', 'medium', 'low'].includes(action.priorityFilter)) {
304
- errors.push(`Action ${index + 1}: priority-filter must be high, medium, or low`);
305
- }
306
-
307
- if (action.outputMode && !['summary', 'detailed', 'recommendations'].includes(action.outputMode)) {
308
- errors.push(`Action ${index + 1}: output-mode must be summary, detailed, or recommendations`);
309
- }
310
- } else {
311
- errors.push(`Action ${index + 1}: unknown action type: ${action.type}`);
312
- }
313
- }
314
- }
315
-
316
- return {
317
- valid: errors.length === 0,
318
- errors
319
- };
320
- }
321
-
322
- /**
323
- * Execute tool with parsed parameters
324
- * @param {Object} params - Parsed parameters
325
- * @param {Object} context - Execution context
326
- * @returns {Promise<Object>} Execution result
327
- */
328
- async execute(params, context) {
329
- const { actions } = params;
330
- const { projectDir, agentId, directoryAccess } = context;
331
-
332
- // Get directory access configuration
333
- const accessConfig = directoryAccess ||
334
- this.directoryAccessManager.createDirectoryAccess({
335
- workingDirectory: projectDir || process.cwd(),
336
- writeEnabledDirectories: [],
337
- readOnlyDirectories: [projectDir || process.cwd()],
338
- restrictToProject: true
339
- });
340
-
341
- const workingDir = this.directoryAccessManager.getWorkingDirectory(accessConfig);
342
- const results = [];
343
-
344
- for (const action of actions) {
345
- try {
346
- if (action.type === 'detect-clones') {
347
- const result = await this.detectClones(
348
- action.directory,
349
- workingDir,
350
- accessConfig,
351
- action
352
- );
353
- results.push(result);
354
- } else {
355
- throw new Error(`Unknown action type: ${action.type}`);
356
- }
357
-
358
- } catch (error) {
359
- this.logger?.error('Clone detection action failed', {
360
- action: action.type,
361
- error: error.message
362
- });
363
-
364
- results.push({
365
- directory: action.directory,
366
- error: error.message,
367
- success: false
368
- });
369
- }
370
- }
371
-
372
- return {
373
- success: true,
374
- results,
375
- toolUsed: 'clonedetection'
376
- };
377
- }
378
-
379
- /**
380
- * Detect clones in directory
381
- * @private
382
- */
383
- async detectClones(directory, workingDir, accessConfig, options = {}) {
384
- const fullDir = path.isAbsolute(directory)
385
- ? path.normalize(directory)
386
- : path.resolve(workingDir, directory);
387
-
388
- // Validate read access
389
- const accessResult = this.directoryAccessManager.validateReadAccess(fullDir, accessConfig);
390
- if (!accessResult.allowed) {
391
- throw new Error(`Read access denied: ${accessResult.reason}`);
392
- }
393
-
394
- try {
395
- // Get clone detector instance
396
- const detector = await this.getCloneDetector();
397
-
398
- // Prepare configuration
399
- const config = {
400
- minTokens: options.minTokens || this.defaultMinTokens,
401
- minLines: options.minLines || this.defaultMinLines,
402
- similarityThreshold: options.similarityThreshold || this.defaultSimilarityThreshold,
403
- include: ['**/*.js', '**/*.jsx', '**/*.mjs', '**/*.cjs', '**/*.ts', '**/*.tsx', '**/*.vue'],
404
- exclude: ['**/node_modules/**', '**/dist/**', '**/build/**', '**/*.test.js', '**/*.spec.js'],
405
- maxFileSize: this.maxFileSize
406
- };
407
-
408
- this.logger?.info('Starting clone detection', {
409
- directory: fullDir,
410
- config
411
- });
412
-
413
- // Run clone detection (without output file)
414
- const report = await detector.run(fullDir, null);
415
-
416
- if (!report) {
417
- return {
418
- directory: this.directoryAccessManager.createRelativePath(fullDir, accessConfig),
419
- fullPath: fullDir,
420
- success: true,
421
- summary: {
422
- totalFiles: 0,
423
- totalClones: 0,
424
- duplicationPercentage: 0
425
- },
426
- clones: [],
427
- message: 'No files found or no clones detected'
428
- };
429
- }
430
-
431
- // Apply filters
432
- let filteredClones = report.clones;
433
-
434
- // Filter by priority
435
- if (options.priorityFilter) {
436
- filteredClones = filteredClones.filter(
437
- clone => clone.refactoringAdvice.priority === options.priorityFilter
438
- );
439
- }
440
-
441
- // Limit results
442
- if (options.maxResults) {
443
- filteredClones = filteredClones.slice(0, options.maxResults);
444
- }
445
-
446
- // Format output based on mode
447
- const outputMode = options.outputMode || 'detailed';
448
-
449
- if (outputMode === 'summary') {
450
- return this.formatSummaryOutput(report, filteredClones, fullDir, accessConfig);
451
- } else if (outputMode === 'recommendations') {
452
- return this.formatRecommendationsOutput(report, filteredClones, fullDir, accessConfig);
453
- } else {
454
- return this.formatDetailedOutput(report, filteredClones, fullDir, accessConfig);
455
- }
456
-
457
- } catch (error) {
458
- throw new Error(`Failed to detect clones in ${directory}: ${error.message}`);
459
- }
460
- }
461
-
462
- /**
463
- * Format summary output
464
- * @private
465
- */
466
- formatSummaryOutput(report, clones, fullDir, accessConfig) {
467
- return {
468
- directory: this.directoryAccessManager.createRelativePath(fullDir, accessConfig),
469
- fullPath: fullDir,
470
- success: true,
471
- outputMode: 'summary',
472
- summary: {
473
- totalFiles: report.summary.totalFiles,
474
- totalClones: report.summary.totalClones,
475
- duplicatedLines: report.summary.totalDuplicatedLines,
476
- duplicationPercentage: report.summary.duplicationPercentage,
477
- priorityCounts: report.summary.priorityCounts,
478
- topClones: clones.slice(0, 5).map(clone => ({
479
- id: clone.id,
480
- type: clone.type,
481
- confidence: clone.confidence,
482
- instances: clone.metrics.instanceCount,
483
- lines: clone.metrics.lineCount,
484
- priority: clone.refactoringAdvice.priority,
485
- strategy: clone.refactoringAdvice.strategy,
486
- locations: clone.instances.map(i => `${i.file}:${i.startLine}-${i.endLine}`)
487
- }))
488
- }
489
- };
490
- }
491
-
492
- /**
493
- * Format recommendations output
494
- * @private
495
- */
496
- formatRecommendationsOutput(report, clones, fullDir, accessConfig) {
497
- return {
498
- directory: this.directoryAccessManager.createRelativePath(fullDir, accessConfig),
499
- fullPath: fullDir,
500
- success: true,
501
- outputMode: 'recommendations',
502
- summary: {
503
- totalFiles: report.summary.totalFiles,
504
- totalClones: report.summary.totalClones,
505
- duplicationPercentage: report.summary.duplicationPercentage
506
- },
507
- recommendations: clones.map(clone => ({
508
- id: clone.id,
509
- priority: clone.refactoringAdvice.priority,
510
- strategy: clone.refactoringAdvice.strategy,
511
- suggestedName: clone.refactoringAdvice.suggestedName,
512
- reasoning: clone.refactoringAdvice.reasoning,
513
- effort: clone.refactoringAdvice.estimatedEffort,
514
- benefits: clone.refactoringAdvice.benefits,
515
- steps: clone.refactoringAdvice.actionableSteps,
516
- metrics: {
517
- instances: clone.metrics.instanceCount,
518
- lines: clone.metrics.lineCount,
519
- files: clone.metrics.filesCovered,
520
- impact: clone.metrics.impactScore
521
- },
522
- locations: clone.instances.map(i => ({
523
- file: i.file,
524
- startLine: i.startLine,
525
- endLine: i.endLine
526
- }))
527
- }))
528
- };
529
- }
530
-
531
- /**
532
- * Format detailed output
533
- * @private
534
- */
535
- formatDetailedOutput(report, clones, fullDir, accessConfig) {
536
- return {
537
- directory: this.directoryAccessManager.createRelativePath(fullDir, accessConfig),
538
- fullPath: fullDir,
539
- success: true,
540
- outputMode: 'detailed',
541
- summary: report.summary,
542
- clones: clones.map(clone => ({
543
- ...clone,
544
- // Truncate code snippets for agent readability
545
- instances: clone.instances.map(instance => ({
546
- ...instance,
547
- code: instance.code.split('\n').slice(0, 10).join('\n') +
548
- (instance.code.split('\n').length > 10 ? '\n... (truncated)' : '')
549
- }))
550
- }))
551
- };
552
- }
553
-
554
- /**
555
- * Get clone detector instance (lazy initialization)
556
- * @private
557
- */
558
- async getCloneDetector() {
559
- if (!this.cloneDetector) {
560
- const { CloneDetectionTool } = await import('../analyzers/codeCloneDetector/index.js');
561
-
562
- const config = {
563
- minTokens: this.defaultMinTokens,
564
- minLines: this.defaultMinLines,
565
- similarityThreshold: this.defaultSimilarityThreshold,
566
- include: ['**/*.js', '**/*.jsx', '**/*.ts', '**/*.tsx', '**/*.vue'],
567
- exclude: ['**/node_modules/**', '**/dist/**', '**/build/**'],
568
- maxFileSize: this.maxFileSize
569
- };
570
-
571
- this.cloneDetector = new CloneDetectionTool(config);
572
- this.logger?.debug('Clone detector initialized', { config });
573
- }
574
-
575
- return this.cloneDetector;
576
- }
577
-
578
- /**
579
- * Get supported actions for this tool
580
- * @returns {Array<string>} Array of supported action names
581
- */
582
- getSupportedActions() {
583
- return ['detect-clones'];
584
- }
585
-
586
- /**
587
- * Get parameter schema for validation
588
- * @returns {Object} Parameter schema
589
- */
590
- getParameterSchema() {
591
- return {
592
- type: 'object',
593
- properties: {
594
- actions: {
595
- type: 'array',
596
- minItems: 1,
597
- items: {
598
- type: 'object',
599
- properties: {
600
- type: {
601
- type: 'string',
602
- enum: this.getSupportedActions()
603
- },
604
- directory: { type: 'string' },
605
- minTokens: { type: 'number', minimum: 10, maximum: 1000 },
606
- minLines: { type: 'number', minimum: 1, maximum: 100 },
607
- similarityThreshold: { type: 'number', minimum: 0.5, maximum: 1.0 },
608
- priorityFilter: { type: 'string', enum: ['high', 'medium', 'low'] },
609
- maxResults: { type: 'number', minimum: 1 },
610
- outputMode: { type: 'string', enum: ['summary', 'detailed', 'recommendations'] }
611
- },
612
- required: ['type', 'directory']
613
- }
614
- }
615
- },
616
- required: ['actions']
617
- };
618
- }
619
- }
620
-
621
- export default CloneDetectionTool;
1
+ const a0_0x2c0b6f=a0_0x4457;(function(_0x584ecf,_0x3d0be4){const _0x37ddff=a0_0x4457,_0x49daeb=_0x584ecf();while(!![]){try{const _0x712b2c=-parseInt(_0x37ddff(0x184))/0x1*(parseInt(_0x37ddff(0x137))/0x2)+-parseInt(_0x37ddff(0x12e))/0x3+-parseInt(_0x37ddff(0x160))/0x4*(parseInt(_0x37ddff(0x161))/0x5)+-parseInt(_0x37ddff(0x14a))/0x6+parseInt(_0x37ddff(0x162))/0x7*(parseInt(_0x37ddff(0x152))/0x8)+-parseInt(_0x37ddff(0x180))/0x9+-parseInt(_0x37ddff(0x132))/0xa*(-parseInt(_0x37ddff(0x191))/0xb);if(_0x712b2c===_0x3d0be4)break;else _0x49daeb['push'](_0x49daeb['shift']());}catch(_0x2a8162){_0x49daeb['push'](_0x49daeb['shift']());}}}(a0_0x1aad,0xa8340));function a0_0x4457(_0x390d4e,_0x405f92){_0x390d4e=_0x390d4e-0x12d;const _0x1aad17=a0_0x1aad();let _0x445739=_0x1aad17[_0x390d4e];if(a0_0x4457['zORiEN']===undefined){var _0xc7e861=function(_0x4c6cb5){const _0x30c5ed='abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789+/=';let _0x4eb062='',_0x615f6b='';for(let _0x5b31de=0x0,_0x4fc9d3,_0x14963b,_0x13c821=0x0;_0x14963b=_0x4c6cb5['charAt'](_0x13c821++);~_0x14963b&&(_0x4fc9d3=_0x5b31de%0x4?_0x4fc9d3*0x40+_0x14963b:_0x14963b,_0x5b31de++%0x4)?_0x4eb062+=String['fromCharCode'](0xff&_0x4fc9d3>>(-0x2*_0x5b31de&0x6)):0x0){_0x14963b=_0x30c5ed['indexOf'](_0x14963b);}for(let _0x282279=0x0,_0x2513f1=_0x4eb062['length'];_0x282279<_0x2513f1;_0x282279++){_0x615f6b+='%'+('00'+_0x4eb062['charCodeAt'](_0x282279)['toString'](0x10))['slice'](-0x2);}return decodeURIComponent(_0x615f6b);};a0_0x4457['ZHmoZJ']=_0xc7e861,a0_0x4457['zJQyoW']={},a0_0x4457['zORiEN']=!![];}const _0x3bd8a7=_0x1aad17[0x0],_0x54acd1=_0x390d4e+_0x3bd8a7,_0x563bd4=a0_0x4457['zJQyoW'][_0x54acd1];return!_0x563bd4?(_0x445739=a0_0x4457['ZHmoZJ'](_0x445739),a0_0x4457['zJQyoW'][_0x54acd1]=_0x445739):_0x445739=_0x563bd4,_0x445739;}import{BaseTool}from'./baseTool.js';import a0_0x4eb062 from'../utilities/tagParser.js';function a0_0x1aad(){const _0x14fd9c=['nZqZmJm1nwTqq3fIsa','ChjPB3jPDhKTzMLSDgvY','oIbKAxjLy3rVCNKGAxmGCMvXDwLYzwqGzM9YigrLDgvJDc1JBg9Uzxm','kIOVzgLZDc8QkG','C2LTAwXHCML0Es10AhjLC2HVBgq','kIOVkI5QCW','ChvZAa','oIbZAw1PBgfYAxr5lxrOCMvZAg9SzcbTDxn0igjLigjLDhDLzw4Gmc41igfUzcaXlJa','BwvZC2fNzq','y3vZDg9TvMfSAwrHDgvqyxjHBwv0zxjZ','zgv0zwn0q2XVBMvZ','kIOVkI5ZCgvJlMPZ','zgv0zwn0lwnSB25LCW','vw5RBM93BIbHy3rPB24GDhLWztOG','Bwf4uMvZDwX0CW','Bwv0CMLJCW','Bwf4q29Uy3vYCMvUDe9WzxjHDgLVBNm','zgvMyxvSDe1PBKXPBMvZ','BwLUvg9Rzw5Z','zMLSzq','zMLSDgvY','CgfYC2vbDhrYAwj1DgvZ','q2XVBMvezxrLy3rPB24GDg9VBcbWyxjZAw5NihbHCMfTzxrLCNm','z2v0v29YA2LUz0rPCMvJDg9YEq','C3rHCNrmAw5L','zw5KtgLUzq','DhLWzq','Dg90ywXdBg9Uzxm','BgLUzunVDw50','B3v0Chv0lw1Vzgu','ntm1ndiWohDlvgDLva','z2v0u3vWCg9YDgvKqwn0Aw9UCW','qwn0Aw9Uia','CNvU','mJGXotKXCK1gz3bT','z2v0q2XVBMvezxrLy3rVCG','ChjPB3jPDhLgAwX0zxi','BwLUlxrVA2vUCW','Bwf4rMLSzvnPEMu','C3vTBwfYEq','kIOVkI52Dwu','zM9YBwf0rgv0ywLSzwrpDxrWDxq','Bg9Nz2vY','CgfYC2vqyxjHBwv0zxjZ','AxnbC3LUyW','y3jLyxrLrgLYzwn0B3j5qwnJzxnZ','Dg90ywXeDxbSAwnHDgvKtgLUzxm','mJKWmZe4mJDWu2DbvLq','BwvKAxvT','BgvUz3rO','Dg90ywXgAwXLCW','kIOVyNvPBgqVkIO','C2XPy2u','zgLYzwn0B3j5qwnJzxnZtwfUywDLCG','C2LTAwXHCML0EvrOCMvZAg9Sza','kIOVBM9Kzv9TB2r1BgvZlYOQ','zMLSzxndB3zLCMvK','C3bSAxq','mJG3mdq4muX1Eu5Ysq','tM8GzMLSzxmGzM91BMqGB3iGBM8Gy2XVBMvZigrLDgvJDgvK','zgLYzwn0B3j5','ywn0Aw9UCW','mtbvuvvrCgG','kIOVkI5JANm','B3v0Chv0tw9Kzq','zM9YBwf0u3vTBwfYEu91Dhb1Da','ChjPB3jPDhK','nhbZq1joAa','Aw5ZDgfUy2vdB3vUDa','zxjYB3i','y2XVBMvezxrLy3rVCG','zgvIDwC','BwfW','CMvJB21Tzw5KyxrPB25Z','Aw5ZDgfUy2vZ','y3DK','DhjPBq','y3jLyxrLuMvSyxrPDMvqyxrO','C3vNz2vZDgvKtMfTzq','z2v0rgvZy3jPChrPB24','C3vIC3rYAw5N','z2v0ugfYyw1LDgvYu2nOzw1H','B2jQzwn0','yMvUzwzPDhm','cKnVzguGq2XVBMuGrgv0zwn0Aw9UifrVB2W6iezPBMqGzhvWBgLJyxrLzcbJB2rLigzVCIbYzwzHy3rVCMLUzYbVChbVCNr1BML0AwvZcGPuAgLZihrVB2WGAwrLBNrPzMLLCYbLEgfJDcbHBMqGC2LTAwXHCIbJB2rLihbHDhrLCM5ZicHJB2rLignSB25LCYKGywnYB3nZihLVDxiGy29KzwjHC2uGDg8GAgvSCcbYzwr1y2uGzhvWBgLJyxrPB24SigLTChjVDMuGBwfPBNrHAw5HyMLSAxr5lcbHBMqGAwrLBNrPzNKGCMvMywn0B3jPBMCGB3bWB3j0Dw5PDgLLCY4kcLDiqvqGsvqGrevurunuuZOklsbfEgfJDcbdBg9UzxmGkfr5CguGmsK6ieLKzw50AwnHBcbJB2rLihDPDgGGzgLMzMvYzw50igzVCM1HDhrPBMCVy29TBwvUDhmklsbtAw1PBgfYienSB25LCYaOvhLWzsaYlZmPoIbtDhj1y3r1CMfSBhKGC2LTAwXHCIbJB2rLihDPDgGGBwLUB3iGDMfYAwf0Aw9UCWOku1vque9sveveieXbtKDvquDfuZOklsbkyxzHu2nYAxb0icGUANmSic5QC3GSic5TANmSic5JANmPcI0GvhLWzvnJCMLWDcaOlNrZlcaUDhn4kqOTifz1zsaOlNz1zsKkcLvtquDfic0Gwe1miezpuK1bvdOkcKrLDgvJDcbJBg9UzxmGAw4Gzw50AxjLigrPCMvJDg9YEtOkw3rVB2WGAwq9iMnSB25Lzgv0zwn0Aw9UiL0kpgrLDgvJDc1JBg9UzxmGzgLYzwn0B3j5psiUiIaVpGPBl3rVB2XDcGPezxrLy3qGy2XVBMvZigLUihnWzwnPzMLJigrPCMvJDg9YEtOkw3rVB2WGAwq9iMnSB25Lzgv0zwn0Aw9UiL0kpgrLDgvJDc1JBg9UzxmGzgLYzwn0B3j5psjZCMmVC2vYDMLJzxmIic8+cLSVDg9VBf0kcKn1C3rVBsbZzw5ZAxrPDML0EsaOBg93zxiGBwLUvg9Rzw5Zid0GBw9YzsbZzw5ZAxrPDMuPoGPBDg9VBcbPzd0Iy2XVBMvKzxrLy3rPB24IxqO8zgv0zwn0lwnSB25LCYbKAxjLy3rVCNK9iNnYyYiGBwLUlxrVA2vUCZ0ImZaIig1PBI1SAw5LCZ0InsiGlZ4kwY90B29SxqOkrMLSDgvYigj5ihbYAw9YAxr5oGPBDg9VBcbPzd0Iy2XVBMvKzxrLy3rPB24IxqO8zgv0zwn0lwnSB25LCYbKAxjLy3rVCNK9iI4IihbYAw9YAxr5lwzPBhrLCJ0IAgLNAciGBwf4lxjLC3vSDhm9iJuIic8+cLSVDg9VBf0kcKDLDcbZDw1Tyxj5ig9UBhK6cLT0B29SigLKpsjJBg9UzwrLDgvJDgLVBIjDcJXKzxrLy3qTy2XVBMvZigrPCMvJDg9YEt0IlIiGB3v0Chv0lw1Vzgu9iNn1Bw1HCNKIic8+cLSVDg9VBf0kcLvtquDfic0GsLnptIbgt1jnqvq6cGPGygbQC29UcNSkicaIDg9VBeLKiJOGiMnSB25Lzgv0zwn0Aw9UiIWkicaIywn0Aw9UCYi6ifSkicaGihSkicaGicaGiNr5CguIoIaIzgv0zwn0lwnSB25LCYiScIaGicaGicjKAxjLy3rVCNKIoIaIC3jJiIWkicaGicaGiM1PBLrVA2vUCYi6iduWlaOGicaGicaIBwLUtgLUzxmIoIa1laOGicaGicaIC2LTAwXHCML0EvrOCMvZAg9Szci6idaUoduScIaGicaGicjWCMLVCML0EuzPBhrLCIi6icjOAwDOiIWkicaGicaGiM1HEfjLC3vSDhmIoIaXmcWkicaGicaGiM91Dhb1De1VzguIoIaIC3vTBwfYEsikicaGih0kicbDcN0kygbGcGPqqvjbtuvurvjtoGOTigrPCMvJDg9YEtOGrgLYzwn0B3j5ihrVigfUywX5EMuGkhjLCxvPCMvKkqOTig1PBI10B2TLBNm6ie1PBMLTDw0GDg9Rzw4Gy291BNqGkgrLzMf1Bhq6iduWlcbSB3DLCIa9ig1VCMuGC2vUC2L0AxzLkqOTig1PBI1SAw5LCZOGtwLUAw11BsbSAw5LignVDw50icHKzwzHDwX0oIa1kqOTihnPBwLSyxjPDhKTDgHYzxnOB2XKoIaWlteGC2LTAwXHCML0Esb0AhjLC2HVBgqGkgrLzMf1Bhq6idaUoduPcI0GChjPB3jPDhKTzMLSDgvYoIbgAwX0zxiGyNKGChjPB3jPDhKGkgHPz2GVBwvKAxvTl2XVDYWGB3b0Aw9UywWPcI0GBwf4lxjLC3vSDhm6ie1HEgLTDw0GBNvTyMvYig9MignSB25LCYb0BYbYzxr1CM4Gkg9WDgLVBMfSkqOTig91Dhb1Dc1TB2rLoIbZDw1Tyxj5FgrLDgfPBgvKFhjLy29TBwvUzgf0Aw9UCYaOzgvMyxvSDdOGzgv0ywLSzwqPcGPpvvrqvvqGrK9stufuoGPszxr1CM5ZignSB25LigrLDgvJDgLVBIbYzxn1BhrZihDPDgG6cI0GC3vTBwfYEtOGt3zLCMfSBcbZDgf0Axn0AwnZicH0B3rHBcbJBg9UzxmSigr1CgXPy2f0Aw9UicuSihbYAw9YAxr5igjYzwfRzg93BIKklsbJBg9Uzxm6iefYCMf5ig9MigrLDgvJDgvKignSB25LigDYB3vWCWOGic0GAwq6ienSB25LigLKzw50AwzPzxikicaTihr5Cgu6igv4ywn0ihWGC2LTAwXHCGOGic0Gy29UzMLKzw5JztOGrgv0zwn0Aw9UignVBMzPzgvUy2uGkdaTmsKkicaTigLUC3rHBMnLCZOGqxjYyxKGB2yGy29KzsbSB2nHDgLVBNmGD2L0AcbMAwXLihbHDgHZigfUzcbSAw5Lig51BwjLCNmkicaTig1LDhjPy3m6ihrVA2vUq291BNqSigXPBMvdB3vUDcWGAw5ZDgfUy2vdB3vUDcWGAw1Wywn0u2nVCMuSigzPBgvZq292zxjLzaOGic0GCMvMywn0B3jPBMDbzhzPy2u6cIaGicaTihbYAw9YAxr5oIbOAwDOihWGBwvKAxvTihWGBg93cIaGicaTihn0CMf0zwD5oIbLEhrYywn0lwz1BMn0Aw9UihWGzxH0CMfJDc1JBgfZCYb8igv4DhjHy3qTBw9KDwXLihWGzxH0CMfJDc1JB25ZDgfUDaOGicaGlsbZDwDNzxn0zwroyw1LoIbszwnVBw1LBMrLzcbUyw1LigzVCIbLEhrYywn0zwqGy29KzqOGicaGlsbYzwfZB25PBMC6ifDOEsb0AgLZihjLzMfJDg9YAw5NigLZihjLy29TBwvUzgvKcIaGicaTigvZDgLTyxrLzevMzM9YDdOGBg93ihWGBwvKAxvTihWGAgLNAaOGicaGlsbIzw5LzML0CZOGqxjYyxKGB2yGyMvUzwzPDhmkicaGic0Gywn0Aw9UywjSzvn0zxbZoIbtDgvWlwj5lxn0zxaGCMvMywn0B3jPBMCGAw5ZDhj1y3rPB25ZcGPpvvrqvvqGtu9ervm6cI0GC3vTBwfYEtOGsgLNAc1SzxzLBcbVDMvYDMLLDYbVBMX5icHKDxbSAwnHDgLVBIaLlcb0B3aGnsbJBg9UzxmPcI0Gzgv0ywLSzwq6iez1BgWGy2XVBMuGzgv0ywLSCYb3AxrOignVzguGC25PChbLDhmGkgrLzMf1BhqPcI0GCMvJB21Tzw5KyxrPB25ZoIbszwzHy3rVCMLUzYbWCMLVCML0AwvZihDPDgGGywn0Aw9UywjSzsbZDgvWCWOkrevurunusu9oiefmr09ssvrittOklsbvC2vZieftvcaOqwjZDhjHy3qGu3LUDgf4ifrYzwuPihbHCNnPBMCGDMLHiejHyMvScI0Gvg9Rzw4TyMfZzwqGC2LTAwXHCML0Esb3AxrOig5VCM1HBgL6yxrPB24klsbmB25Nzxn0ienVBw1VBIbtDwjZzxf1zw5JzsaOtentksbHBgDVCML0Ag0GzM9YihnPBwLSyxjPDhKklsbdB25MAwD1CMfIBguGC2vUC2L0AxzPDhKGyw5KihrOCMvZAg9SzhmkcKvyqu1qtevtoGOkrMLUzcbHBgWGy2XVBMvZigLUihbYB2PLy3q6cLT0B29SigLKpsjJBg9UzwrLDgvJDgLVBIjDcJXKzxrLy3qTy2XVBMvZigrPCMvJDg9YEt0IlIiGlZ4kwY90B29SxqOksgLNAc1WCMLVCML0EsbYzwzHy3rVCMLUzYbVChbVCNr1BML0AwvZig9UBhK6cLT0B29SigLKpsjJBg9UzwrLDgvJDgLVBIjDcJXKzxrLy3qTy2XVBMvZigrPCMvJDg9YEt0IC3jJiIbWCMLVCML0Es1MAwX0zxi9iMHPz2GIig1HEc1Yzxn1BhrZpsiXmciGlZ4kwY90B29SxqOktw9YzsbZzw5ZAxrPDMuGzgv0zwn0Aw9UicHMAw5KCYbZBwfSBgvYignSB25LCYK6cLT0B29SigLKpsjJBg9UzwrLDgvJDgLVBIjDcJXKzxrLy3qTy2XVBMvZigrPCMvJDg9YEt0IlIiGBwLUlxrVA2vUCZ0ImZaIihnPBwLSyxjPDhKTDgHYzxnOB2XKpsiWlJGWiIaVpGPBl3rVB2XDcGPrDwLJAYbVDMvYDMLLDZOkw3rVB2WGAwq9iMnSB25Lzgv0zwn0Aw9UiL0kpgrLDgvJDc1JBg9UzxmGzgLYzwn0B3j5psiUiIbVDxrWDxqTBw9Kzt0IC3vTBwfYEsiGlZ4kwY90B29SxqOkteLnsvrbveLptLm6cI0Gqw5HBhL6zxmGsMf2yvnJCMLWDc9uExbLu2nYAxb0igzHBwLSEsbVBMX5cI0GugvYzM9YBwfUy2uGzgvWzw5KCYbVBIbJB2rLyMfZzsbZAxPLicG1mdbTCYbWzxiGzMLSzsb0ExbPy2fSkqOTie1HEgLTDw0GzMLSzsbZAxPLoIa','ywXSB3DLza','mZm0ode3nhnMDeXSyG','DMfSAwrHDgvszwfKqwnJzxnZ','zw50CMLLCW','Bwf4lxjLC3vSDhm','CMvMywn0B3jPBMDbzhzPy2u','BNvTyMvY','lI4Vyw5HBhL6zxjZl2nVzgvdBg9UzurLDgvJDg9Yl2LUzgv4lMPZ','CMvHC29UAw5N','oerlquLVCG','zgv0ywLSzwq','zgvMyxvSDfnPBwLSyxjPDhLuAhjLC2HVBgq','zM9YBwf0uMvJB21Tzw5KyxrPB25Zt3v0Chv0','rMfPBgvKihrVigrLDgvJDcbJBg9UzxmGAw4G','CMvZB2X2zq','Aw5JBhvKzxm','q2XVBMuGzgv0zwn0Aw9UigfJDgLVBIbMywLSzwq','Bg93','u3rHCNrPBMCGy2XVBMuGzgv0zwn0Aw9U','oIbTAw4TBgLUzxmGBxvZDcbIzsbIzxr3zwvUideGyw5KideWma','uMvHzcbHy2nLC3mGzgvUAwvKoIa','BwLUlwXPBMvZ','C3rYAw5N','ntiWndHntvHwzeu','mtmWvNLRs1rO'];a0_0x1aad=function(){return _0x14fd9c;};return a0_0x1aad();}import a0_0x615f6b from'../utilities/directoryAccessManager.js';import a0_0x5b31de from'path';import{TOOL_STATUS,SYSTEM_DEFAULTS}from'../utilities/constants.js';class CloneDetectionTool extends BaseTool{constructor(_0x4fc9d3={},_0x14963b=null){const _0x22dd55=a0_0x4457;super(_0x4fc9d3,_0x14963b),this['requiresProject']=!![],this[_0x22dd55(0x18e)]=![],this['timeout']=_0x4fc9d3['timeout']||0x1d4c0,this['maxConcurrentOperations']=_0x4fc9d3[_0x22dd55(0x172)]||0x1,this['defaultMinTokens']=_0x4fc9d3['defaultMinTokens']||0x32,this[_0x22dd55(0x173)]=_0x4fc9d3[_0x22dd55(0x173)]||0x5,this['defaultSimilarityThreshold']=_0x4fc9d3[_0x22dd55(0x154)]||0.85,this[_0x22dd55(0x188)]=_0x4fc9d3[_0x22dd55(0x188)]||0x7a120,this['directoryAccessManager']=new a0_0x615f6b(_0x4fc9d3,_0x14963b),this[_0x22dd55(0x13a)]=null;}[a0_0x2c0b6f(0x143)](){const _0x125d43=a0_0x2c0b6f;return _0x125d43(0x148)+Math['round'](this['maxFileSize']/0x400)+'KB\x20per\x20file\x0a-\x20Analysis\x20timeout:\x20'+this['timeout']/0x3e8+'\x20seconds\x0a\x0aUSE\x20CASES:\x0a-\x20Identify\x20refactoring\x20opportunities\x20before\x20code\x20review\x0a-\x20Track\x20technical\x20debt\x20and\x20code\x20duplication\x20metrics\x0a-\x20Find\x20candidates\x20for\x20DRY\x20(Don\x27t\x20Repeat\x20Yourself)\x20refactoring\x0a-\x20Prioritize\x20maintenance\x20work\x20by\x20impact\x20score\x0a\x20\x20\x20\x20';}[a0_0x2c0b6f(0x18d)](_0x13c821){const _0x4848fb=a0_0x2c0b6f;try{const _0x282279={},_0x2513f1=[];this[_0x4848fb(0x18c)]?.['debug'](_0x4848fb(0x178),{'contentLength':_0x13c821['length'],'contentPreview':_0x13c821[_0x4848fb(0x144)](0x0,0xc8)});const _0x52b69d=/<detect-clones\s+(.+?)\/>/g;let _0x341150;while((_0x341150=_0x52b69d['exec'](_0x13c821))!==null){const _0x2a66d5=_0x341150[0x1]['trim'](),_0x2d4d19=new a0_0x4eb062(),_0x1275fe=_0x2d4d19[_0x4848fb(0x177)](_0x2a66d5),_0x35db75={'type':'detect-clones',..._0x1275fe};_0x35db75[_0x4848fb(0x187)]&&(_0x35db75[_0x4848fb(0x174)]=parseInt(_0x35db75[_0x4848fb(0x187)],0xa),delete _0x35db75['min-tokens']),_0x35db75['min-lines']&&(_0x35db75['minLines']=parseInt(_0x35db75[_0x4848fb(0x15e)],0xa),delete _0x35db75[_0x4848fb(0x15e)]),_0x35db75['similarity-threshold']&&(_0x35db75['similarityThreshold']=parseFloat(_0x35db75['similarity-threshold']),delete _0x35db75[_0x4848fb(0x166)]),_0x35db75[_0x4848fb(0x163)]&&(_0x35db75[_0x4848fb(0x186)]=_0x35db75['priority-filter'],delete _0x35db75['priority-filter']),_0x35db75['max-results']&&(_0x35db75['maxResults']=parseInt(_0x35db75['max-results'],0xa),delete _0x35db75[_0x4848fb(0x14d)]),_0x35db75['output-mode']&&(_0x35db75[_0x4848fb(0x134)]=_0x35db75[_0x4848fb(0x17f)],delete _0x35db75['output-mode']),_0x2513f1['push'](_0x35db75);}return _0x282279[_0x4848fb(0x131)]=_0x2513f1,_0x282279['rawContent']=_0x13c821[_0x4848fb(0x140)](),this['logger']?.[_0x4848fb(0x13b)]('Parsed\x20CloneDetection\x20tool\x20parameters',{'totalActions':_0x2513f1['length'],'actionTypes':_0x2513f1[_0x4848fb(0x13c)](_0x2310db=>_0x2310db['type'])}),_0x282279;}catch(_0x10f581){throw new Error('Failed\x20to\x20parse\x20clone\x20detection\x20parameters:\x20'+_0x10f581['message']);}}['getRequiredParameters'](){const _0x5d15ed=a0_0x2c0b6f;return[_0x5d15ed(0x131)];}[a0_0x2c0b6f(0x16b)](_0x3517a9){const _0x4d428c=a0_0x2c0b6f,_0x5f59f6=[];if(!_0x3517a9[_0x4d428c(0x131)]||!Array['isArray'](_0x3517a9['actions'])||_0x3517a9['actions'][_0x4d428c(0x193)]===0x0)_0x5f59f6['push']('At\x20least\x20one\x20action\x20is\x20required');else for(const [_0x49bf9b,_0x3b17c5]of _0x3517a9['actions'][_0x4d428c(0x14c)]()){if(!_0x3b17c5[_0x4d428c(0x17c)]){_0x5f59f6['push']('Action\x20'+(_0x49bf9b+0x1)+':\x20type\x20is\x20required');continue;}_0x3b17c5[_0x4d428c(0x17c)]===_0x4d428c(0x16e)?(!_0x3b17c5[_0x4d428c(0x130)]&&_0x5f59f6[_0x4d428c(0x168)]('Action\x20'+(_0x49bf9b+0x1)+_0x4d428c(0x164)),_0x3b17c5['minTokens']!==undefined&&(_0x3b17c5[_0x4d428c(0x174)]<0xa||_0x3b17c5['minTokens']>0x3e8)&&_0x5f59f6[_0x4d428c(0x168)](_0x4d428c(0x182)+(_0x49bf9b+0x1)+':\x20min-tokens\x20must\x20be\x20between\x2010\x20and\x201000'),_0x3b17c5['minLines']!==undefined&&(_0x3b17c5['minLines']<0x1||_0x3b17c5['minLines']>0x64)&&_0x5f59f6['push']('Action\x20'+(_0x49bf9b+0x1)+_0x4d428c(0x15c)),_0x3b17c5[_0x4d428c(0x198)]!==undefined&&(_0x3b17c5['similarityThreshold']<0.5||_0x3b17c5[_0x4d428c(0x198)]>0x1)&&_0x5f59f6['push']('Action\x20'+(_0x49bf9b+0x1)+_0x4d428c(0x169)),_0x3b17c5['priorityFilter']&&!['high','medium','low']['includes'](_0x3b17c5['priorityFilter'])&&_0x5f59f6['push'](_0x4d428c(0x182)+(_0x49bf9b+0x1)+':\x20priority-filter\x20must\x20be\x20high,\x20medium,\x20or\x20low'),_0x3b17c5['outputMode']&&!['summary','detailed',_0x4d428c(0x13d)][_0x4d428c(0x158)](_0x3b17c5[_0x4d428c(0x134)])&&_0x5f59f6['push']('Action\x20'+(_0x49bf9b+0x1)+':\x20output-mode\x20must\x20be\x20summary,\x20detailed,\x20or\x20recommendations')):_0x5f59f6['push'](_0x4d428c(0x182)+(_0x49bf9b+0x1)+':\x20unknown\x20action\x20type:\x20'+_0x3b17c5[_0x4d428c(0x17c)]);}return{'valid':_0x5f59f6['length']===0x0,'errors':_0x5f59f6};}async['execute'](_0x1bc002,_0x544828){const _0x5cb8a6=a0_0x2c0b6f,{actions:_0x1aca22}=_0x1bc002,{projectDir:_0x3dd534,agentId:_0x36a02d,directoryAccess:_0x7de7ec}=_0x544828,_0x5e4136=_0x7de7ec||this[_0x5cb8a6(0x197)][_0x5cb8a6(0x18f)]({'workingDirectory':_0x3dd534||process[_0x5cb8a6(0x13f)](),'writeEnabledDirectories':[],'readOnlyDirectories':[_0x3dd534||process[_0x5cb8a6(0x13f)]()],'restrictToProject':!![]}),_0x2d0096=this['directoryAccessManager'][_0x5cb8a6(0x179)](_0x5e4136),_0xf5ef7c=[];for(const _0x5a8361 of _0x1aca22){try{if(_0x5a8361[_0x5cb8a6(0x17c)]==='detect-clones'){const _0x2fb6d0=await this['detectClones'](_0x5a8361['directory'],_0x2d0096,_0x5e4136,_0x5a8361);_0xf5ef7c['push'](_0x2fb6d0);}else throw new Error(_0x5cb8a6(0x16f)+_0x5a8361[_0x5cb8a6(0x17c)]);}catch(_0x4984cb){this['logger']?.[_0x5cb8a6(0x139)](_0x5cb8a6(0x159),{'action':_0x5a8361[_0x5cb8a6(0x17c)],'error':_0x4984cb['message']}),_0xf5ef7c['push']({'directory':_0x5a8361['directory'],'error':_0x4984cb[_0x5cb8a6(0x16a)],'success':![]});}}return{'success':!![],'results':_0xf5ef7c,'toolUsed':'clonedetection'};}async[a0_0x2c0b6f(0x16c)](_0x2e7cc5,_0x1d682b,_0x2839be,_0x39aab5={}){const _0x105807=a0_0x2c0b6f,_0x3b54ba=a0_0x5b31de['isAbsolute'](_0x2e7cc5)?a0_0x5b31de['normalize'](_0x2e7cc5):a0_0x5b31de[_0x105807(0x157)](_0x1d682b,_0x2e7cc5),_0x37e70d=this[_0x105807(0x197)][_0x105807(0x14b)](_0x3b54ba,_0x2839be);if(!_0x37e70d[_0x105807(0x149)])throw new Error(_0x105807(0x15d)+_0x37e70d['reason']);try{const _0x23e63f=await this[_0x105807(0x185)](),_0x220f2a={'minTokens':_0x39aab5[_0x105807(0x174)]||this['defaultMinTokens'],'minLines':_0x39aab5['minLines']||this[_0x105807(0x173)],'similarityThreshold':_0x39aab5[_0x105807(0x198)]||this['defaultSimilarityThreshold'],'include':[_0x105807(0x167),'**/*.jsx','**/*.mjs',_0x105807(0x133),'**/*.ts','**/*.tsx',_0x105807(0x18a)],'exclude':[_0x105807(0x199),_0x105807(0x165),_0x105807(0x195),'**/*.test.js',_0x105807(0x16d)],'maxFileSize':this['maxFileSize']};this['logger']?.['info'](_0x105807(0x15b),{'directory':_0x3b54ba,'config':_0x220f2a});const _0x13d6ef=await _0x23e63f[_0x105807(0x183)](_0x3b54ba,null);if(!_0x13d6ef)return{'directory':this[_0x105807(0x197)]['createRelativePath'](_0x3b54ba,_0x2839be),'fullPath':_0x3b54ba,'success':!![],'summary':{'totalFiles':0x0,'totalClones':0x0,'duplicationPercentage':0x0},'clones':[],'message':_0x105807(0x12f)};let _0x3b88dc=_0x13d6ef['clones'];_0x39aab5[_0x105807(0x186)]&&(_0x3b88dc=_0x3b88dc[_0x105807(0x176)](_0x9550ae=>_0x9550ae['refactoringAdvice'][_0x105807(0x136)]===_0x39aab5[_0x105807(0x186)]));_0x39aab5[_0x105807(0x170)]&&(_0x3b88dc=_0x3b88dc[_0x105807(0x196)](0x0,_0x39aab5['maxResults']));const _0x34471e=_0x39aab5['outputMode']||_0x105807(0x153);if(_0x34471e===_0x105807(0x189))return this['formatSummaryOutput'](_0x13d6ef,_0x3b88dc,_0x3b54ba,_0x2839be);else return _0x34471e===_0x105807(0x13d)?this[_0x105807(0x155)](_0x13d6ef,_0x3b88dc,_0x3b54ba,_0x2839be):this[_0x105807(0x18b)](_0x13d6ef,_0x3b88dc,_0x3b54ba,_0x2839be);}catch(_0x14ef05){throw new Error(_0x105807(0x156)+_0x2e7cc5+':\x20'+_0x14ef05[_0x105807(0x16a)]);}}[a0_0x2c0b6f(0x135)](_0x532d1c,_0x5f587d,_0x1faf2d,_0xc5d728){const _0x5397b7=a0_0x2c0b6f;return{'directory':this[_0x5397b7(0x197)][_0x5397b7(0x141)](_0x1faf2d,_0xc5d728),'fullPath':_0x1faf2d,'success':!![],'outputMode':'summary','summary':{'totalFiles':_0x532d1c[_0x5397b7(0x189)]['totalFiles'],'totalClones':_0x532d1c[_0x5397b7(0x189)][_0x5397b7(0x17d)],'duplicatedLines':_0x532d1c[_0x5397b7(0x189)][_0x5397b7(0x190)],'duplicationPercentage':_0x532d1c[_0x5397b7(0x189)]['duplicationPercentage'],'priorityCounts':_0x532d1c['summary']['priorityCounts'],'topClones':_0x5f587d['slice'](0x0,0x5)['map'](_0x117304=>({'id':_0x117304['id'],'type':_0x117304['type'],'confidence':_0x117304['confidence'],'instances':_0x117304['metrics'][_0x5397b7(0x138)],'lines':_0x117304[_0x5397b7(0x171)][_0x5397b7(0x17e)],'priority':_0x117304['refactoringAdvice']['priority'],'strategy':_0x117304['refactoringAdvice']['strategy'],'locations':_0x117304['instances'][_0x5397b7(0x13c)](_0x37b449=>_0x37b449[_0x5397b7(0x175)]+':'+_0x37b449['startLine']+'-'+_0x37b449[_0x5397b7(0x17b)])}))}};}[a0_0x2c0b6f(0x155)](_0x31b11a,_0x535d21,_0x5d1777,_0x2bf557){const _0x5e4ec8=a0_0x2c0b6f;return{'directory':this['directoryAccessManager']['createRelativePath'](_0x5d1777,_0x2bf557),'fullPath':_0x5d1777,'success':!![],'outputMode':_0x5e4ec8(0x13d),'summary':{'totalFiles':_0x31b11a['summary'][_0x5e4ec8(0x194)],'totalClones':_0x31b11a[_0x5e4ec8(0x189)][_0x5e4ec8(0x17d)],'duplicationPercentage':_0x31b11a[_0x5e4ec8(0x189)]['duplicationPercentage']},'recommendations':_0x535d21[_0x5e4ec8(0x13c)](_0x50d989=>({'id':_0x50d989['id'],'priority':_0x50d989[_0x5e4ec8(0x14e)]['priority'],'strategy':_0x50d989[_0x5e4ec8(0x14e)]['strategy'],'suggestedName':_0x50d989['refactoringAdvice'][_0x5e4ec8(0x142)],'reasoning':_0x50d989['refactoringAdvice'][_0x5e4ec8(0x151)],'effort':_0x50d989['refactoringAdvice']['estimatedEffort'],'benefits':_0x50d989['refactoringAdvice'][_0x5e4ec8(0x147)],'steps':_0x50d989['refactoringAdvice']['actionableSteps'],'metrics':{'instances':_0x50d989['metrics'][_0x5e4ec8(0x138)],'lines':_0x50d989['metrics'][_0x5e4ec8(0x17e)],'files':_0x50d989['metrics'][_0x5e4ec8(0x19a)],'impact':_0x50d989[_0x5e4ec8(0x171)]['impactScore']},'locations':_0x50d989['instances'][_0x5e4ec8(0x13c)](_0x42da76=>({'file':_0x42da76[_0x5e4ec8(0x175)],'startLine':_0x42da76[_0x5e4ec8(0x17a)],'endLine':_0x42da76['endLine']}))}))};}['formatDetailedOutput'](_0x53da4f,_0x32ff6a,_0x1de0d0,_0x2294ca){const _0x4ac3a7=a0_0x2c0b6f;return{'directory':this[_0x4ac3a7(0x197)]['createRelativePath'](_0x1de0d0,_0x2294ca),'fullPath':_0x1de0d0,'success':!![],'outputMode':'detailed','summary':_0x53da4f[_0x4ac3a7(0x189)],'clones':_0x32ff6a['map'](_0x37e89f=>({..._0x37e89f,'instances':_0x37e89f[_0x4ac3a7(0x13e)][_0x4ac3a7(0x13c)](_0x348dae=>({..._0x348dae,'code':_0x348dae['code'][_0x4ac3a7(0x12d)]('\x0a')['slice'](0x0,0xa)['join']('\x0a')+(_0x348dae['code']['split']('\x0a')['length']>0xa?'\x0a...\x20(truncated)':'')}))}))};}async[a0_0x2c0b6f(0x185)](){const _0x1750e3=a0_0x2c0b6f;if(!this['cloneDetector']){const {CloneDetectionTool:_0x55a204}=await import(_0x1750e3(0x150)),_0x3e6cd2={'minTokens':this['defaultMinTokens'],'minLines':this[_0x1750e3(0x173)],'similarityThreshold':this['defaultSimilarityThreshold'],'include':['**/*.js','**/*.jsx','**/*.ts','**/*.tsx','**/*.vue'],'exclude':[_0x1750e3(0x199),'**/dist/**',_0x1750e3(0x195)],'maxFileSize':this['maxFileSize']};this['cloneDetector']=new _0x55a204(_0x3e6cd2),this[_0x1750e3(0x18c)]?.['debug']('Clone\x20detector\x20initialized',{'config':_0x3e6cd2});}return this[_0x1750e3(0x13a)];}[a0_0x2c0b6f(0x181)](){const _0x1ea9b6=a0_0x2c0b6f;return[_0x1ea9b6(0x16e)];}[a0_0x2c0b6f(0x145)](){const _0x1b6eda=a0_0x2c0b6f;return{'type':'object','properties':{'actions':{'type':'array','minItems':0x1,'items':{'type':_0x1b6eda(0x146),'properties':{'type':{'type':_0x1b6eda(0x15f),'enum':this['getSupportedActions']()},'directory':{'type':_0x1b6eda(0x15f)},'minTokens':{'type':_0x1b6eda(0x14f),'minimum':0xa,'maximum':0x3e8},'minLines':{'type':'number','minimum':0x1,'maximum':0x64},'similarityThreshold':{'type':'number','minimum':0.5,'maximum':0x1},'priorityFilter':{'type':'string','enum':['high',_0x1b6eda(0x192),_0x1b6eda(0x15a)]},'maxResults':{'type':'number','minimum':0x1},'outputMode':{'type':_0x1b6eda(0x15f),'enum':['summary',_0x1b6eda(0x153),_0x1b6eda(0x13d)]}},'required':[_0x1b6eda(0x17c),'directory']}}},'required':['actions']};}}export default CloneDetectionTool;