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

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 +14 -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_0x24898f=a0_0x1c8b;(function(_0x20bb6f,_0x176874){const _0x11afe0=a0_0x1c8b,_0x354aff=_0x20bb6f();while(!![]){try{const _0x3e0894=parseInt(_0x11afe0(0x241))/0x1+parseInt(_0x11afe0(0x1f9))/0x2+parseInt(_0x11afe0(0x236))/0x3*(parseInt(_0x11afe0(0x1e2))/0x4)+-parseInt(_0x11afe0(0x1dc))/0x5+parseInt(_0x11afe0(0x208))/0x6+parseInt(_0x11afe0(0x1ec))/0x7*(parseInt(_0x11afe0(0x1e4))/0x8)+-parseInt(_0x11afe0(0x23f))/0x9*(parseInt(_0x11afe0(0x218))/0xa);if(_0x3e0894===_0x176874)break;else _0x354aff['push'](_0x354aff['shift']());}catch(_0x5954b5){_0x354aff['push'](_0x354aff['shift']());}}}(a0_0x2058,0x7dac6));function a0_0x2058(){const _0x2d19d3=['y3DK','zMLSzq','mJm2mdm2nZbqzuzov0q','Bg9Nz2vY','mtaXmtqYme5fzhHSvq','zgvMyxvSDe1PBKXPBMvZ','kIOVkI5TANm','z2v0rgvZy3jPChrPB24','ndyWodKYnuTWEunvBa','C3vNz2vZDgvKtMfTzq','BwLUlxrVA2vUCW','vw5RBM93BIbHy3rPB24GDhLWztOG','AgLNAa','Aw5JBhvKzxm','mtm0nZK5nNPswLPZqG','oIbKAxjLy3rVCNKGAxmGCMvXDwLYzwqGzM9YigrLDgvJDc1JBg9Uzxm','nZm1nZi4yKL0AMnw','ChjPB3jPDhK','kIOVyNvPBgqVkIO','BwvZC2fNzq','kIOVkI52Dwu','oIb1BMTUB3DUigfJDgLVBIb0ExbLoIa','zxn0Aw1HDgvKrwzMB3j0','CMvJB21Tzw5KyxrPB25Z','ntzAuvPLtNe','zgvMyxvSDe1PBLrVA2vUCW','B3v0Chv0tw9Kzq','CMvMywn0B3jPBMDbzhzPy2u','BNvTyMvY','BwLUvg9Rzw5Z','Bg93','tM8GzMLSzxmGzM91BMqGB3iGBM8Gy2XVBMvZigrLDgvJDgvK','AxnbCNjHEq','y29UzMLKzw5Jzq','ChjPB3jPDhLgAwX0zxi','yMvUzwzPDhm','lI4Vyw5HBhL6zxjZl2nVzgvdBg9UzurLDgvJDg9Yl2LUzgv4lMPZ','mtq1mdGZnLPTC1DhCG','zgv0zwn0q2XVBMvZ','uMvHzcbHy2nLC3mGzgvUAwvKoIa','rMfPBgvKihrVihbHCNnLignSB25LigrLDgvJDgLVBIbWyxjHBwv0zxjZoIa','kIOVzgLZDc8QkG','C2LTAwXHCML0Es10AhjLC2HVBgq','Dg90ywXeDxbSAwnHDgvKtgLUzxm','ihnLy29UzhmkcLvtrsbdqvnfuZOklsbjzgvUDgLMEsbYzwzHy3rVCMLUzYbVChbVCNr1BML0AwvZigjLzM9YzsbJB2rLihjLDMLLDWOTifrYywnRihrLy2HUAwnHBcbKzwj0igfUzcbJB2rLigr1CgXPy2f0Aw9Uig1LDhjPy3mklsbgAw5KignHBMrPzgf0zxmGzM9YierswsaOrg9Uj3qGuMvWzwf0ifLVDxjZzwXMksbYzwzHy3rVCMLUzWOTifbYAw9YAxrPEMuGBwfPBNrLBMfUy2uGD29YAYbIEsbPBxbHy3qGC2nVCMukicaGia','C2XPy2u','kIOVkI5QCW','oIbWCMLVCML0Es1MAwX0zxiGBxvZDcbIzsbOAwDOlcbTzwrPDw0Sig9YigXVDW','C3vTBwfYEq','BgvUz3rO','kIOVkI50CW','B2jQzwn0','ntq3nty1nhrsC012uG','C2LTAwXHCML0EvrOCMvZAg9Sza','y29Kzq','y3jLyxrLuMvSyxrPDMvqyxrO','zMLSDgvY','zM9YBwf0rgv0ywLSzwrpDxrWDxq','BwfW','Aw5MBW','C3bSAxq','zgvMyxvSDfnPBwLSyxjPDhLuAhjLC2HVBgq','ywn0Aw9UCW','BwLUtgLUzxm','zgv0ywLSzwq','zw50CMLLCW','Bwf4uMvZDwX0CW','zgLYzwn0B3j5qwnJzxnZtwfUywDLCG','mtbeD2Piu04','AxnbC3LUyW','DgLTzw91Da','zM9YBwf0uMvJB21Tzw5KyxrPB25Zt3v0Chv0','C3rYAw5N','Bwf4lxjLC3vSDhm','oIbTAw4TBgLUzxmGBxvZDcbIzsbIzxr3zwvUideGyw5KideWma','zM9YBwf0u3vTBwfYEu91Dhb1Da','Bwv0CMLJCW','Aw5ZDgfUy2vdB3vUDa','zhvWBgLJyxrPB25qzxjJzw50ywDL','qxqGBgvHC3qGB25LigfJDgLVBIbPCYbYzxf1AxjLza','z2v0u3vWCg9YDgvKqwn0Aw9UCW','CMvXDwLYzxnqCM9Qzwn0','kIOVkI50C3G','ChvZAa','s0iGCgvYigzPBguklsbbBMfSExnPCYb0Aw1LB3v0oIa','Aw5ZDgfUy2vZ','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','y2XVBMvKzxrLy3rPB24','zgv0zwn0lwnSB25LCW','BwvKAxvT','Dg90ywXdBg9Uzxm','BgLUzunVDw50','kIOVkI50zxn0lMPZ','y2XVBMvezxrLy3rVCG','DhLWzq','DhjPBq','AM9PBG','zgvIDwC','nNLIChn4wa','z2v0v29YA2LUz0rPCMvJDg9YEq','zgLYzwn0B3j5','yxjYyxK','Bwf4q29Uy3vYCMvUDe9WzxjHDgLVBNm','Bwf4rMLSzvnPEMu','qwn0Aw9Uia'];a0_0x2058=function(){return _0x2d19d3;};return a0_0x2058();}import{BaseTool}from'./baseTool.js';import a0_0x18adee from'../utilities/tagParser.js';import a0_0x441f97 from'../utilities/directoryAccessManager.js';function a0_0x1c8b(_0x1ca11e,_0xd89da1){_0x1ca11e=_0x1ca11e-0x1da;const _0x205836=a0_0x2058();let _0x1c8b2d=_0x205836[_0x1ca11e];if(a0_0x1c8b['AAJgmy']===undefined){var _0x1edb14=function(_0x4bdf68){const _0x461482='abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789+/=';let _0x18adee='',_0x441f97='';for(let _0x16124f=0x0,_0x53c5a0,_0x37ec95,_0x207271=0x0;_0x37ec95=_0x4bdf68['charAt'](_0x207271++);~_0x37ec95&&(_0x53c5a0=_0x16124f%0x4?_0x53c5a0*0x40+_0x37ec95:_0x37ec95,_0x16124f++%0x4)?_0x18adee+=String['fromCharCode'](0xff&_0x53c5a0>>(-0x2*_0x16124f&0x6)):0x0){_0x37ec95=_0x461482['indexOf'](_0x37ec95);}for(let _0x38e7d2=0x0,_0x3c33c2=_0x18adee['length'];_0x38e7d2<_0x3c33c2;_0x38e7d2++){_0x441f97+='%'+('00'+_0x18adee['charCodeAt'](_0x38e7d2)['toString'](0x10))['slice'](-0x2);}return decodeURIComponent(_0x441f97);};a0_0x1c8b['rntKeQ']=_0x1edb14,a0_0x1c8b['BlypLX']={},a0_0x1c8b['AAJgmy']=!![];}const _0x215938=_0x205836[0x0],_0x6ee9e5=_0x1ca11e+_0x215938,_0x4af88c=a0_0x1c8b['BlypLX'][_0x6ee9e5];return!_0x4af88c?(_0x1c8b2d=a0_0x1c8b['rntKeQ'](_0x1c8b2d),a0_0x1c8b['BlypLX'][_0x6ee9e5]=_0x1c8b2d):_0x1c8b2d=_0x4af88c,_0x1c8b2d;}import a0_0x16124f from'path';import{TOOL_STATUS,SYSTEM_DEFAULTS}from'../utilities/constants.js';class CloneDetectionTool extends BaseTool{constructor(_0x53c5a0={},_0x37ec95=null){const _0x4eec16=a0_0x1c8b;super(_0x53c5a0,_0x37ec95),this[_0x4eec16(0x225)]=!![],this[_0x4eec16(0x219)]=![],this['timeout']=_0x53c5a0[_0x4eec16(0x21a)]||0x1d4c0,this['maxConcurrentOperations']=_0x53c5a0[_0x4eec16(0x23a)]||0x1,this[_0x4eec16(0x1ed)]=_0x53c5a0['defaultMinTokens']||0x32,this['defaultMinLines']=_0x53c5a0['defaultMinLines']||0x5,this['defaultSimilarityThreshold']=_0x53c5a0[_0x4eec16(0x211)]||0.85,this[_0x4eec16(0x23b)]=_0x53c5a0['maxFileSize']||0x7a120,this['directoryAccessManager']=new a0_0x441f97(_0x53c5a0,_0x37ec95),this['cloneDetector']=null;}[a0_0x24898f(0x1db)](){const _0x5a4506=a0_0x24898f;return _0x5a4506(0x22a)+Math['round'](this['maxFileSize']/0x400)+_0x5a4506(0x228)+this['timeout']/0x3e8+_0x5a4506(0x200);}['parseParameters'](_0x207271){const _0x4d0831=a0_0x24898f;try{const _0x38e7d2={},_0x3c33c2=[];this[_0x4d0831(0x240)]?.[_0x4d0831(0x235)]('CloneDetection\x20tool\x20parsing\x20parameters',{'contentLength':_0x207271['length'],'contentPreview':_0x207271['substring'](0x0,0xc8)});const _0xe2568e=/<detect-clones\s+(.+?)\/>/g;let _0x55ab34;while((_0x55ab34=_0xe2568e['exec'](_0x207271))!==null){const _0x78ff65=_0x55ab34[0x1]['trim'](),_0x89f67a=new a0_0x18adee(),_0x231f56=_0x89f67a['parseAttributes'](_0x78ff65),_0xbb4837={'type':'detect-clones',..._0x231f56};_0xbb4837['min-tokens']&&(_0xbb4837[_0x4d0831(0x1f1)]=parseInt(_0xbb4837[_0x4d0831(0x1de)],0xa),delete _0xbb4837['min-tokens']),_0xbb4837['min-lines']&&(_0xbb4837[_0x4d0831(0x213)]=parseInt(_0xbb4837['min-lines'],0xa),delete _0xbb4837['min-lines']),_0xbb4837['similarity-threshold']&&(_0xbb4837['similarityThreshold']=parseFloat(_0xbb4837[_0x4d0831(0x1fe)]),delete _0xbb4837['similarity-threshold']),_0xbb4837['priority-filter']&&(_0xbb4837['priorityFilter']=_0xbb4837['priority-filter'],delete _0xbb4837['priority-filter']),_0xbb4837['max-results']&&(_0xbb4837['maxResults']=parseInt(_0xbb4837[_0x4d0831(0x21d)],0xa),delete _0xbb4837['max-results']),_0xbb4837['output-mode']&&(_0xbb4837[_0x4d0831(0x1ee)]=_0xbb4837['output-mode'],delete _0xbb4837['output-mode']),_0x3c33c2['push'](_0xbb4837);}return _0x38e7d2[_0x4d0831(0x212)]=_0x3c33c2,_0x38e7d2['rawContent']=_0x207271[_0x4d0831(0x233)](),this[_0x4d0831(0x240)]?.[_0x4d0831(0x235)]('Parsed\x20CloneDetection\x20tool\x20parameters',{'totalActions':_0x3c33c2['length'],'actionTypes':_0x3c33c2['map'](_0x39b362=>_0x39b362[_0x4d0831(0x232)])}),_0x38e7d2;}catch(_0x423c3e){throw new Error(_0x4d0831(0x1fc)+_0x423c3e[_0x4d0831(0x1e7)]);}}['getRequiredParameters'](){return['actions'];}['customValidateParameters'](_0x47482d){const _0x4e6337=a0_0x24898f,_0x40c453=[];if(!_0x47482d[_0x4e6337(0x212)]||!Array[_0x4e6337(0x1f4)](_0x47482d['actions'])||_0x47482d['actions']['length']===0x0)_0x40c453[_0x4e6337(0x227)](_0x4e6337(0x223));else for(const [_0x1ecb52,_0x526955]of _0x47482d[_0x4e6337(0x212)][_0x4e6337(0x215)]()){if(!_0x526955['type']){_0x40c453['push'](_0x4e6337(0x23c)+(_0x1ecb52+0x1)+':\x20type\x20is\x20required');continue;}_0x526955[_0x4e6337(0x232)]===_0x4e6337(0x22c)?(!_0x526955['directory']&&_0x40c453['push'](_0x4e6337(0x23c)+(_0x1ecb52+0x1)+_0x4e6337(0x1e3)),_0x526955['minTokens']!==undefined&&(_0x526955[_0x4e6337(0x1f1)]<0xa||_0x526955['minTokens']>0x3e8)&&_0x40c453[_0x4e6337(0x227)](_0x4e6337(0x23c)+(_0x1ecb52+0x1)+':\x20min-tokens\x20must\x20be\x20between\x2010\x20and\x201000'),_0x526955[_0x4e6337(0x213)]!==undefined&&(_0x526955['minLines']<0x1||_0x526955[_0x4e6337(0x213)]>0x64)&&_0x40c453[_0x4e6337(0x227)]('Action\x20'+(_0x1ecb52+0x1)+_0x4e6337(0x21e)),_0x526955[_0x4e6337(0x209)]!==undefined&&(_0x526955['similarityThreshold']<0.5||_0x526955['similarityThreshold']>0x1)&&_0x40c453['push'](_0x4e6337(0x23c)+(_0x1ecb52+0x1)+':\x20similarity-threshold\x20must\x20be\x20between\x200.5\x20and\x201.0'),_0x526955['priorityFilter']&&![_0x4e6337(0x1e0),_0x4e6337(0x22d),_0x4e6337(0x1f2)]['includes'](_0x526955[_0x4e6337(0x1f6)])&&_0x40c453[_0x4e6337(0x227)](_0x4e6337(0x23c)+(_0x1ecb52+0x1)+_0x4e6337(0x203)),_0x526955['outputMode']&&![_0x4e6337(0x204),'detailed','recommendations'][_0x4e6337(0x1e1)](_0x526955[_0x4e6337(0x1ee)])&&_0x40c453['push']('Action\x20'+(_0x1ecb52+0x1)+':\x20output-mode\x20must\x20be\x20summary,\x20detailed,\x20or\x20recommendations')):_0x40c453[_0x4e6337(0x227)]('Action\x20'+(_0x1ecb52+0x1)+_0x4e6337(0x1e9)+_0x526955[_0x4e6337(0x232)]);}return{'valid':_0x40c453[_0x4e6337(0x205)]===0x0,'errors':_0x40c453};}async['execute'](_0xfc7191,_0x2bf144){const _0x13f086=a0_0x24898f,{actions:_0x3d38bd}=_0xfc7191,{projectDir:_0x24c018,agentId:_0x2eda08,directoryAccess:_0x6ef149}=_0x2bf144,_0x5757d6=_0x6ef149||this[_0x13f086(0x217)]['createDirectoryAccess']({'workingDirectory':_0x24c018||process[_0x13f086(0x23d)](),'writeEnabledDirectories':[],'readOnlyDirectories':[_0x24c018||process[_0x13f086(0x23d)]()],'restrictToProject':!![]}),_0x24dbb9=this['directoryAccessManager'][_0x13f086(0x237)](_0x5757d6),_0x57e110=[];for(const _0x4da63c of _0x3d38bd){try{if(_0x4da63c[_0x13f086(0x232)]==='detect-clones'){const _0x1c70aa=await this[_0x13f086(0x1fa)](_0x4da63c[_0x13f086(0x238)],_0x24dbb9,_0x5757d6,_0x4da63c);_0x57e110['push'](_0x1c70aa);}else throw new Error(_0x13f086(0x1df)+_0x4da63c[_0x13f086(0x232)]);}catch(_0x5e8419){this[_0x13f086(0x240)]?.['error']('Clone\x20detection\x20action\x20failed',{'action':_0x4da63c[_0x13f086(0x232)],'error':_0x5e8419[_0x13f086(0x1e7)]}),_0x57e110[_0x13f086(0x227)]({'directory':_0x4da63c['directory'],'error':_0x5e8419[_0x13f086(0x1e7)],'success':![]});}}return{'success':!![],'results':_0x57e110,'toolUsed':_0x13f086(0x22b)};}async['detectClones'](_0x8e25b2,_0x1bbdf5,_0xd8905d,_0x232289={}){const _0x1798a4=a0_0x24898f,_0x546864=a0_0x16124f['isAbsolute'](_0x8e25b2)?a0_0x16124f['normalize'](_0x8e25b2):a0_0x16124f['resolve'](_0x1bbdf5,_0x8e25b2),_0x43bf6d=this['directoryAccessManager']['validateReadAccess'](_0x546864,_0xd8905d);if(!_0x43bf6d['allowed'])throw new Error(_0x1798a4(0x1fb)+_0x43bf6d['reason']);try{const _0x2a5327=await this['getCloneDetector'](),_0x2736ba={'minTokens':_0x232289['minTokens']||this[_0x1798a4(0x1ed)],'minLines':_0x232289['minLines']||this['defaultMinLines'],'similarityThreshold':_0x232289['similarityThreshold']||this[_0x1798a4(0x211)],'include':[_0x1798a4(0x202),'**/*.jsx',_0x1798a4(0x1da),'**/*.cjs',_0x1798a4(0x206),_0x1798a4(0x226),'**/*.vue'],'exclude':['**/node_modules/**',_0x1798a4(0x1fd),_0x1798a4(0x1e6),_0x1798a4(0x230),'**/*.spec.js'],'maxFileSize':this[_0x1798a4(0x23b)]};this['logger']?.[_0x1798a4(0x20f)]('Starting\x20clone\x20detection',{'directory':_0x546864,'config':_0x2736ba});const _0x7d5c69=await _0x2a5327['run'](_0x546864,null);if(!_0x7d5c69)return{'directory':this['directoryAccessManager']['createRelativePath'](_0x546864,_0xd8905d),'fullPath':_0x546864,'success':!![],'summary':{'totalFiles':0x0,'totalClones':0x0,'duplicationPercentage':0x0},'clones':[],'message':_0x1798a4(0x1f3)};let _0x35dd89=_0x7d5c69['clones'];_0x232289['priorityFilter']&&(_0x35dd89=_0x35dd89[_0x1798a4(0x20c)](_0x161884=>_0x161884['refactoringAdvice'][_0x1798a4(0x1e5)]===_0x232289['priorityFilter']));_0x232289[_0x1798a4(0x216)]&&(_0x35dd89=_0x35dd89['slice'](0x0,_0x232289[_0x1798a4(0x216)]));const _0x4bfd3d=_0x232289['outputMode']||'detailed';if(_0x4bfd3d===_0x1798a4(0x204))return this[_0x1798a4(0x21f)](_0x7d5c69,_0x35dd89,_0x546864,_0xd8905d);else return _0x4bfd3d==='recommendations'?this['formatRecommendationsOutput'](_0x7d5c69,_0x35dd89,_0x546864,_0xd8905d):this[_0x1798a4(0x20d)](_0x7d5c69,_0x35dd89,_0x546864,_0xd8905d);}catch(_0x3168cd){throw new Error('Failed\x20to\x20detect\x20clones\x20in\x20'+_0x8e25b2+':\x20'+_0x3168cd[_0x1798a4(0x1e7)]);}}['formatSummaryOutput'](_0x4af6f6,_0x480fb5,_0x3b6a59,_0x34bfd1){const _0x2c8062=a0_0x24898f;return{'directory':this[_0x2c8062(0x217)]['createRelativePath'](_0x3b6a59,_0x34bfd1),'fullPath':_0x3b6a59,'success':!![],'outputMode':'summary','summary':{'totalFiles':_0x4af6f6['summary']['totalFiles'],'totalClones':_0x4af6f6[_0x2c8062(0x204)]['totalClones'],'duplicatedLines':_0x4af6f6['summary'][_0x2c8062(0x1ff)],'duplicationPercentage':_0x4af6f6[_0x2c8062(0x204)][_0x2c8062(0x222)],'priorityCounts':_0x4af6f6['summary']['priorityCounts'],'topClones':_0x480fb5[_0x2c8062(0x201)](0x0,0x5)['map'](_0x8e18ad=>({'id':_0x8e18ad['id'],'type':_0x8e18ad[_0x2c8062(0x232)],'confidence':_0x8e18ad[_0x2c8062(0x1f5)],'instances':_0x8e18ad['metrics'][_0x2c8062(0x221)],'lines':_0x8e18ad[_0x2c8062(0x220)][_0x2c8062(0x22f)],'priority':_0x8e18ad[_0x2c8062(0x1ef)]['priority'],'strategy':_0x8e18ad['refactoringAdvice']['strategy'],'locations':_0x8e18ad[_0x2c8062(0x229)]['map'](_0x1bc0e4=>_0x1bc0e4[_0x2c8062(0x23e)]+':'+_0x1bc0e4['startLine']+'-'+_0x1bc0e4['endLine'])}))}};}[a0_0x24898f(0x21b)](_0x561b9d,_0x3b14f5,_0x9d1b52,_0x4cb81a){const _0x1cf90d=a0_0x24898f;return{'directory':this[_0x1cf90d(0x217)][_0x1cf90d(0x20b)](_0x9d1b52,_0x4cb81a),'fullPath':_0x9d1b52,'success':!![],'outputMode':_0x1cf90d(0x1eb),'summary':{'totalFiles':_0x561b9d['summary']['totalFiles'],'totalClones':_0x561b9d[_0x1cf90d(0x204)][_0x1cf90d(0x22e)],'duplicationPercentage':_0x561b9d['summary'][_0x1cf90d(0x222)]},'recommendations':_0x3b14f5[_0x1cf90d(0x20e)](_0x3b2ec0=>({'id':_0x3b2ec0['id'],'priority':_0x3b2ec0[_0x1cf90d(0x1ef)][_0x1cf90d(0x1e5)],'strategy':_0x3b2ec0[_0x1cf90d(0x1ef)]['strategy'],'suggestedName':_0x3b2ec0['refactoringAdvice'][_0x1cf90d(0x1dd)],'reasoning':_0x3b2ec0[_0x1cf90d(0x1ef)]['reasoning'],'effort':_0x3b2ec0['refactoringAdvice'][_0x1cf90d(0x1ea)],'benefits':_0x3b2ec0['refactoringAdvice'][_0x1cf90d(0x1f7)],'steps':_0x3b2ec0[_0x1cf90d(0x1ef)]['actionableSteps'],'metrics':{'instances':_0x3b2ec0[_0x1cf90d(0x220)][_0x1cf90d(0x221)],'lines':_0x3b2ec0['metrics'][_0x1cf90d(0x22f)],'files':_0x3b2ec0['metrics']['filesCovered'],'impact':_0x3b2ec0['metrics']['impactScore']},'locations':_0x3b2ec0['instances'][_0x1cf90d(0x20e)](_0x3d2b3a=>({'file':_0x3d2b3a['file'],'startLine':_0x3d2b3a['startLine'],'endLine':_0x3d2b3a['endLine']}))}))};}[a0_0x24898f(0x20d)](_0x1d40d1,_0x4ac694,_0x228067,_0x2b3071){const _0x2a380a=a0_0x24898f;return{'directory':this['directoryAccessManager']['createRelativePath'](_0x228067,_0x2b3071),'fullPath':_0x228067,'success':!![],'outputMode':_0x2a380a(0x214),'summary':_0x1d40d1['summary'],'clones':_0x4ac694['map'](_0x50bf13=>({..._0x50bf13,'instances':_0x50bf13['instances'][_0x2a380a(0x20e)](_0x24116e=>({..._0x24116e,'code':_0x24116e[_0x2a380a(0x20a)][_0x2a380a(0x210)]('\x0a')['slice'](0x0,0xa)[_0x2a380a(0x234)]('\x0a')+(_0x24116e['code']['split']('\x0a')[_0x2a380a(0x205)]>0xa?'\x0a...\x20(truncated)':'')}))}))};}async['getCloneDetector'](){const _0x55b1fd=a0_0x24898f;if(!this['cloneDetector']){const {CloneDetectionTool:_0x4b2be2}=await import(_0x55b1fd(0x1f8)),_0x4ed9fc={'minTokens':this[_0x55b1fd(0x1ed)],'minLines':this[_0x55b1fd(0x242)],'similarityThreshold':this[_0x55b1fd(0x211)],'include':['**/*.js','**/*.jsx','**/*.ts',_0x55b1fd(0x226),_0x55b1fd(0x1e8)],'exclude':['**/node_modules/**','**/dist/**','**/build/**'],'maxFileSize':this[_0x55b1fd(0x23b)]};this[_0x55b1fd(0x231)]=new _0x4b2be2(_0x4ed9fc),this['logger']?.[_0x55b1fd(0x235)]('Clone\x20detector\x20initialized',{'config':_0x4ed9fc});}return this[_0x55b1fd(0x231)];}[a0_0x24898f(0x224)](){const _0x306d93=a0_0x24898f;return[_0x306d93(0x22c)];}['getParameterSchema'](){const _0x51796=a0_0x24898f;return{'type':_0x51796(0x207),'properties':{'actions':{'type':_0x51796(0x239),'minItems':0x1,'items':{'type':_0x51796(0x207),'properties':{'type':{'type':_0x51796(0x21c),'enum':this['getSupportedActions']()},'directory':{'type':'string'},'minTokens':{'type':_0x51796(0x1f0),'minimum':0xa,'maximum':0x3e8},'minLines':{'type':_0x51796(0x1f0),'minimum':0x1,'maximum':0x64},'similarityThreshold':{'type':'number','minimum':0.5,'maximum':0x1},'priorityFilter':{'type':'string','enum':[_0x51796(0x1e0),_0x51796(0x22d),_0x51796(0x1f2)]},'maxResults':{'type':_0x51796(0x1f0),'minimum':0x1},'outputMode':{'type':'string','enum':[_0x51796(0x204),_0x51796(0x214),_0x51796(0x1eb)]}},'required':[_0x51796(0x232),_0x51796(0x238)]}}},'required':[_0x51796(0x212)]};}}export default CloneDetectionTool;