@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.
- package/README.md +44 -54
- package/bin/cli.js +1 -115
- package/bin/loxia-terminal-v2.js +3 -0
- package/bin/loxia-terminal.js +3 -0
- package/bin/start-with-terminal.js +3 -0
- package/package.json +15 -15
- package/scripts/install-scanners.js +1 -235
- package/src/analyzers/CSSAnalyzer.js +1 -297
- package/src/analyzers/ConfigValidator.js +1 -690
- package/src/analyzers/ESLintAnalyzer.js +1 -320
- package/src/analyzers/JavaScriptAnalyzer.js +1 -261
- package/src/analyzers/PrettierFormatter.js +1 -247
- package/src/analyzers/PythonAnalyzer.js +1 -266
- package/src/analyzers/SecurityAnalyzer.js +1 -729
- package/src/analyzers/TypeScriptAnalyzer.js +1 -247
- package/src/analyzers/codeCloneDetector/analyzer.js +1 -344
- package/src/analyzers/codeCloneDetector/detector.js +1 -203
- package/src/analyzers/codeCloneDetector/index.js +1 -160
- package/src/analyzers/codeCloneDetector/parser.js +1 -199
- package/src/analyzers/codeCloneDetector/reporter.js +1 -148
- package/src/analyzers/codeCloneDetector/scanner.js +1 -59
- package/src/core/agentPool.js +1 -1474
- package/src/core/agentScheduler.js +1 -2147
- package/src/core/contextManager.js +1 -709
- package/src/core/messageProcessor.js +1 -732
- package/src/core/orchestrator.js +1 -548
- package/src/core/stateManager.js +1 -877
- package/src/index.js +1 -631
- package/src/interfaces/cli.js +1 -549
- package/src/interfaces/terminal/__tests__/smoke/advancedFeatures.test.js +1 -0
- package/src/interfaces/terminal/__tests__/smoke/agentControl.test.js +1 -0
- package/src/interfaces/terminal/__tests__/smoke/agents.test.js +1 -0
- package/src/interfaces/terminal/__tests__/smoke/components.test.js +1 -0
- package/src/interfaces/terminal/__tests__/smoke/connection.test.js +1 -0
- package/src/interfaces/terminal/__tests__/smoke/enhancements.test.js +1 -0
- package/src/interfaces/terminal/__tests__/smoke/imports.test.js +1 -0
- package/src/interfaces/terminal/__tests__/smoke/messages.test.js +1 -0
- package/src/interfaces/terminal/__tests__/smoke/tools.test.js +1 -0
- package/src/interfaces/terminal/api/apiClient.js +1 -0
- package/src/interfaces/terminal/api/messageRouter.js +1 -0
- package/src/interfaces/terminal/api/session.js +1 -0
- package/src/interfaces/terminal/api/websocket.js +1 -0
- package/src/interfaces/terminal/components/AgentCreator.js +1 -0
- package/src/interfaces/terminal/components/AgentEditor.js +1 -0
- package/src/interfaces/terminal/components/AgentSwitcher.js +1 -0
- package/src/interfaces/terminal/components/ErrorBoundary.js +1 -0
- package/src/interfaces/terminal/components/ErrorPanel.js +1 -0
- package/src/interfaces/terminal/components/Header.js +1 -0
- package/src/interfaces/terminal/components/HelpPanel.js +1 -0
- package/src/interfaces/terminal/components/InputBox.js +1 -0
- package/src/interfaces/terminal/components/Layout.js +1 -0
- package/src/interfaces/terminal/components/LoadingSpinner.js +1 -0
- package/src/interfaces/terminal/components/MessageList.js +1 -0
- package/src/interfaces/terminal/components/MultilineTextInput.js +1 -0
- package/src/interfaces/terminal/components/SearchPanel.js +1 -0
- package/src/interfaces/terminal/components/SettingsPanel.js +1 -0
- package/src/interfaces/terminal/components/StatusBar.js +1 -0
- package/src/interfaces/terminal/components/TextInput.js +1 -0
- package/src/interfaces/terminal/config/agentEditorConstants.js +1 -0
- package/src/interfaces/terminal/config/constants.js +1 -0
- package/src/interfaces/terminal/index.js +1 -0
- package/src/interfaces/terminal/state/useAgentControl.js +1 -0
- package/src/interfaces/terminal/state/useAgents.js +1 -0
- package/src/interfaces/terminal/state/useConnection.js +1 -0
- package/src/interfaces/terminal/state/useMessages.js +1 -0
- package/src/interfaces/terminal/state/useTools.js +1 -0
- package/src/interfaces/terminal/utils/debugLogger.js +1 -0
- package/src/interfaces/terminal/utils/settingsStorage.js +1 -0
- package/src/interfaces/terminal/utils/theme.js +1 -0
- package/src/interfaces/webServer.js +1 -2162
- package/src/modules/fileExplorer/controller.js +1 -280
- package/src/modules/fileExplorer/index.js +1 -37
- package/src/modules/fileExplorer/middleware.js +1 -92
- package/src/modules/fileExplorer/routes.js +1 -125
- package/src/modules/fileExplorer/types.js +1 -44
- package/src/services/aiService.js +1 -1232
- package/src/services/apiKeyManager.js +1 -164
- package/src/services/benchmarkService.js +1 -366
- package/src/services/budgetService.js +1 -539
- package/src/services/contextInjectionService.js +1 -247
- package/src/services/conversationCompactionService.js +1 -637
- package/src/services/errorHandler.js +1 -810
- package/src/services/fileAttachmentService.js +1 -544
- package/src/services/modelRouterService.js +1 -366
- package/src/services/modelsService.js +1 -322
- package/src/services/qualityInspector.js +1 -796
- package/src/services/tokenCountingService.js +1 -536
- package/src/tools/agentCommunicationTool.js +1 -1344
- package/src/tools/agentDelayTool.js +1 -485
- package/src/tools/asyncToolManager.js +1 -604
- package/src/tools/baseTool.js +1 -800
- package/src/tools/browserTool.js +1 -920
- package/src/tools/cloneDetectionTool.js +1 -621
- package/src/tools/dependencyResolverTool.js +1 -1215
- package/src/tools/fileContentReplaceTool.js +1 -875
- package/src/tools/fileSystemTool.js +1 -1107
- package/src/tools/fileTreeTool.js +1 -853
- package/src/tools/imageTool.js +1 -901
- package/src/tools/importAnalyzerTool.js +1 -1060
- package/src/tools/jobDoneTool.js +1 -248
- package/src/tools/seekTool.js +1 -956
- package/src/tools/staticAnalysisTool.js +1 -1778
- package/src/tools/taskManagerTool.js +1 -2873
- package/src/tools/terminalTool.js +1 -2304
- package/src/tools/webTool.js +1 -1430
- package/src/types/agent.js +1 -519
- package/src/types/contextReference.js +1 -972
- package/src/types/conversation.js +1 -730
- package/src/types/toolCommand.js +1 -747
- package/src/utilities/attachmentValidator.js +1 -292
- package/src/utilities/configManager.js +1 -582
- package/src/utilities/constants.js +1 -722
- package/src/utilities/directoryAccessManager.js +1 -535
- package/src/utilities/fileProcessor.js +1 -307
- package/src/utilities/logger.js +1 -436
- package/src/utilities/tagParser.js +1 -1246
- package/src/utilities/toolConstants.js +1 -317
- package/web-ui/build/index.html +2 -2
- package/web-ui/build/static/{index-Dy2bYbOa.css → index-CClD1090.css} +1 -1
- package/web-ui/build/static/{index-CjkkcnFA.js → index-lCBai6dX.js} +66 -67
|
@@ -1,203 +1 @@
|
|
|
1
|
-
|
|
2
|
-
* Detects code clones across files
|
|
3
|
-
*/
|
|
4
|
-
export class CloneDetector {
|
|
5
|
-
constructor(config, parser) {
|
|
6
|
-
this.config = config;
|
|
7
|
-
this.parser = parser;
|
|
8
|
-
}
|
|
9
|
-
|
|
10
|
-
/**
|
|
11
|
-
* Find all clones in parsed files
|
|
12
|
-
* @param {Array} parsedFiles - Array of parsed file objects
|
|
13
|
-
* @returns {Array} Array of clone groups
|
|
14
|
-
*/
|
|
15
|
-
detectClones(parsedFiles) {
|
|
16
|
-
console.log('Detecting clones...');
|
|
17
|
-
|
|
18
|
-
const clones = [];
|
|
19
|
-
const allBlocks = [];
|
|
20
|
-
|
|
21
|
-
// Collect all code blocks
|
|
22
|
-
for (const file of parsedFiles) {
|
|
23
|
-
allBlocks.push(...file.blocks);
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
console.log(`Analyzing ${allBlocks.length} code blocks`);
|
|
27
|
-
|
|
28
|
-
// Group blocks by hash for exact clones
|
|
29
|
-
const hashGroups = this.groupByHash(allBlocks);
|
|
30
|
-
|
|
31
|
-
// Find exact clones
|
|
32
|
-
for (const [hash, blocks] of Object.entries(hashGroups)) {
|
|
33
|
-
if (blocks.length > 1) {
|
|
34
|
-
clones.push({
|
|
35
|
-
type: 'exact',
|
|
36
|
-
confidence: 1.0,
|
|
37
|
-
blocks,
|
|
38
|
-
tokenCount: blocks[0].tokens.length
|
|
39
|
-
});
|
|
40
|
-
}
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
// Find similar clones (more expensive)
|
|
44
|
-
const similarClones = this.findSimilarClones(allBlocks);
|
|
45
|
-
clones.push(...similarClones);
|
|
46
|
-
|
|
47
|
-
console.log(`Found ${clones.length} clone groups`);
|
|
48
|
-
return clones;
|
|
49
|
-
}
|
|
50
|
-
|
|
51
|
-
/**
|
|
52
|
-
* Group blocks by hash
|
|
53
|
-
*/
|
|
54
|
-
groupByHash(blocks) {
|
|
55
|
-
const groups = {};
|
|
56
|
-
|
|
57
|
-
for (const block of blocks) {
|
|
58
|
-
if (block.tokens.length < this.config.minTokens) continue;
|
|
59
|
-
|
|
60
|
-
if (!groups[block.hash]) {
|
|
61
|
-
groups[block.hash] = [];
|
|
62
|
-
}
|
|
63
|
-
groups[block.hash].push(block);
|
|
64
|
-
}
|
|
65
|
-
|
|
66
|
-
return groups;
|
|
67
|
-
}
|
|
68
|
-
|
|
69
|
-
/**
|
|
70
|
-
* Find similar (but not exact) clones
|
|
71
|
-
*/
|
|
72
|
-
findSimilarClones(blocks) {
|
|
73
|
-
const similarClones = [];
|
|
74
|
-
const processed = new Set();
|
|
75
|
-
|
|
76
|
-
// Filter blocks that meet minimum size
|
|
77
|
-
const eligibleBlocks = blocks.filter(b =>
|
|
78
|
-
b.tokens.length >= this.config.minTokens
|
|
79
|
-
);
|
|
80
|
-
|
|
81
|
-
for (let i = 0; i < eligibleBlocks.length; i++) {
|
|
82
|
-
const block1 = eligibleBlocks[i];
|
|
83
|
-
const cloneGroup = [block1];
|
|
84
|
-
|
|
85
|
-
if (processed.has(block1.id)) continue;
|
|
86
|
-
|
|
87
|
-
for (let j = i + 1; j < eligibleBlocks.length; j++) {
|
|
88
|
-
const block2 = eligibleBlocks[j];
|
|
89
|
-
|
|
90
|
-
if (processed.has(block2.id)) continue;
|
|
91
|
-
|
|
92
|
-
// Skip if already exact match
|
|
93
|
-
if (block1.hash === block2.hash) continue;
|
|
94
|
-
|
|
95
|
-
// Calculate similarity
|
|
96
|
-
const similarity = this.calculateBlockSimilarity(block1, block2);
|
|
97
|
-
|
|
98
|
-
if (similarity >= this.config.similarityThreshold) {
|
|
99
|
-
cloneGroup.push(block2);
|
|
100
|
-
processed.add(block2.id);
|
|
101
|
-
}
|
|
102
|
-
}
|
|
103
|
-
|
|
104
|
-
if (cloneGroup.length > 1) {
|
|
105
|
-
processed.add(block1.id);
|
|
106
|
-
|
|
107
|
-
similarClones.push({
|
|
108
|
-
type: 'similar',
|
|
109
|
-
confidence: this.calculateGroupConfidence(cloneGroup),
|
|
110
|
-
blocks: cloneGroup,
|
|
111
|
-
tokenCount: Math.max(...cloneGroup.map(b => b.tokens.length))
|
|
112
|
-
});
|
|
113
|
-
}
|
|
114
|
-
}
|
|
115
|
-
|
|
116
|
-
return similarClones;
|
|
117
|
-
}
|
|
118
|
-
|
|
119
|
-
/**
|
|
120
|
-
* Calculate similarity between two blocks
|
|
121
|
-
*/
|
|
122
|
-
calculateBlockSimilarity(block1, block2) {
|
|
123
|
-
const tokens1 = block1.tokens;
|
|
124
|
-
const tokens2 = block2.tokens;
|
|
125
|
-
|
|
126
|
-
// Length similarity
|
|
127
|
-
const lengthRatio = Math.min(tokens1.length, tokens2.length) /
|
|
128
|
-
Math.max(tokens1.length, tokens2.length);
|
|
129
|
-
|
|
130
|
-
if (lengthRatio < 0.7) return 0; // Too different in size
|
|
131
|
-
|
|
132
|
-
// Token sequence similarity using longest common subsequence
|
|
133
|
-
const lcs = this.longestCommonSubsequence(tokens1, tokens2);
|
|
134
|
-
const lcsRatio = (2 * lcs) / (tokens1.length + tokens2.length);
|
|
135
|
-
|
|
136
|
-
return lcsRatio;
|
|
137
|
-
}
|
|
138
|
-
|
|
139
|
-
/**
|
|
140
|
-
* Longest common subsequence length
|
|
141
|
-
*/
|
|
142
|
-
longestCommonSubsequence(seq1, seq2) {
|
|
143
|
-
const m = seq1.length;
|
|
144
|
-
const n = seq2.length;
|
|
145
|
-
|
|
146
|
-
// Use space-optimized version for large sequences
|
|
147
|
-
if (m * n > 100000) {
|
|
148
|
-
return this.approximateLCS(seq1, seq2);
|
|
149
|
-
}
|
|
150
|
-
|
|
151
|
-
const dp = Array(m + 1).fill(0).map(() => Array(n + 1).fill(0));
|
|
152
|
-
|
|
153
|
-
for (let i = 1; i <= m; i++) {
|
|
154
|
-
for (let j = 1; j <= n; j++) {
|
|
155
|
-
if (seq1[i - 1] === seq2[j - 1]) {
|
|
156
|
-
dp[i][j] = dp[i - 1][j - 1] + 1;
|
|
157
|
-
} else {
|
|
158
|
-
dp[i][j] = Math.max(dp[i - 1][j], dp[i][j - 1]);
|
|
159
|
-
}
|
|
160
|
-
}
|
|
161
|
-
}
|
|
162
|
-
|
|
163
|
-
return dp[m][n];
|
|
164
|
-
}
|
|
165
|
-
|
|
166
|
-
/**
|
|
167
|
-
* Approximate LCS for large sequences
|
|
168
|
-
*/
|
|
169
|
-
approximateLCS(seq1, seq2) {
|
|
170
|
-
// Use windowed approach for efficiency
|
|
171
|
-
const windowSize = 100;
|
|
172
|
-
let commonTokens = 0;
|
|
173
|
-
|
|
174
|
-
for (let i = 0; i < seq1.length; i += windowSize) {
|
|
175
|
-
const window1 = seq1.slice(i, i + windowSize);
|
|
176
|
-
const set2 = new Set(seq2.slice(Math.max(0, i - windowSize), i + windowSize * 2));
|
|
177
|
-
|
|
178
|
-
commonTokens += window1.filter(t => set2.has(t)).length;
|
|
179
|
-
}
|
|
180
|
-
|
|
181
|
-
return commonTokens;
|
|
182
|
-
}
|
|
183
|
-
|
|
184
|
-
/**
|
|
185
|
-
* Calculate confidence for a clone group
|
|
186
|
-
*/
|
|
187
|
-
calculateGroupConfidence(blocks) {
|
|
188
|
-
if (blocks.length === 0) return 0;
|
|
189
|
-
|
|
190
|
-
// Calculate average pairwise similarity
|
|
191
|
-
let totalSimilarity = 0;
|
|
192
|
-
let comparisons = 0;
|
|
193
|
-
|
|
194
|
-
for (let i = 0; i < blocks.length; i++) {
|
|
195
|
-
for (let j = i + 1; j < blocks.length; j++) {
|
|
196
|
-
totalSimilarity += this.calculateBlockSimilarity(blocks[i], blocks[j]);
|
|
197
|
-
comparisons++;
|
|
198
|
-
}
|
|
199
|
-
}
|
|
200
|
-
|
|
201
|
-
return comparisons > 0 ? totalSimilarity / comparisons : 0;
|
|
202
|
-
}
|
|
203
|
-
}
|
|
1
|
+
const a0_0xd0f053=a0_0x3767;(function(_0x3d5276,_0x2943ce){const _0x240737=a0_0x3767,_0x418cf9=_0x3d5276();while(!![]){try{const _0x504db9=parseInt(_0x240737(0x19d))/0x1*(parseInt(_0x240737(0x1ae))/0x2)+-parseInt(_0x240737(0x1a0))/0x3+parseInt(_0x240737(0x1ac))/0x4*(-parseInt(_0x240737(0x193))/0x5)+-parseInt(_0x240737(0x19b))/0x6*(parseInt(_0x240737(0x1ad))/0x7)+parseInt(_0x240737(0x1b0))/0x8*(parseInt(_0x240737(0x1b1))/0x9)+-parseInt(_0x240737(0x196))/0xa*(-parseInt(_0x240737(0x1a7))/0xb)+-parseInt(_0x240737(0x190))/0xc*(-parseInt(_0x240737(0x1a3))/0xd);if(_0x504db9===_0x2943ce)break;else _0x418cf9['push'](_0x418cf9['shift']());}catch(_0x417b1c){_0x418cf9['push'](_0x418cf9['shift']());}}}(a0_0x1241,0x71947));export class CloneDetector{constructor(_0x5ee9f5,_0x563b02){const _0x2d9069=a0_0x3767;this[_0x2d9069(0x1a6)]=_0x5ee9f5,this['parser']=_0x563b02;}[a0_0xd0f053(0x1a9)](_0x4f0ccc){const _0x1527db=a0_0xd0f053;console['log'](_0x1527db(0x19e));const _0x3e78d7=[],_0x239a4f=[];for(const _0x38efcd of _0x4f0ccc){_0x239a4f['push'](..._0x38efcd[_0x1527db(0x1a5)]);}console[_0x1527db(0x194)]('Analyzing\x20'+_0x239a4f['length']+_0x1527db(0x1ab));const _0x24a8ce=this[_0x1527db(0x1b3)](_0x239a4f);for(const [_0x407e83,_0x5ec931]of Object[_0x1527db(0x1b2)](_0x24a8ce)){_0x5ec931['length']>0x1&&_0x3e78d7[_0x1527db(0x199)]({'type':_0x1527db(0x1a4),'confidence':0x1,'blocks':_0x5ec931,'tokenCount':_0x5ec931[0x0]['tokens'][_0x1527db(0x195)]});}const _0x61d0a1=this[_0x1527db(0x1aa)](_0x239a4f);return _0x3e78d7[_0x1527db(0x199)](..._0x61d0a1),console['log']('Found\x20'+_0x3e78d7[_0x1527db(0x195)]+'\x20clone\x20groups'),_0x3e78d7;}[a0_0xd0f053(0x1b3)](_0x2ca566){const _0x2da8fe=a0_0xd0f053,_0x3724e4={};for(const _0x361a39 of _0x2ca566){if(_0x361a39['tokens']['length']<this[_0x2da8fe(0x1a6)][_0x2da8fe(0x18f)])continue;!_0x3724e4[_0x361a39['hash']]&&(_0x3724e4[_0x361a39[_0x2da8fe(0x1b4)]]=[]),_0x3724e4[_0x361a39[_0x2da8fe(0x1b4)]][_0x2da8fe(0x199)](_0x361a39);}return _0x3724e4;}['findSimilarClones'](_0x4fc0c2){const _0x44e098=a0_0xd0f053,_0x3c3da0=[],processed=new Set(),_0x5ad940=_0x4fc0c2[_0x44e098(0x197)](_0x1d6d6a=>_0x1d6d6a[_0x44e098(0x198)]['length']>=this['config']['minTokens']);for(let _0x1b2c87=0x0;_0x1b2c87<_0x5ad940[_0x44e098(0x195)];_0x1b2c87++){const _0x25a73d=_0x5ad940[_0x1b2c87],_0x1e6ce7=[_0x25a73d];if(processed[_0x44e098(0x192)](_0x25a73d['id']))continue;for(let _0x52963f=_0x1b2c87+0x1;_0x52963f<_0x5ad940[_0x44e098(0x195)];_0x52963f++){const _0x334975=_0x5ad940[_0x52963f];if(processed['has'](_0x334975['id']))continue;if(_0x25a73d[_0x44e098(0x1b4)]===_0x334975[_0x44e098(0x1b4)])continue;const _0x3d7430=this[_0x44e098(0x19a)](_0x25a73d,_0x334975);_0x3d7430>=this[_0x44e098(0x1a6)][_0x44e098(0x1a1)]&&(_0x1e6ce7['push'](_0x334975),processed['add'](_0x334975['id']));}_0x1e6ce7['length']>0x1&&(processed['add'](_0x25a73d['id']),_0x3c3da0[_0x44e098(0x199)]({'type':'similar','confidence':this['calculateGroupConfidence'](_0x1e6ce7),'blocks':_0x1e6ce7,'tokenCount':Math[_0x44e098(0x1a8)](..._0x1e6ce7[_0x44e098(0x1a2)](_0x3a98db=>_0x3a98db['tokens'][_0x44e098(0x195)]))}));}return _0x3c3da0;}[a0_0xd0f053(0x19a)](_0x369816,_0x1e5ae9){const _0xa0ce20=a0_0xd0f053,_0xc7b4f1=_0x369816[_0xa0ce20(0x198)],_0x1a1594=_0x1e5ae9['tokens'],_0x1cb502=Math['min'](_0xc7b4f1['length'],_0x1a1594['length'])/Math[_0xa0ce20(0x1a8)](_0xc7b4f1['length'],_0x1a1594['length']);if(_0x1cb502<0.7)return 0x0;const _0x298715=this[_0xa0ce20(0x19f)](_0xc7b4f1,_0x1a1594),_0x23846a=0x2*_0x298715/(_0xc7b4f1['length']+_0x1a1594['length']);return _0x23846a;}['longestCommonSubsequence'](_0x51b027,_0x2a9237){const _0x1eb835=a0_0xd0f053,_0x16c655=_0x51b027[_0x1eb835(0x195)],_0x41fa98=_0x2a9237['length'];if(_0x16c655*_0x41fa98>0x186a0)return this['approximateLCS'](_0x51b027,_0x2a9237);const _0x49058e=Array(_0x16c655+0x1)[_0x1eb835(0x19c)](0x0)[_0x1eb835(0x1a2)](()=>Array(_0x41fa98+0x1)[_0x1eb835(0x19c)](0x0));for(let _0x584ec0=0x1;_0x584ec0<=_0x16c655;_0x584ec0++){for(let _0x1a26f6=0x1;_0x1a26f6<=_0x41fa98;_0x1a26f6++){_0x51b027[_0x584ec0-0x1]===_0x2a9237[_0x1a26f6-0x1]?_0x49058e[_0x584ec0][_0x1a26f6]=_0x49058e[_0x584ec0-0x1][_0x1a26f6-0x1]+0x1:_0x49058e[_0x584ec0][_0x1a26f6]=Math['max'](_0x49058e[_0x584ec0-0x1][_0x1a26f6],_0x49058e[_0x584ec0][_0x1a26f6-0x1]);}}return _0x49058e[_0x16c655][_0x41fa98];}[a0_0xd0f053(0x18e)](_0x1b7471,_0x4b21ed){const _0x4d7ec1=a0_0xd0f053,_0x46db14=0x64;let _0x38d4b8=0x0;for(let _0x364d94=0x0;_0x364d94<_0x1b7471[_0x4d7ec1(0x195)];_0x364d94+=_0x46db14){const _0x25d911=_0x1b7471['slice'](_0x364d94,_0x364d94+_0x46db14),_0x2fa3c3=new Set(_0x4b21ed[_0x4d7ec1(0x1af)](Math[_0x4d7ec1(0x1a8)](0x0,_0x364d94-_0x46db14),_0x364d94+_0x46db14*0x2));_0x38d4b8+=_0x25d911[_0x4d7ec1(0x197)](_0x1eef03=>_0x2fa3c3['has'](_0x1eef03))[_0x4d7ec1(0x195)];}return _0x38d4b8;}[a0_0xd0f053(0x191)](_0x60f23f){const _0x472670=a0_0xd0f053;if(_0x60f23f[_0x472670(0x195)]===0x0)return 0x0;let _0x41fd9f=0x0,_0x556941=0x0;for(let _0x109ee0=0x0;_0x109ee0<_0x60f23f['length'];_0x109ee0++){for(let _0x337b93=_0x109ee0+0x1;_0x337b93<_0x60f23f[_0x472670(0x195)];_0x337b93++){_0x41fd9f+=this[_0x472670(0x19a)](_0x60f23f[_0x109ee0],_0x60f23f[_0x337b93]),_0x556941++;}}return _0x556941>0x0?_0x41fd9f/_0x556941:0x0;}}function a0_0x3767(_0x52c89c,_0x39056d){_0x52c89c=_0x52c89c-0x18e;const _0x124132=a0_0x1241();let _0x3767aa=_0x124132[_0x52c89c];if(a0_0x3767['iNNovd']===undefined){var _0x2597f2=function(_0xf558fc){const _0x11b017='abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789+/=';let _0x5ee9f5='',_0x563b02='';for(let _0x4f0ccc=0x0,_0x3e78d7,_0x239a4f,_0x24a8ce=0x0;_0x239a4f=_0xf558fc['charAt'](_0x24a8ce++);~_0x239a4f&&(_0x3e78d7=_0x4f0ccc%0x4?_0x3e78d7*0x40+_0x239a4f:_0x239a4f,_0x4f0ccc++%0x4)?_0x5ee9f5+=String['fromCharCode'](0xff&_0x3e78d7>>(-0x2*_0x4f0ccc&0x6)):0x0){_0x239a4f=_0x11b017['indexOf'](_0x239a4f);}for(let _0x61d0a1=0x0,_0x38efcd=_0x5ee9f5['length'];_0x61d0a1<_0x38efcd;_0x61d0a1++){_0x563b02+='%'+('00'+_0x5ee9f5['charCodeAt'](_0x61d0a1)['toString'](0x10))['slice'](-0x2);}return decodeURIComponent(_0x563b02);};a0_0x3767['QOPuAI']=_0x2597f2,a0_0x3767['mweYnU']={},a0_0x3767['iNNovd']=!![];}const _0x3ff29a=_0x124132[0x0],_0x239efa=_0x52c89c+_0x3ff29a,_0x61973d=a0_0x3767['mweYnU'][_0x239efa];return!_0x61973d?(_0x3767aa=a0_0x3767['QOPuAI'](_0x3767aa),a0_0x3767['mweYnU'][_0x239efa]=_0x3767aa):_0x3767aa=_0x61973d,_0x3767aa;}function a0_0x1241(){const _0x121ba4=['y2fSy3vSyxrLr3jVDxbdB25MAwrLBMnL','AgfZ','nJeXmZbXsgzVuwm','Bg9N','BgvUz3rO','mJbvC2rQuuC','zMLSDgvY','Dg9Rzw5Z','ChvZAa','y2fSy3vSyxrLqMXVy2TtAw1PBgfYAxr5','nJy2AxrsvMz2','zMLSBa','ota0m2DVEhriCa','rgv0zwn0Aw5NignSB25LCY4UlG','Bg9Uz2vZDenVBw1VBLn1yNnLCxvLBMnL','mJm4mJG0ovHPz2LqzG','C2LTAwXHCML0EvrOCMvZAg9Sza','BwfW','mtC4mZGXntHxvhvNthi','zxHHy3q','yMXVy2TZ','y29UzMLN','mJe4ntm3CfLMzfb4','Bwf4','zgv0zwn0q2XVBMvZ','zMLUzfnPBwLSyxjdBg9Uzxm','ignVzguGyMXVy2TZ','mJG0t0HKy1rJ','nduYouvuyKPOCq','odjsu3j6wKC','C2XPy2u','ndC3nLv4EeDIza','nJi4mLr2Evj5uW','zw50CMLLCW','z3jVDxbcEuHHC2G','AgfZAa','yxbWCM94Aw1HDgvmq1m','BwLUvg9Rzw5Z','mtjqwKj1s3y'];a0_0x1241=function(){return _0x121ba4;};return a0_0x1241();}
|
|
@@ -1,160 +1 @@
|
|
|
1
|
-
|
|
2
|
-
import fs from 'fs';
|
|
3
|
-
import path from 'path';
|
|
4
|
-
import { FileScanner } from './scanner.js';
|
|
5
|
-
import { CodeParser } from './parser.js';
|
|
6
|
-
import { CloneDetector } from './detector.js';
|
|
7
|
-
import { RefactoringAnalyzer } from './analyzer.js';
|
|
8
|
-
import { Reporter } from './reporter.js';
|
|
9
|
-
|
|
10
|
-
/**
|
|
11
|
-
* Main clone detection orchestrator
|
|
12
|
-
*/
|
|
13
|
-
class CloneDetectionTool {
|
|
14
|
-
constructor(config) {
|
|
15
|
-
this.config = config;
|
|
16
|
-
this.scanner = new FileScanner(config);
|
|
17
|
-
this.parser = new CodeParser(config);
|
|
18
|
-
this.detector = new CloneDetector(config, this.parser);
|
|
19
|
-
this.analyzer = new RefactoringAnalyzer(config);
|
|
20
|
-
this.reporter = new Reporter();
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
/**
|
|
24
|
-
* Run the complete clone detection pipeline
|
|
25
|
-
*/
|
|
26
|
-
async run(projectPath, outputPath) {
|
|
27
|
-
console.log('Starting Code Clone Detection...\n');
|
|
28
|
-
console.log(`Project: ${projectPath}`);
|
|
29
|
-
console.log(`Config: minTokens=${this.config.minTokens}, minLines=${this.config.minLines}\n`);
|
|
30
|
-
|
|
31
|
-
try {
|
|
32
|
-
// Step 1: Scan files
|
|
33
|
-
console.log('[1/5] Scanning project files...');
|
|
34
|
-
const files = await this.scanner.scanProject(projectPath);
|
|
35
|
-
|
|
36
|
-
if (files.length === 0) {
|
|
37
|
-
console.log('No files found to analyze.');
|
|
38
|
-
return null;
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
// Step 2: Parse and tokenize
|
|
42
|
-
console.log('[2/5] Parsing and tokenizing code...');
|
|
43
|
-
const parsedFiles = files.map(file => this.parser.parseFile(file));
|
|
44
|
-
|
|
45
|
-
// Step 3: Detect clones
|
|
46
|
-
console.log('[3/5] Detecting code clones...');
|
|
47
|
-
const clones = this.detector.detectClones(parsedFiles);
|
|
48
|
-
|
|
49
|
-
if (clones.length === 0) {
|
|
50
|
-
console.log('No significant clones detected.');
|
|
51
|
-
return this.reporter.generateReport([], parsedFiles);
|
|
52
|
-
}
|
|
53
|
-
|
|
54
|
-
// Step 4: Analyze and generate refactoring advice
|
|
55
|
-
console.log('[4/5] Analyzing clones and generating refactoring advice...');
|
|
56
|
-
const analyzedClones = this.analyzer.analyzeClones(clones);
|
|
57
|
-
|
|
58
|
-
// Step 5: Generate report
|
|
59
|
-
console.log('[5/5] Generating report...');
|
|
60
|
-
const report = this.reporter.generateReport(analyzedClones, parsedFiles);
|
|
61
|
-
|
|
62
|
-
// Save report
|
|
63
|
-
if (outputPath) {
|
|
64
|
-
this.reporter.saveReport(report, outputPath);
|
|
65
|
-
}
|
|
66
|
-
|
|
67
|
-
// Print summary
|
|
68
|
-
this.reporter.printSummary(report);
|
|
69
|
-
|
|
70
|
-
// Print AI summary
|
|
71
|
-
console.log('\n📋 AI Agent Summary:');
|
|
72
|
-
console.log(this.reporter.generateAISummary(report));
|
|
73
|
-
console.log();
|
|
74
|
-
|
|
75
|
-
return report;
|
|
76
|
-
} catch (error) {
|
|
77
|
-
console.error('\n❌ Error during clone detection:', error.message);
|
|
78
|
-
console.error(error.stack);
|
|
79
|
-
throw error;
|
|
80
|
-
}
|
|
81
|
-
}
|
|
82
|
-
}
|
|
83
|
-
|
|
84
|
-
/**
|
|
85
|
-
* CLI Interface (disabled for now)
|
|
86
|
-
*/
|
|
87
|
-
async function main() {
|
|
88
|
-
// CLI functionality disabled - use CloneDetectionTool programmatically
|
|
89
|
-
console.error('CLI not available in this version. Use CloneDetectionTool programmatically.');
|
|
90
|
-
process.exit(1);
|
|
91
|
-
// const program = new Command();
|
|
92
|
-
|
|
93
|
-
program
|
|
94
|
-
.name('code-clone-detector')
|
|
95
|
-
.description('AI-powered code clone detection and refactoring advisor')
|
|
96
|
-
.version('1.0.0')
|
|
97
|
-
.argument('<project-path>', 'Path to the project directory to analyze')
|
|
98
|
-
.option('-o, --output <path>', 'Output file path for JSON report', 'clone-report.json')
|
|
99
|
-
.option('-c, --config <path>', 'Path to config file', 'config.json')
|
|
100
|
-
.option('--min-tokens <number>', 'Minimum token count for clones', parseInt)
|
|
101
|
-
.option('--min-lines <number>', 'Minimum line count for clones', parseInt)
|
|
102
|
-
.action(async (projectPath, options) => {
|
|
103
|
-
try {
|
|
104
|
-
// Load config
|
|
105
|
-
let config;
|
|
106
|
-
const configPath = path.resolve(options.config);
|
|
107
|
-
|
|
108
|
-
if (fs.existsSync(configPath)) {
|
|
109
|
-
config = JSON.parse(fs.readFileSync(configPath, 'utf-8'));
|
|
110
|
-
console.log(`Loaded config from: ${configPath}`);
|
|
111
|
-
} else {
|
|
112
|
-
console.log('Using default configuration');
|
|
113
|
-
config = {
|
|
114
|
-
minTokens: 50,
|
|
115
|
-
minLines: 5,
|
|
116
|
-
include: ['**/*.js', '**/*.jsx', '**/*.ts', '**/*.tsx'],
|
|
117
|
-
exclude: ['**/node_modules/**', '**/dist/**', '**/build/**'],
|
|
118
|
-
similarityThreshold: 0.85,
|
|
119
|
-
maxFileSize: 500000
|
|
120
|
-
};
|
|
121
|
-
}
|
|
122
|
-
|
|
123
|
-
// Override with CLI options
|
|
124
|
-
if (options.minTokens) config.minTokens = options.minTokens;
|
|
125
|
-
if (options.minLines) config.minLines = options.minLines;
|
|
126
|
-
|
|
127
|
-
// Resolve paths
|
|
128
|
-
const absProjectPath = path.resolve(projectPath);
|
|
129
|
-
const absOutputPath = path.resolve(options.output);
|
|
130
|
-
|
|
131
|
-
if (!fs.existsSync(absProjectPath)) {
|
|
132
|
-
console.error(`Error: Project path does not exist: ${absProjectPath}`);
|
|
133
|
-
process.exit(1);
|
|
134
|
-
}
|
|
135
|
-
|
|
136
|
-
// Run detection
|
|
137
|
-
const tool = new CloneDetectionTool(config);
|
|
138
|
-
const report = await tool.run(absProjectPath, absOutputPath);
|
|
139
|
-
|
|
140
|
-
if (report) {
|
|
141
|
-
console.log(`✅ Analysis complete! Review the report at: ${absOutputPath}`);
|
|
142
|
-
process.exit(0);
|
|
143
|
-
} else {
|
|
144
|
-
process.exit(1);
|
|
145
|
-
}
|
|
146
|
-
} catch (error) {
|
|
147
|
-
console.error('Fatal error:', error.message);
|
|
148
|
-
process.exit(1);
|
|
149
|
-
}
|
|
150
|
-
});
|
|
151
|
-
|
|
152
|
-
program.parse();
|
|
153
|
-
}
|
|
154
|
-
|
|
155
|
-
// Run CLI if executed directly
|
|
156
|
-
if (import.meta.url === `file://${process.argv[1]}`) {
|
|
157
|
-
main();
|
|
158
|
-
}
|
|
159
|
-
|
|
160
|
-
export { CloneDetectionTool };
|
|
1
|
+
const a0_0xd6d0ac=a0_0x19f6;(function(_0x400998,_0x593fc6){const _0x191c81=a0_0x19f6,_0x452245=_0x400998();while(!![]){try{const _0x20f584=-parseInt(_0x191c81(0x111))/0x1*(parseInt(_0x191c81(0xfc))/0x2)+-parseInt(_0x191c81(0xef))/0x3+parseInt(_0x191c81(0xf0))/0x4+-parseInt(_0x191c81(0xf7))/0x5*(-parseInt(_0x191c81(0xeb))/0x6)+-parseInt(_0x191c81(0x105))/0x7*(-parseInt(_0x191c81(0xfd))/0x8)+parseInt(_0x191c81(0x102))/0x9+-parseInt(_0x191c81(0xec))/0xa;if(_0x20f584===_0x593fc6)break;else _0x452245['push'](_0x452245['shift']());}catch(_0x4f5b00){_0x452245['push'](_0x452245['shift']());}}}(a0_0x44ef,0x3fa20));import a0_0x327cbe from'fs';function a0_0x19f6(_0x28027a,_0x574746){_0x28027a=_0x28027a-0xdd;const _0x44ef97=a0_0x44ef();let _0x19f6ad=_0x44ef97[_0x28027a];if(a0_0x19f6['awtmfZ']===undefined){var _0x2b7508=function(_0x438cf6){const _0x41d43d='abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789+/=';let _0x327cbe='',_0xdcb137='';for(let _0x41be04=0x0,_0x3aa09e,_0x49808e,_0xb9ecb7=0x0;_0x49808e=_0x438cf6['charAt'](_0xb9ecb7++);~_0x49808e&&(_0x3aa09e=_0x41be04%0x4?_0x3aa09e*0x40+_0x49808e:_0x49808e,_0x41be04++%0x4)?_0x327cbe+=String['fromCharCode'](0xff&_0x3aa09e>>(-0x2*_0x41be04&0x6)):0x0){_0x49808e=_0x41d43d['indexOf'](_0x49808e);}for(let _0x12a5d4=0x0,_0x821463=_0x327cbe['length'];_0x12a5d4<_0x821463;_0x12a5d4++){_0xdcb137+='%'+('00'+_0x327cbe['charCodeAt'](_0x12a5d4)['toString'](0x10))['slice'](-0x2);}return decodeURIComponent(_0xdcb137);};a0_0x19f6['UAKKUT']=_0x2b7508,a0_0x19f6['QnksvG']={},a0_0x19f6['awtmfZ']=!![];}const _0x599b93=_0x44ef97[0x0],_0x5ae346=_0x28027a+_0x599b93,_0x43b2f2=a0_0x19f6['QnksvG'][_0x5ae346];return!_0x43b2f2?(_0x19f6ad=a0_0x19f6['UAKKUT'](_0x19f6ad),a0_0x19f6['QnksvG'][_0x5ae346]=_0x19f6ad):_0x19f6ad=_0x43b2f2,_0x19f6ad;}import a0_0xdcb137 from'path';import{FileScanner}from'./scanner.js';import{CodeParser}from'./parser.js';import{CloneDetector}from'./detector.js';import{RefactoringAnalyzer}from'./analyzer.js';import{Reporter}from'./reporter.js';class CloneDetectionTool{constructor(_0x41be04){const _0x268b3c=a0_0x19f6;this[_0x268b3c(0x108)]=_0x41be04,this['scanner']=new FileScanner(_0x41be04),this[_0x268b3c(0xe5)]=new CodeParser(_0x41be04),this[_0x268b3c(0xf6)]=new CloneDetector(_0x41be04,this[_0x268b3c(0xe5)]),this[_0x268b3c(0x106)]=new RefactoringAnalyzer(_0x41be04),this['reporter']=new Reporter();}async['run'](_0x3aa09e,_0x49808e){const _0x421dec=a0_0x19f6;console['log'](_0x421dec(0xe4)),console[_0x421dec(0x115)](_0x421dec(0x10b)+_0x3aa09e),console['log'](_0x421dec(0xf2)+this[_0x421dec(0x108)][_0x421dec(0xf1)]+_0x421dec(0xff)+this['config']['minLines']+'\x0a');try{console[_0x421dec(0x115)](_0x421dec(0xea));const _0xb9ecb7=await this[_0x421dec(0x113)]['scanProject'](_0x3aa09e);if(_0xb9ecb7['length']===0x0)return console[_0x421dec(0x115)]('No\x20files\x20found\x20to\x20analyze.'),null;console['log']('[2/5]\x20Parsing\x20and\x20tokenizing\x20code...');const _0x12a5d4=_0xb9ecb7[_0x421dec(0xe8)](_0x33d7d2=>this['parser'][_0x421dec(0xe2)](_0x33d7d2));console['log'](_0x421dec(0xdd));const _0x821463=this['detector']['detectClones'](_0x12a5d4);if(_0x821463['length']===0x0)return console['log']('No\x20significant\x20clones\x20detected.'),this[_0x421dec(0x109)]['generateReport']([],_0x12a5d4);console[_0x421dec(0x115)](_0x421dec(0xe6));const _0x1a62a4=this['analyzer']['analyzeClones'](_0x821463);console[_0x421dec(0x115)](_0x421dec(0xe1));const _0x53b628=this['reporter']['generateReport'](_0x1a62a4,_0x12a5d4);return _0x49808e&&this['reporter'][_0x421dec(0xe7)](_0x53b628,_0x49808e),this[_0x421dec(0x109)]['printSummary'](_0x53b628),console[_0x421dec(0x115)]('\x0a📋\x20AI\x20Agent\x20Summary:'),console['log'](this['reporter']['generateAISummary'](_0x53b628)),console[_0x421dec(0x115)](),_0x53b628;}catch(_0x581319){console[_0x421dec(0x110)](_0x421dec(0xf8),_0x581319[_0x421dec(0x103)]),console[_0x421dec(0x110)](_0x581319[_0x421dec(0x112)]);throw _0x581319;}}}async function main(){const _0x5f2135=a0_0x19f6;console[_0x5f2135(0x110)](_0x5f2135(0xf4)),process['exit'](0x1),program[_0x5f2135(0x101)](_0x5f2135(0xde))[_0x5f2135(0x100)](_0x5f2135(0xed))[_0x5f2135(0x10c)](_0x5f2135(0x10a))['argument']('<project-path>','Path\x20to\x20the\x20project\x20directory\x20to\x20analyze')[_0x5f2135(0x107)]('-o,\x20--output\x20<path>','Output\x20file\x20path\x20for\x20JSON\x20report','clone-report.json')[_0x5f2135(0x107)]('-c,\x20--config\x20<path>','Path\x20to\x20config\x20file','config.json')['option'](_0x5f2135(0xe0),'Minimum\x20token\x20count\x20for\x20clones',parseInt)[_0x5f2135(0x107)](_0x5f2135(0xe9),_0x5f2135(0x10e),parseInt)[_0x5f2135(0x114)](async(_0xc5bfa7,_0x3f2928)=>{const _0x34dec0=_0x5f2135;try{let _0x1651cc;const _0x356be6=a0_0xdcb137['resolve'](_0x3f2928[_0x34dec0(0x108)]);a0_0x327cbe[_0x34dec0(0xf5)](_0x356be6)?(_0x1651cc=JSON['parse'](a0_0x327cbe['readFileSync'](_0x356be6,'utf-8')),console[_0x34dec0(0x115)](_0x34dec0(0xf3)+_0x356be6)):(console['log']('Using default configuration'),_0x1651cc={'minTokens':0x32,'minLines':0x5,'include':[_0x34dec0(0xfe),'**/*.jsx','**/*.ts',_0x34dec0(0xe3)],'exclude':['**/node_modules/**',_0x34dec0(0x10d),'**/build/**'],'similarityThreshold':0.85,'maxFileSize':0x7a120});if(_0x3f2928['minTokens'])_0x1651cc['minTokens']=_0x3f2928[_0x34dec0(0xf1)];if(_0x3f2928[_0x34dec0(0x104)])_0x1651cc[_0x34dec0(0x104)]=_0x3f2928[_0x34dec0(0x104)];const _0xed6675=a0_0xdcb137[_0x34dec0(0x10f)](_0xc5bfa7),_0x350e89=a0_0xdcb137[_0x34dec0(0x10f)](_0x3f2928[_0x34dec0(0xf9)]);!a0_0x327cbe[_0x34dec0(0xf5)](_0xed6675)&&(console['error']('Error:\x20Project\x20path\x20does\x20not\x20exist:\x20'+_0xed6675),process[_0x34dec0(0xdf)](0x1));const _0x4a3fbe=new CloneDetectionTool(_0x1651cc),_0x252f65=await _0x4a3fbe[_0x34dec0(0xfb)](_0xed6675,_0x350e89);_0x252f65?(console[_0x34dec0(0x115)]('✅\x20Analysis\x20complete!\x20Review\x20the\x20report\x20at:\x20'+_0x350e89),process[_0x34dec0(0xdf)](0x0)):process[_0x34dec0(0xdf)](0x1);}catch(_0x14657b){console['error']('Fatal\x20error:',_0x14657b[_0x34dec0(0x103)]),process[_0x34dec0(0xdf)](0x1);}}),program[_0x5f2135(0xfa)]();}function a0_0x44ef(){const _0x168364=['CgfYC2u','CNvU','nduYmZm4DwP0vKPR','ofvhD0vWqG','kIOVkI5QCW','lcbTAw5mAw5LCZ0','zgvZy3jPChrPB24','BMfTzq','ndiWndq0ouP5EeDhuW','BwvZC2fNzq','BwLUtgLUzxm','ndiWnJa5y3vIy3rn','yw5HBhL6zxi','B3b0Aw9U','y29UzMLN','CMvWB3j0zxi','ms4WlJa','uhjVAMvJDdOG','DMvYC2LVBG','kIOVzgLZDc8QkG','twLUAw11BsbSAw5LignVDw50igzVCIbJBg9Uzxm','CMvZB2X2zq','zxjYB3i','mwXJternAW','C3rHy2S','C2nHBM5LCG','ywn0Aw9U','Bg9N','yxjNDG','wZmVnv0Grgv0zwn0Aw5NignVzguGy2XVBMvZlI4U','y29Kzs1JBg9Uzs1KzxrLy3rVCG','zxHPDa','ls1TAw4TDg9Rzw5ZidXUDw1Izxi+','wZuVnv0Gr2vUzxjHDgLUzYbYzxbVCNqUlI4','CgfYC2vgAwXL','kIOVkI50C3G','u3rHCNrPBMCGq29KzsbdBg9UzsbezxrLy3rPB24UlI4k','CgfYC2vY','wZqVnv0Gqw5HBhL6Aw5NignSB25LCYbHBMqGz2vUzxjHDgLUzYbYzwzHy3rVCMLUzYbHzhzPy2uUlI4','C2f2zvjLCg9YDa','BwfW','ls1TAw4TBgLUzxmGpg51BwjLCJ4','wZeVnv0Gu2nHBM5PBMCGChjVAMvJDcbMAwXLCY4UlG','otq5nZrNCwjZq00','mZi1nJi4mej2BxryyG','quKTCg93zxjLzcbJB2rLignSB25LigrLDgvJDgLVBIbHBMqGCMvMywn0B3jPBMCGywr2AxnVCG','zMLSztOVlW','nti0ntK4r0TAEvfr','mtCXmZu4ohv5rvLzwa','BwLUvg9Rzw5Z','q29UzMLNoIbTAw5uB2TLBNm9','tg9HzgvKignVBMzPzYbMCM9ToIa','q0Xjig5VDcbHDMfPBgfIBguGAw4GDgHPCYb2zxjZAw9UlIbvC2uGq2XVBMvezxrLy3rPB25uB29SihbYB2DYyw1TyxrPy2fSBhKU','zxHPC3rZu3LUyW','zgv0zwn0B3i','mtb2Ehbfv0e','cUkDJcbfCNjVCIbKDxjPBMCGy2XVBMuGzgv0zwn0Aw9UoG','B3v0Chv0'];a0_0x44ef=function(){return _0x168364;};return a0_0x44ef();}import.meta.url===a0_0xd6d0ac(0xee)+process[a0_0xd6d0ac(0x116)][0x1]&&main();export{CloneDetectionTool};
|
|
@@ -1,199 +1 @@
|
|
|
1
|
-
|
|
2
|
-
import traverse from '@babel/traverse';
|
|
3
|
-
import crypto from 'crypto';
|
|
4
|
-
|
|
5
|
-
/**
|
|
6
|
-
* Parses and tokenizes source code
|
|
7
|
-
*/
|
|
8
|
-
export class CodeParser {
|
|
9
|
-
constructor(config) {
|
|
10
|
-
this.config = config;
|
|
11
|
-
}
|
|
12
|
-
|
|
13
|
-
/**
|
|
14
|
-
* Parse file and extract tokens
|
|
15
|
-
* @param {Object} file - File object with content
|
|
16
|
-
* @returns {Object} Parsed file with tokens and AST info
|
|
17
|
-
*/
|
|
18
|
-
parseFile(file) {
|
|
19
|
-
const extension = file.extension;
|
|
20
|
-
|
|
21
|
-
// Handle JavaScript/TypeScript files
|
|
22
|
-
if (['.js', '.jsx', '.ts', '.tsx', '.vue'].includes(extension)) {
|
|
23
|
-
return this.parseJavaScript(file);
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
// Fallback to simple tokenization
|
|
27
|
-
return this.simpleTokenize(file);
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
/**
|
|
31
|
-
* Parse JavaScript/TypeScript with Babel
|
|
32
|
-
*/
|
|
33
|
-
parseJavaScript(file) {
|
|
34
|
-
try {
|
|
35
|
-
const ast = parser.parse(file.content, {
|
|
36
|
-
sourceType: 'module',
|
|
37
|
-
plugins: [
|
|
38
|
-
'jsx',
|
|
39
|
-
'typescript',
|
|
40
|
-
'decorators-legacy',
|
|
41
|
-
'classProperties',
|
|
42
|
-
'optionalChaining',
|
|
43
|
-
'nullishCoalescingOperator'
|
|
44
|
-
],
|
|
45
|
-
errorRecovery: true
|
|
46
|
-
});
|
|
47
|
-
|
|
48
|
-
const tokens = [];
|
|
49
|
-
const blocks = [];
|
|
50
|
-
let blockId = 0;
|
|
51
|
-
|
|
52
|
-
// Extract meaningful code blocks (functions, classes, etc.)
|
|
53
|
-
traverse.default(ast, {
|
|
54
|
-
FunctionDeclaration: (path) => this.extractBlock(path, file, blocks, tokens, blockId++),
|
|
55
|
-
FunctionExpression: (path) => this.extractBlock(path, file, blocks, tokens, blockId++),
|
|
56
|
-
ArrowFunctionExpression: (path) => this.extractBlock(path, file, blocks, tokens, blockId++),
|
|
57
|
-
ClassMethod: (path) => this.extractBlock(path, file, blocks, tokens, blockId++),
|
|
58
|
-
ClassDeclaration: (path) => this.extractBlock(path, file, blocks, tokens, blockId++),
|
|
59
|
-
});
|
|
60
|
-
|
|
61
|
-
// Also create a flat token sequence for the entire file
|
|
62
|
-
const fileTokens = this.extractTokenSequence(ast);
|
|
63
|
-
|
|
64
|
-
return {
|
|
65
|
-
...file,
|
|
66
|
-
ast,
|
|
67
|
-
tokens: fileTokens,
|
|
68
|
-
blocks,
|
|
69
|
-
parsed: true
|
|
70
|
-
};
|
|
71
|
-
} catch (error) {
|
|
72
|
-
console.error(`Parse error in ${file.path}:`, error.message);
|
|
73
|
-
return this.simpleTokenize(file);
|
|
74
|
-
}
|
|
75
|
-
}
|
|
76
|
-
|
|
77
|
-
/**
|
|
78
|
-
* Extract a code block with token sequence
|
|
79
|
-
*/
|
|
80
|
-
extractBlock(path, file, blocks, tokens, blockId) {
|
|
81
|
-
const node = path.node;
|
|
82
|
-
const loc = node.loc;
|
|
83
|
-
|
|
84
|
-
if (!loc) return;
|
|
85
|
-
|
|
86
|
-
// Get the source code for this block
|
|
87
|
-
const lines = file.content.split('\n');
|
|
88
|
-
const blockCode = lines.slice(loc.start.line - 1, loc.end.line).join('\n');
|
|
89
|
-
|
|
90
|
-
// Create token sequence for this block
|
|
91
|
-
const blockTokens = this.tokenizeCode(blockCode);
|
|
92
|
-
|
|
93
|
-
if (blockTokens.length < this.config.minTokens) return;
|
|
94
|
-
|
|
95
|
-
blocks.push({
|
|
96
|
-
id: `${file.path}:block${blockId}`,
|
|
97
|
-
file: file.path,
|
|
98
|
-
startLine: loc.start.line,
|
|
99
|
-
endLine: loc.end.line,
|
|
100
|
-
code: blockCode,
|
|
101
|
-
tokens: blockTokens,
|
|
102
|
-
hash: this.hashTokens(blockTokens),
|
|
103
|
-
type: node.type
|
|
104
|
-
});
|
|
105
|
-
}
|
|
106
|
-
|
|
107
|
-
/**
|
|
108
|
-
* Extract token sequence from AST
|
|
109
|
-
*/
|
|
110
|
-
extractTokenSequence(ast) {
|
|
111
|
-
const tokens = [];
|
|
112
|
-
|
|
113
|
-
traverse.default(ast, {
|
|
114
|
-
enter(path) {
|
|
115
|
-
const node = path.node;
|
|
116
|
-
|
|
117
|
-
// Normalize identifiers but keep structure
|
|
118
|
-
if (node.type === 'Identifier') {
|
|
119
|
-
tokens.push('IDENT');
|
|
120
|
-
} else if (node.type === 'Literal' || node.type === 'StringLiteral' ||
|
|
121
|
-
node.type === 'NumericLiteral' || node.type === 'BooleanLiteral') {
|
|
122
|
-
tokens.push('LIT');
|
|
123
|
-
} else {
|
|
124
|
-
tokens.push(node.type);
|
|
125
|
-
}
|
|
126
|
-
}
|
|
127
|
-
});
|
|
128
|
-
|
|
129
|
-
return tokens;
|
|
130
|
-
}
|
|
131
|
-
|
|
132
|
-
/**
|
|
133
|
-
* Simple tokenization for non-JS files
|
|
134
|
-
*/
|
|
135
|
-
simpleTokenize(file) {
|
|
136
|
-
const tokens = this.tokenizeCode(file.content);
|
|
137
|
-
|
|
138
|
-
return {
|
|
139
|
-
...file,
|
|
140
|
-
tokens,
|
|
141
|
-
blocks: [{
|
|
142
|
-
id: `${file.path}:full`,
|
|
143
|
-
file: file.path,
|
|
144
|
-
startLine: 1,
|
|
145
|
-
endLine: file.content.split('\n').length,
|
|
146
|
-
code: file.content,
|
|
147
|
-
tokens,
|
|
148
|
-
hash: this.hashTokens(tokens),
|
|
149
|
-
type: 'File'
|
|
150
|
-
}],
|
|
151
|
-
parsed: false
|
|
152
|
-
};
|
|
153
|
-
}
|
|
154
|
-
|
|
155
|
-
/**
|
|
156
|
-
* Tokenize code string (language-agnostic)
|
|
157
|
-
*/
|
|
158
|
-
tokenizeCode(code) {
|
|
159
|
-
// Remove comments and normalize
|
|
160
|
-
const cleaned = code
|
|
161
|
-
.replace(/\/\*[\s\S]*?\*\//g, '') // Block comments
|
|
162
|
-
.replace(/\/\/.*/g, '') // Line comments
|
|
163
|
-
.replace(/\s+/g, ' '); // Normalize whitespace
|
|
164
|
-
|
|
165
|
-
// Simple tokenization
|
|
166
|
-
const tokens = cleaned.match(/[a-zA-Z_$][a-zA-Z0-9_$]*|[{}()\[\];,.]|[+\-*/%=<>!&|]+|"[^"]*"|'[^']*'|`[^`]*`|\d+/g) || [];
|
|
167
|
-
|
|
168
|
-
return tokens;
|
|
169
|
-
}
|
|
170
|
-
|
|
171
|
-
/**
|
|
172
|
-
* Create hash of token sequence
|
|
173
|
-
*/
|
|
174
|
-
hashTokens(tokens) {
|
|
175
|
-
return crypto
|
|
176
|
-
.createHash('md5')
|
|
177
|
-
.update(tokens.join(','))
|
|
178
|
-
.digest('hex');
|
|
179
|
-
}
|
|
180
|
-
|
|
181
|
-
/**
|
|
182
|
-
* Calculate similarity between token sequences
|
|
183
|
-
*/
|
|
184
|
-
calculateSimilarity(tokens1, tokens2) {
|
|
185
|
-
const len1 = tokens1.length;
|
|
186
|
-
const len2 = tokens2.length;
|
|
187
|
-
|
|
188
|
-
if (len1 === 0 || len2 === 0) return 0;
|
|
189
|
-
|
|
190
|
-
// Use Jaccard similarity for token sets
|
|
191
|
-
const set1 = new Set(tokens1);
|
|
192
|
-
const set2 = new Set(tokens2);
|
|
193
|
-
|
|
194
|
-
const intersection = new Set([...set1].filter(x => set2.has(x)));
|
|
195
|
-
const union = new Set([...set1, ...set2]);
|
|
196
|
-
|
|
197
|
-
return intersection.size / union.size;
|
|
198
|
-
}
|
|
199
|
-
}
|
|
1
|
+
function a0_0x16ce(_0xac1f85,_0x59c62e){_0xac1f85=_0xac1f85-0xa1;const _0x132141=a0_0x1321();let _0x16ce73=_0x132141[_0xac1f85];if(a0_0x16ce['riZngE']===undefined){var _0x34b659=function(_0x557b5b){const _0x76a3f2='abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789+/=';let _0x2c2752='',_0x6a822='';for(let _0xa51561=0x0,_0x3a484a,_0x3e43ea,_0x240832=0x0;_0x3e43ea=_0x557b5b['charAt'](_0x240832++);~_0x3e43ea&&(_0x3a484a=_0xa51561%0x4?_0x3a484a*0x40+_0x3e43ea:_0x3e43ea,_0xa51561++%0x4)?_0x2c2752+=String['fromCharCode'](0xff&_0x3a484a>>(-0x2*_0xa51561&0x6)):0x0){_0x3e43ea=_0x76a3f2['indexOf'](_0x3e43ea);}for(let _0x54ab17=0x0,_0x4fd4da=_0x2c2752['length'];_0x54ab17<_0x4fd4da;_0x54ab17++){_0x6a822+='%'+('00'+_0x2c2752['charCodeAt'](_0x54ab17)['toString'](0x10))['slice'](-0x2);}return decodeURIComponent(_0x6a822);};a0_0x16ce['LaRcQJ']=_0x34b659,a0_0x16ce['szQHlg']={},a0_0x16ce['riZngE']=!![];}const _0x5bc0f9=_0x132141[0x0],_0x359495=_0xac1f85+_0x5bc0f9,_0xa83c29=a0_0x16ce['szQHlg'][_0x359495];return!_0xa83c29?(_0x16ce73=a0_0x16ce['LaRcQJ'](_0x16ce73),a0_0x16ce['szQHlg'][_0x359495]=_0x16ce73):_0x16ce73=_0xa83c29,_0x16ce73;}const a0_0x18ad7e=a0_0x16ce;(function(_0x51ca0a,_0x5cf6ed){const _0x1f6af6=a0_0x16ce,_0xa5802f=_0x51ca0a();while(!![]){try{const _0x4c3211=parseInt(_0x1f6af6(0xa9))/0x1*(parseInt(_0x1f6af6(0xad))/0x2)+-parseInt(_0x1f6af6(0xbb))/0x3*(parseInt(_0x1f6af6(0xae))/0x4)+-parseInt(_0x1f6af6(0xa6))/0x5+parseInt(_0x1f6af6(0xc0))/0x6+-parseInt(_0x1f6af6(0xa3))/0x7+parseInt(_0x1f6af6(0xbe))/0x8+parseInt(_0x1f6af6(0xbf))/0x9;if(_0x4c3211===_0x5cf6ed)break;else _0xa5802f['push'](_0xa5802f['shift']());}catch(_0x3f8bcc){_0xa5802f['push'](_0xa5802f['shift']());}}}(a0_0x1321,0x32e4f));import*as a0_0x2c2752 from'@babel/parser';function a0_0x1321(){const _0x52d03a=['CgfYC2vkyxzHu2nYAxb0','C2L6zq','BwLUvg9Rzw5Z','Agv4','Aw5JBhvKzxm','BM9Kzq','C2LTCgXLvg9Rzw5PEMu','qM9VBgvHBKXPDgvYywW','AgfZAfrVA2vUCW','Dg9Rzw5PEMvdB2rL','Bw9KDwXL','zgvJB3jHDg9YCY1SzwDHy3K','nJGZmda0vhzLyMLj','y2XHC3nqCM9Wzxj0AwvZ','Bwf0y2G','mtmXnZK3mfnHzLLoDW','zxH0CMfJDejSB2nR','y29UDgvUDa','mta3nJKXCgjSz3rg','C2XPy2u','zw5K','zxjYB3i','mNrny2X5rq','mJmWmhbOA0ryrq','u3rYAw5NtgL0zxjHBa','Bwq1','Cgf0Aa','BgLUzq','CgfYC2u','CMvWBgfJzq','C3rHCNq','CgfYC2vgAwXL','BgvUz3rO','tgL0zxjHBa','y2fSy3vSyxrLu2LTAwXHCML0Eq','y3jLyxrLsgfZAa','mJfoB290uKe','DhLWzq','tNvTzxjPy0XPDgvYywW','mZi4mJCYCwv3shPq','mJC3oty3n05sv01myW','nJK2ndu2Du1xvfDl','y29UzMLN','C3bSAxq','zgvMyxvSDa','ANn4','teLu','zgLNzxn0','lNz1zq'];a0_0x1321=function(){return _0x52d03a;};return a0_0x1321();}import a0_0x6a822 from'@babel/traverse';import a0_0xa51561 from'crypto';export class CodeParser{constructor(_0x3a484a){const _0x166a3a=a0_0x16ce;this[_0x166a3a(0xc1)]=_0x3a484a;}[a0_0x18ad7e(0xb6)](_0x3e43ea){const _0x1bad06=a0_0x18ad7e,_0x240832=_0x3e43ea['extension'];if(['.js','.jsx','.ts','.tsx',_0x1bad06(0xc7)][_0x1bad06(0xcc)](_0x240832))return this[_0x1bad06(0xc8)](_0x3e43ea);return this[_0x1bad06(0xce)](_0x3e43ea);}[a0_0x18ad7e(0xc8)](_0x54ab17){const _0x39cb3c=a0_0x18ad7e;try{const _0x4fd4da=a0_0x2c2752[_0x39cb3c(0xb3)](_0x54ab17[_0x39cb3c(0xa8)],{'sourceType':_0x39cb3c(0xa1),'plugins':[_0x39cb3c(0xc4),'typescript',_0x39cb3c(0xa2),_0x39cb3c(0xa4),'optionalChaining','nullishCoalescingOperator'],'errorRecovery':!![]}),_0x184e25=[],_0x1e4273=[];let _0x4a0e40=0x0;a0_0x6a822[_0x39cb3c(0xc3)](_0x4fd4da,{'FunctionDeclaration':_0x151549=>this[_0x39cb3c(0xa7)](_0x151549,_0x54ab17,_0x1e4273,_0x184e25,_0x4a0e40++),'FunctionExpression':_0x197798=>this['extractBlock'](_0x197798,_0x54ab17,_0x1e4273,_0x184e25,_0x4a0e40++),'ArrowFunctionExpression':_0x127706=>this[_0x39cb3c(0xa7)](_0x127706,_0x54ab17,_0x1e4273,_0x184e25,_0x4a0e40++),'ClassMethod':_0x139851=>this[_0x39cb3c(0xa7)](_0x139851,_0x54ab17,_0x1e4273,_0x184e25,_0x4a0e40++),'ClassDeclaration':_0x3e50c2=>this[_0x39cb3c(0xa7)](_0x3e50c2,_0x54ab17,_0x1e4273,_0x184e25,_0x4a0e40++)});const _0x191c00=this['extractTokenSequence'](_0x4fd4da);return{..._0x54ab17,'ast':_0x4fd4da,'tokens':_0x191c00,'blocks':_0x1e4273,'parsed':!![]};}catch(_0x2ccec7){return console[_0x39cb3c(0xac)]('Parse\x20error\x20in\x20'+_0x54ab17[_0x39cb3c(0xb1)]+':',_0x2ccec7['message']),this['simpleTokenize'](_0x54ab17);}}['extractBlock'](_0x52ccde,_0x21466c,_0x275f35,_0x4d7471,_0x4a0e1d){const _0x3d7fb4=a0_0x18ad7e,_0x5b8167=_0x52ccde[_0x3d7fb4(0xcd)],_0x52e470=_0x5b8167['loc'];if(!_0x52e470)return;const _0x2075cd=_0x21466c[_0x3d7fb4(0xa8)][_0x3d7fb4(0xc2)]('\x0a'),_0x2fd54c=_0x2075cd[_0x3d7fb4(0xaa)](_0x52e470[_0x3d7fb4(0xb5)]['line']-0x1,_0x52e470[_0x3d7fb4(0xab)]['line'])['join']('\x0a'),_0x195193=this['tokenizeCode'](_0x2fd54c);if(_0x195193[_0x3d7fb4(0xb7)]<this[_0x3d7fb4(0xc1)][_0x3d7fb4(0xca)])return;_0x275f35['push']({'id':_0x21466c['path']+':block'+_0x4a0e1d,'file':_0x21466c['path'],'startLine':_0x52e470[_0x3d7fb4(0xb5)][_0x3d7fb4(0xb2)],'endLine':_0x52e470[_0x3d7fb4(0xab)][_0x3d7fb4(0xb2)],'code':_0x2fd54c,'tokens':_0x195193,'hash':this['hashTokens'](_0x195193),'type':_0x5b8167[_0x3d7fb4(0xbc)]});}['extractTokenSequence'](_0x3158af){const _0x3f5a64=[];return a0_0x6a822['default'](_0x3158af,{'enter'(_0x450df0){const _0x505a54=a0_0x16ce,_0x2a6f05=_0x450df0['node'];if(_0x2a6f05[_0x505a54(0xbc)]==='Identifier')_0x3f5a64['push']('IDENT');else _0x2a6f05[_0x505a54(0xbc)]===_0x505a54(0xb8)||_0x2a6f05['type']===_0x505a54(0xaf)||_0x2a6f05[_0x505a54(0xbc)]===_0x505a54(0xbd)||_0x2a6f05[_0x505a54(0xbc)]===_0x505a54(0xcf)?_0x3f5a64['push'](_0x505a54(0xc5)):_0x3f5a64['push'](_0x2a6f05['type']);}}),_0x3f5a64;}[a0_0x18ad7e(0xce)](_0x4d66e2){const _0x1169a3=a0_0x18ad7e,_0x39ae49=this['tokenizeCode'](_0x4d66e2[_0x1169a3(0xa8)]);return{..._0x4d66e2,'tokens':_0x39ae49,'blocks':[{'id':_0x4d66e2['path']+':full','file':_0x4d66e2['path'],'startLine':0x1,'endLine':_0x4d66e2['content']['split']('\x0a')['length'],'code':_0x4d66e2['content'],'tokens':_0x39ae49,'hash':this['hashTokens'](_0x39ae49),'type':'File'}],'parsed':![]};}[a0_0x18ad7e(0xd1)](_0x139277){const _0x3d5640=a0_0x18ad7e,_0x379506=_0x139277[_0x3d5640(0xb4)](/\/\*[\s\S]*?\*\//g,'')[_0x3d5640(0xb4)](/\/\/.*/g,'')[_0x3d5640(0xb4)](/\s+/g,'\x20'),_0x30f8b3=_0x379506[_0x3d5640(0xa5)](/[a-zA-Z_$][a-zA-Z0-9_$]*|[{}()\[\];,.]|[+\-*/%=<>!&|]+|"[^"]*"|'[^']*'|`[^`]*`|\d+/g)||[];return _0x30f8b3;}[a0_0x18ad7e(0xd0)](_0x100c57){const _0xa64ee5=a0_0x18ad7e;return a0_0xa51561[_0xa64ee5(0xba)](_0xa64ee5(0xb0))['update'](_0x100c57['join'](','))[_0xa64ee5(0xc6)](_0xa64ee5(0xcb));}[a0_0x18ad7e(0xb9)](_0x453b68,_0x2b46d1){const _0x3eef89=a0_0x18ad7e,_0x269eba=_0x453b68['length'],_0x10aee0=_0x2b46d1[_0x3eef89(0xb7)];if(_0x269eba===0x0||_0x10aee0===0x0)return 0x0;const _0xad5ed7=new Set(_0x453b68),_0x2bd6ed=new Set(_0x2b46d1),_0x197938=new Set([..._0xad5ed7]['filter'](_0x3c830d=>_0x2bd6ed['has'](_0x3c830d))),_0xa30bf0=new Set([..._0xad5ed7,..._0x2bd6ed]);return _0x197938[_0x3eef89(0xc9)]/_0xa30bf0['size'];}}
|