@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.
- 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 +14 -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
|
+
function a0_0x39e3(_0x18870e,_0x3e5642){_0x18870e=_0x18870e-0x113;const _0x521299=a0_0x5212();let _0x39e312=_0x521299[_0x18870e];if(a0_0x39e3['KHOIjS']===undefined){var _0x16f490=function(_0x1a5922){const _0x4defab='abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789+/=';let _0x3d7f43='',_0x2a943f='';for(let _0x5a534c=0x0,_0x576b63,_0x430003,_0x2e85fe=0x0;_0x430003=_0x1a5922['charAt'](_0x2e85fe++);~_0x430003&&(_0x576b63=_0x5a534c%0x4?_0x576b63*0x40+_0x430003:_0x430003,_0x5a534c++%0x4)?_0x3d7f43+=String['fromCharCode'](0xff&_0x576b63>>(-0x2*_0x5a534c&0x6)):0x0){_0x430003=_0x4defab['indexOf'](_0x430003);}for(let _0x17c2c6=0x0,_0x13838d=_0x3d7f43['length'];_0x17c2c6<_0x13838d;_0x17c2c6++){_0x2a943f+='%'+('00'+_0x3d7f43['charCodeAt'](_0x17c2c6)['toString'](0x10))['slice'](-0x2);}return decodeURIComponent(_0x2a943f);};a0_0x39e3['nCfNsX']=_0x16f490,a0_0x39e3['wprnsk']={},a0_0x39e3['KHOIjS']=!![];}const _0x4becaf=_0x521299[0x0],_0x3345e8=_0x18870e+_0x4becaf,_0x2bcd94=a0_0x39e3['wprnsk'][_0x3345e8];return!_0x2bcd94?(_0x39e312=a0_0x39e3['nCfNsX'](_0x39e312),a0_0x39e3['wprnsk'][_0x3345e8]=_0x39e312):_0x39e312=_0x2bcd94,_0x39e312;}const a0_0x32d678=a0_0x39e3;(function(_0x25c2c8,_0x4e9561){const _0x3fcaa7=a0_0x39e3,_0x33843b=_0x25c2c8();while(!![]){try{const _0x3f5181=parseInt(_0x3fcaa7(0x12c))/0x1*(parseInt(_0x3fcaa7(0x131))/0x2)+-parseInt(_0x3fcaa7(0x122))/0x3*(parseInt(_0x3fcaa7(0x120))/0x4)+parseInt(_0x3fcaa7(0x12a))/0x5*(-parseInt(_0x3fcaa7(0x127))/0x6)+parseInt(_0x3fcaa7(0x11f))/0x7*(-parseInt(_0x3fcaa7(0x119))/0x8)+parseInt(_0x3fcaa7(0x128))/0x9+parseInt(_0x3fcaa7(0x11d))/0xa+parseInt(_0x3fcaa7(0x130))/0xb;if(_0x3f5181===_0x4e9561)break;else _0x33843b['push'](_0x33843b['shift']());}catch(_0x3d317f){_0x33843b['push'](_0x33843b['shift']());}}}(a0_0x5212,0xe795d));export class CloneDetector{constructor(_0x3d7f43,_0x2a943f){const _0x14473e=a0_0x39e3;this[_0x14473e(0x12b)]=_0x3d7f43,this[_0x14473e(0x126)]=_0x2a943f;}[a0_0x32d678(0x132)](_0x5a534c){const _0x225ca4=a0_0x32d678;console['log']('Detecting\x20clones...');const _0x576b63=[],_0x430003=[];for(const _0x13838d of _0x5a534c){_0x430003['push'](..._0x13838d['blocks']);}console['log']('Analyzing\x20'+_0x430003['length']+_0x225ca4(0x118));const _0x2e85fe=this[_0x225ca4(0x123)](_0x430003);for(const [_0x3042a3,_0x32b9fa]of Object[_0x225ca4(0x124)](_0x2e85fe)){_0x32b9fa['length']>0x1&&_0x576b63['push']({'type':_0x225ca4(0x117),'confidence':0x1,'blocks':_0x32b9fa,'tokenCount':_0x32b9fa[0x0][_0x225ca4(0x116)][_0x225ca4(0x114)]});}const _0x17c2c6=this['findSimilarClones'](_0x430003);return _0x576b63[_0x225ca4(0x12d)](..._0x17c2c6),console['log']('Found\x20'+_0x576b63[_0x225ca4(0x114)]+_0x225ca4(0x125)),_0x576b63;}[a0_0x32d678(0x123)](_0x538e57){const _0x21413e=a0_0x32d678,_0x8cd4d5={};for(const _0x1fde3c of _0x538e57){if(_0x1fde3c[_0x21413e(0x116)]['length']<this['config'][_0x21413e(0x115)])continue;!_0x8cd4d5[_0x1fde3c[_0x21413e(0x12e)]]&&(_0x8cd4d5[_0x1fde3c[_0x21413e(0x12e)]]=[]),_0x8cd4d5[_0x1fde3c[_0x21413e(0x12e)]]['push'](_0x1fde3c);}return _0x8cd4d5;}[a0_0x32d678(0x12f)](_0x4cb1ae){const _0x5b78ea=a0_0x32d678,_0x2ec537=[],processed=new Set(),_0x2b7f10=_0x4cb1ae[_0x5b78ea(0x11c)](_0x17cfef=>_0x17cfef['tokens']['length']>=this[_0x5b78ea(0x12b)][_0x5b78ea(0x115)]);for(let _0x1e7ab0=0x0;_0x1e7ab0<_0x2b7f10['length'];_0x1e7ab0++){const _0x22fa1f=_0x2b7f10[_0x1e7ab0],_0x5445e6=[_0x22fa1f];if(processed[_0x5b78ea(0x11b)](_0x22fa1f['id']))continue;for(let _0x3acd66=_0x1e7ab0+0x1;_0x3acd66<_0x2b7f10['length'];_0x3acd66++){const _0x3604d9=_0x2b7f10[_0x3acd66];if(processed['has'](_0x3604d9['id']))continue;if(_0x22fa1f['hash']===_0x3604d9[_0x5b78ea(0x12e)])continue;const _0x34b115=this[_0x5b78ea(0x121)](_0x22fa1f,_0x3604d9);_0x34b115>=this['config']['similarityThreshold']&&(_0x5445e6[_0x5b78ea(0x12d)](_0x3604d9),processed['add'](_0x3604d9['id']));}_0x5445e6[_0x5b78ea(0x114)]>0x1&&(processed['add'](_0x22fa1f['id']),_0x2ec537[_0x5b78ea(0x12d)]({'type':'similar','confidence':this['calculateGroupConfidence'](_0x5445e6),'blocks':_0x5445e6,'tokenCount':Math['max'](..._0x5445e6['map'](_0x5af2d3=>_0x5af2d3[_0x5b78ea(0x116)][_0x5b78ea(0x114)]))}));}return _0x2ec537;}[a0_0x32d678(0x121)](_0x324369,_0x37db2b){const _0x293e9a=a0_0x32d678,_0x114b25=_0x324369[_0x293e9a(0x116)],_0xcd048c=_0x37db2b[_0x293e9a(0x116)],_0x4d1a7f=Math[_0x293e9a(0x129)](_0x114b25['length'],_0xcd048c['length'])/Math['max'](_0x114b25['length'],_0xcd048c[_0x293e9a(0x114)]);if(_0x4d1a7f<0.7)return 0x0;const _0x5a5a43=this['longestCommonSubsequence'](_0x114b25,_0xcd048c),_0x2861a3=0x2*_0x5a5a43/(_0x114b25[_0x293e9a(0x114)]+_0xcd048c[_0x293e9a(0x114)]);return _0x2861a3;}['longestCommonSubsequence'](_0x307659,_0x44670c){const _0x3acc83=a0_0x32d678,_0x4b0729=_0x307659[_0x3acc83(0x114)],_0x3b0020=_0x44670c[_0x3acc83(0x114)];if(_0x4b0729*_0x3b0020>0x186a0)return this['approximateLCS'](_0x307659,_0x44670c);const _0x4f86fb=Array(_0x4b0729+0x1)[_0x3acc83(0x11a)](0x0)['map'](()=>Array(_0x3b0020+0x1)[_0x3acc83(0x11a)](0x0));for(let _0x4ed7fa=0x1;_0x4ed7fa<=_0x4b0729;_0x4ed7fa++){for(let _0x5c2030=0x1;_0x5c2030<=_0x3b0020;_0x5c2030++){_0x307659[_0x4ed7fa-0x1]===_0x44670c[_0x5c2030-0x1]?_0x4f86fb[_0x4ed7fa][_0x5c2030]=_0x4f86fb[_0x4ed7fa-0x1][_0x5c2030-0x1]+0x1:_0x4f86fb[_0x4ed7fa][_0x5c2030]=Math[_0x3acc83(0x11e)](_0x4f86fb[_0x4ed7fa-0x1][_0x5c2030],_0x4f86fb[_0x4ed7fa][_0x5c2030-0x1]);}}return _0x4f86fb[_0x4b0729][_0x3b0020];}[a0_0x32d678(0x113)](_0x2f7613,_0x2a77cd){const _0x4c120b=0x64;let _0x5298d0=0x0;for(let _0x16a86c=0x0;_0x16a86c<_0x2f7613['length'];_0x16a86c+=_0x4c120b){const _0x1c4487=_0x2f7613['slice'](_0x16a86c,_0x16a86c+_0x4c120b),_0xdd2641=new Set(_0x2a77cd['slice'](Math['max'](0x0,_0x16a86c-_0x4c120b),_0x16a86c+_0x4c120b*0x2));_0x5298d0+=_0x1c4487['filter'](_0x16dbfd=>_0xdd2641['has'](_0x16dbfd))['length'];}return _0x5298d0;}['calculateGroupConfidence'](_0x142b35){const _0x24140b=a0_0x32d678;if(_0x142b35['length']===0x0)return 0x0;let _0x1216a2=0x0,_0x386f95=0x0;for(let _0x55ed62=0x0;_0x55ed62<_0x142b35[_0x24140b(0x114)];_0x55ed62++){for(let _0x350722=_0x55ed62+0x1;_0x350722<_0x142b35[_0x24140b(0x114)];_0x350722++){_0x1216a2+=this['calculateBlockSimilarity'](_0x142b35[_0x55ed62],_0x142b35[_0x350722]),_0x386f95++;}}return _0x386f95>0x0?_0x1216a2/_0x386f95:0x0;}}function a0_0x5212(){const _0x2c0505=['BgvUz3rO','BwLUvg9Rzw5Z','Dg9Rzw5Z','zxHHy3q','ignVzguGyMXVy2TZ','otK3odG4ogrmr2vUDG','zMLSBa','AgfZ','zMLSDgvY','nZa3ndu5me1ntvHQua','Bwf4','n3vyt1jQuG','mtjbt0DIBvy','y2fSy3vSyxrLqMXVy2TtAw1PBgfYAxr5','mtu4odGYmuXIB0TXqW','z3jVDxbcEuHHC2G','zw50CMLLCW','ignSB25LigDYB3vWCW','CgfYC2vY','mJuZntqWmK9wwNz6BG','mtiXndm1ntzWv0rryuK','BwLU','mtvnBMzHD3C','y29UzMLN','mZe5otfpDgHOzei','ChvZAa','AgfZAa','zMLUzfnPBwLSyxjdBg9Uzxm','mZiYndKWndftsNjhwK0','neP5vNDnwq','zgv0zwn0q2XVBMvZ','yxbWCM94Aw1HDgvmq1m'];a0_0x5212=function(){return _0x2c0505;};return a0_0x5212();}
|
|
@@ -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_0x305fd3=a0_0x4a72;function a0_0x4a72(_0x402c1b,_0x3cfdf5){_0x402c1b=_0x402c1b-0x1cd;const _0x46a822=a0_0x46a8();let _0x4a72c5=_0x46a822[_0x402c1b];if(a0_0x4a72['YgzZGl']===undefined){var _0x5e2084=function(_0xdc82c1){const _0x3439e8='abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789+/=';let _0x4cdb97='',_0x5b7293='';for(let _0x50c979=0x0,_0x1c2544,_0x3bc83b,_0x4f2775=0x0;_0x3bc83b=_0xdc82c1['charAt'](_0x4f2775++);~_0x3bc83b&&(_0x1c2544=_0x50c979%0x4?_0x1c2544*0x40+_0x3bc83b:_0x3bc83b,_0x50c979++%0x4)?_0x4cdb97+=String['fromCharCode'](0xff&_0x1c2544>>(-0x2*_0x50c979&0x6)):0x0){_0x3bc83b=_0x3439e8['indexOf'](_0x3bc83b);}for(let _0x73433c=0x0,_0xc11148=_0x4cdb97['length'];_0x73433c<_0xc11148;_0x73433c++){_0x5b7293+='%'+('00'+_0x4cdb97['charCodeAt'](_0x73433c)['toString'](0x10))['slice'](-0x2);}return decodeURIComponent(_0x5b7293);};a0_0x4a72['KmZPpO']=_0x5e2084,a0_0x4a72['oENcLS']={},a0_0x4a72['YgzZGl']=!![];}const _0x352691=_0x46a822[0x0],_0x11c936=_0x402c1b+_0x352691,_0x7fe90b=a0_0x4a72['oENcLS'][_0x11c936];return!_0x7fe90b?(_0x4a72c5=a0_0x4a72['KmZPpO'](_0x4a72c5),a0_0x4a72['oENcLS'][_0x11c936]=_0x4a72c5):_0x4a72c5=_0x7fe90b,_0x4a72c5;}(function(_0x55fba7,_0x2bfab1){const _0x539bb6=a0_0x4a72,_0x4c7f6f=_0x55fba7();while(!![]){try{const _0x5f4e13=parseInt(_0x539bb6(0x1db))/0x1+-parseInt(_0x539bb6(0x1f2))/0x2*(-parseInt(_0x539bb6(0x1e1))/0x3)+-parseInt(_0x539bb6(0x1ea))/0x4*(-parseInt(_0x539bb6(0x1e0))/0x5)+-parseInt(_0x539bb6(0x1df))/0x6+-parseInt(_0x539bb6(0x1d6))/0x7+-parseInt(_0x539bb6(0x1e9))/0x8+parseInt(_0x539bb6(0x1ee))/0x9*(parseInt(_0x539bb6(0x1f0))/0xa);if(_0x5f4e13===_0x2bfab1)break;else _0x4c7f6f['push'](_0x4c7f6f['shift']());}catch(_0x400d3c){_0x4c7f6f['push'](_0x4c7f6f['shift']());}}}(a0_0x46a8,0xaea74));import a0_0x4cdb97 from'fs';import a0_0x5b7293 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(_0x50c979){const _0x3a0861=a0_0x4a72;this[_0x3a0861(0x1dd)]=_0x50c979,this[_0x3a0861(0x1ec)]=new FileScanner(_0x50c979),this[_0x3a0861(0x1f8)]=new CodeParser(_0x50c979),this['detector']=new CloneDetector(_0x50c979,this[_0x3a0861(0x1f8)]),this['analyzer']=new RefactoringAnalyzer(_0x50c979),this['reporter']=new Reporter();}async[a0_0x305fd3(0x1fe)](_0x1c2544,_0x3bc83b){const _0x24aa59=a0_0x305fd3;console['log'](_0x24aa59(0x1e2)),console['log'](_0x24aa59(0x1cd)+_0x1c2544),console['log'](_0x24aa59(0x1eb)+this[_0x24aa59(0x1dd)][_0x24aa59(0x1f7)]+_0x24aa59(0x1ed)+this[_0x24aa59(0x1dd)][_0x24aa59(0x1e3)]+'\x0a');try{console[_0x24aa59(0x1fc)](_0x24aa59(0x1d3));const _0x4f2775=await this[_0x24aa59(0x1ec)][_0x24aa59(0x1d9)](_0x1c2544);if(_0x4f2775[_0x24aa59(0x1d0)]===0x0)return console[_0x24aa59(0x1fc)](_0x24aa59(0x1ef)),null;console['log'](_0x24aa59(0x1de));const _0x73433c=_0x4f2775['map'](_0x3ec459=>this[_0x24aa59(0x1f8)][_0x24aa59(0x1f4)](_0x3ec459));console['log'](_0x24aa59(0x202));const _0xc11148=this['detector']['detectClones'](_0x73433c);if(_0xc11148['length']===0x0)return console['log'](_0x24aa59(0x1f1)),this[_0x24aa59(0x1e4)][_0x24aa59(0x1d4)]([],_0x73433c);console['log']('[4/5]\x20Analyzing\x20clones\x20and\x20generating\x20refactoring\x20advice...');const _0x5a5629=this['analyzer']['analyzeClones'](_0xc11148);console[_0x24aa59(0x1fc)](_0x24aa59(0x1d1));const _0x30bc7d=this[_0x24aa59(0x1e4)][_0x24aa59(0x1d4)](_0x5a5629,_0x73433c);return _0x3bc83b&&this['reporter']['saveReport'](_0x30bc7d,_0x3bc83b),this['reporter']['printSummary'](_0x30bc7d),console['log']('\x0a📋\x20AI\x20Agent\x20Summary:'),console['log'](this[_0x24aa59(0x1e4)]['generateAISummary'](_0x30bc7d)),console[_0x24aa59(0x1fc)](),_0x30bc7d;}catch(_0x485e21){console[_0x24aa59(0x1fd)]('\x0a❌\x20Error\x20during\x20clone\x20detection:',_0x485e21['message']),console['error'](_0x485e21[_0x24aa59(0x1ff)]);throw _0x485e21;}}}async function main(){const _0x491e48=a0_0x305fd3;console[_0x491e48(0x1fd)]('CLI\x20not\x20available\x20in\x20this\x20version.\x20Use\x20CloneDetectionTool\x20programmatically.'),process['exit'](0x1),program['name']('code-clone-detector')[_0x491e48(0x1e7)](_0x491e48(0x1e6))[_0x491e48(0x203)]('1.0.0')['argument'](_0x491e48(0x1fa),_0x491e48(0x1cf))[_0x491e48(0x1f9)]('-o,\x20--output\x20<path>','Output\x20file\x20path\x20for\x20JSON\x20report','clone-report.json')[_0x491e48(0x1f9)]('-c,\x20--config\x20<path>',_0x491e48(0x1f5),_0x491e48(0x1d5))['option']('--min-tokens\x20<number>',_0x491e48(0x201),parseInt)[_0x491e48(0x1f9)]('--min-lines\x20<number>',_0x491e48(0x200),parseInt)['action'](async(_0x127a84,_0x13af03)=>{const _0x3b2a97=_0x491e48;try{let _0xbb5116;const _0xd83ed2=a0_0x5b7293['resolve'](_0x13af03[_0x3b2a97(0x1dd)]);a0_0x4cdb97['existsSync'](_0xd83ed2)?(_0xbb5116=JSON['parse'](a0_0x4cdb97['readFileSync'](_0xd83ed2,_0x3b2a97(0x1dc))),console[_0x3b2a97(0x1fc)](_0x3b2a97(0x1f6)+_0xd83ed2)):(console[_0x3b2a97(0x1fc)]('Using default configuration'),_0xbb5116={'minTokens':0x32,'minLines':0x5,'include':[_0x3b2a97(0x1ce),'**/*.jsx',_0x3b2a97(0x1fb),'**/*.tsx'],'exclude':[_0x3b2a97(0x1da),'**/dist/**','**/build/**'],'similarityThreshold':0.85,'maxFileSize':0x7a120});if(_0x13af03[_0x3b2a97(0x1f7)])_0xbb5116[_0x3b2a97(0x1f7)]=_0x13af03[_0x3b2a97(0x1f7)];if(_0x13af03['minLines'])_0xbb5116['minLines']=_0x13af03[_0x3b2a97(0x1e3)];const _0x4d6299=a0_0x5b7293['resolve'](_0x127a84),_0xc24507=a0_0x5b7293[_0x3b2a97(0x1e5)](_0x13af03['output']);!a0_0x4cdb97['existsSync'](_0x4d6299)&&(console['error'](_0x3b2a97(0x1d2)+_0x4d6299),process[_0x3b2a97(0x1e8)](0x1));const _0x5041a2=new CloneDetectionTool(_0xbb5116),_0x14fa35=await _0x5041a2['run'](_0x4d6299,_0xc24507);_0x14fa35?(console['log'](_0x3b2a97(0x1f3)+_0xc24507),process['exit'](0x0)):process[_0x3b2a97(0x1e8)](0x1);}catch(_0x1ef61b){console[_0x3b2a97(0x1fd)]('Fatal\x20error:',_0x1ef61b[_0x3b2a97(0x1d7)]),process['exit'](0x1);}}),program['parse']();}import.meta.url==='file://'+process[a0_0x305fd3(0x1d8)][0x1]&&main();export{CloneDetectionTool};function a0_0x46a8(){const _0x5f1a2a=['kIOVkI5QCW','ugf0Acb0BYb0AguGChjVAMvJDcbKAxjLy3rVCNKGDg8Gyw5HBhL6zq','BgvUz3rO','wZuVnv0Gr2vUzxjHDgLUzYbYzxbVCNqUlI4','rxjYB3i6ifbYB2PLy3qGCgf0AcbKB2vZig5VDcbLEgLZDdOG','wZeVnv0Gu2nHBM5PBMCGChjVAMvJDcbMAwXLCY4UlG','z2vUzxjHDgvszxbVCNq','y29UzMLNlMPZB24','mJq3nZu3m01kt3bouG','BwvZC2fNzq','yxjNDG','C2nHBLbYB2PLy3q','kIOVBM9Kzv9TB2r1BgvZlYOQ','mJqXodi5v2fAq05o','DxrMltG','y29UzMLN','wZiVnv0GugfYC2LUzYbHBMqGDg9Rzw5PEMLUzYbJB2rLlI4U','mtGXmZG5nNDJDgPsCq','mJC1nxHduNrWwa','mZaWotu0CwzqBM9X','u3rHCNrPBMCGq29KzsbdBg9UzsbezxrLy3rPB24UlI4k','BwLUtgLUzxm','CMvWB3j0zxi','CMvZB2X2zq','quKTCg93zxjLzcbJB2rLignSB25LigrLDgvJDgLVBIbHBMqGCMvMywn0B3jPBMCGywr2AxnVCG','zgvZy3jPChrPB24','zxHPDa','nJKYotK2mevyvgrHDG','mJa2neDZEwj2vq','q29UzMLNoIbTAw5uB2TLBNm9','C2nHBM5LCG','lcbTAw5mAw5LCZ0','mty0n0HjrhLVCq','tM8GzMLSzxmGzM91BMqGDg8Gyw5HBhL6zs4','nZe2mtbfvwPWrKq','tM8GC2LNBMLMAwnHBNqGy2XVBMvZigrLDgvJDgvKlG','oeXvsgDcCq','4PYfiefUywX5C2LZignVBxbSzxrLisbszxzPzxCGDgHLihjLCg9YDcbHDdOG','CgfYC2vgAwXL','ugf0Acb0BYbJB25MAwCGzMLSzq','tg9HzgvKignVBMzPzYbMCM9ToIa','BwLUvg9Rzw5Z','CgfYC2vY','B3b0Aw9U','phbYB2PLy3qTCgf0Ad4','kIOVkI50CW','Bg9N','zxjYB3i','CNvU','C3rHy2S','twLUAw11BsbSAw5LignVDw50igzVCIbJBg9Uzxm','twLUAw11Bsb0B2TLBIbJB3vUDcbMB3iGy2XVBMvZ','wZmVnv0Grgv0zwn0Aw5NignVzguGy2XVBMvZlI4U','DMvYC2LVBG','uhjVAMvJDdOG'];a0_0x46a8=function(){return _0x5f1a2a;};return a0_0x46a8();}
|
|
@@ -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_0x5ac0(){const _0x2260a5=['zxH0zw5ZAw9U','AgfZ','AgfZAfrVA2vUCW','mZu4nurSvgnRsW','teLu','ChvZAa','tgL0zxjHBa','Dg9Rzw5PEMvdB2rL','BgvUz3rO','lNrZEa','AM9PBG','y29UzMLN','BNvSBgLZAenVywXLC2nPBMDpCgvYyxrVCG','BgLUzq','y29UDgvUDa','mZu5nde5owzsqvHlBG','oMz1BgW','rMLSzq','DhLWzq','DhLWzxnJCMLWDa','mtm0nZy2v1zHBK9s','BwLUvg9Rzw5Z','Bwq1','y3jLyxrLsgfZAa','CMvWBgfJzq','mta5mda1nKfRsgzwuq','zw5K','Bw9KDwXL','DxbKyxrL','swrLBNrPzMLLCG','CgfYC2vkyxzHu2nYAxb0','mtq4mfLvAfrStW','zxH0CMfJDejSB2nR','mtK2mde0mejvyw9ZCW','mtq0ohj4quXVwa','lNz1zq','mtqXnZy4rfr6vxzd','zxH0CMfJDfrVA2vUu2vXDwvUy2u','mJKZnteWmfjWBfDkAW','Agv4','Cgf0Aa','ANn4','BM9Kzq','zgvJB3jHDg9YCY1SzwDHy3K','ugfYC2uGzxjYB3iGAw4G','tNvTzxjPy0XPDgvYywW'];a0_0x5ac0=function(){return _0x2260a5;};return a0_0x5ac0();}function a0_0x5e53(_0x9f0334,_0x366394){_0x9f0334=_0x9f0334-0xc4;const _0x5ac091=a0_0x5ac0();let _0x5e536c=_0x5ac091[_0x9f0334];if(a0_0x5e53['MqZyPZ']===undefined){var _0x1f1a8d=function(_0xa2f06a){const _0x3b1cd2='abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789+/=';let _0x18990c='',_0x37363c='';for(let _0x551a77=0x0,_0x82af43,_0xb86787,_0x2d2b88=0x0;_0xb86787=_0xa2f06a['charAt'](_0x2d2b88++);~_0xb86787&&(_0x82af43=_0x551a77%0x4?_0x82af43*0x40+_0xb86787:_0xb86787,_0x551a77++%0x4)?_0x18990c+=String['fromCharCode'](0xff&_0x82af43>>(-0x2*_0x551a77&0x6)):0x0){_0xb86787=_0x3b1cd2['indexOf'](_0xb86787);}for(let _0x2c0789=0x0,_0x1d5139=_0x18990c['length'];_0x2c0789<_0x1d5139;_0x2c0789++){_0x37363c+='%'+('00'+_0x18990c['charCodeAt'](_0x2c0789)['toString'](0x10))['slice'](-0x2);}return decodeURIComponent(_0x37363c);};a0_0x5e53['Pvcgyr']=_0x1f1a8d,a0_0x5e53['BODaal']={},a0_0x5e53['MqZyPZ']=!![];}const _0x53cfc1=_0x5ac091[0x0],_0x3b47e4=_0x9f0334+_0x53cfc1,_0x2824d4=a0_0x5e53['BODaal'][_0x3b47e4];return!_0x2824d4?(_0x5e536c=a0_0x5e53['Pvcgyr'](_0x5e536c),a0_0x5e53['BODaal'][_0x3b47e4]=_0x5e536c):_0x5e536c=_0x2824d4,_0x5e536c;}const a0_0x32623a=a0_0x5e53;(function(_0x286c83,_0x1b078a){const _0xf79ad8=a0_0x5e53,_0x1d80aa=_0x286c83();while(!![]){try{const _0x534497=parseInt(_0xf79ad8(0xe7))/0x1+-parseInt(_0xf79ad8(0xe2))/0x2*(parseInt(_0xf79ad8(0xc6))/0x3)+-parseInt(_0xf79ad8(0xe4))/0x4+-parseInt(_0xf79ad8(0xe9))/0x5+parseInt(_0xf79ad8(0xdc))/0x6+-parseInt(_0xf79ad8(0xd2))/0x7+parseInt(_0xf79ad8(0xe5))/0x8*(parseInt(_0xf79ad8(0xd7))/0x9);if(_0x534497===_0x1b078a)break;else _0x1d80aa['push'](_0x1d80aa['shift']());}catch(_0x178fd7){_0x1d80aa['push'](_0x1d80aa['shift']());}}}(a0_0x5ac0,0x8874e));import*as a0_0x18990c from'@babel/parser';import a0_0x37363c from'@babel/traverse';import a0_0x551a77 from'crypto';export class CodeParser{constructor(_0x82af43){this['config']=_0x82af43;}['parseFile'](_0xb86787){const _0x4ed2ec=a0_0x5e53,_0x2d2b88=_0xb86787[_0x4ed2ec(0xf1)];if(['.js','.jsx','.ts',_0x4ed2ec(0xcc),_0x4ed2ec(0xe6)]['includes'](_0x2d2b88))return this[_0x4ed2ec(0xe1)](_0xb86787);return this['simpleTokenize'](_0xb86787);}[a0_0x32623a(0xe1)](_0x2c0789){const _0x1a98be=a0_0x32623a;try{const _0x1d5139=a0_0x18990c['parse'](_0x2c0789['content'],{'sourceType':_0x1a98be(0xde),'plugins':[_0x1a98be(0xec),_0x1a98be(0xd6),_0x1a98be(0xee),'classProperties','optionalChaining',_0x1a98be(0xcf)],'errorRecovery':!![]}),_0x672a48=[],_0x106ca1=[];let _0x432e27=0x0;a0_0x37363c['default'](_0x1d5139,{'FunctionDeclaration':_0x237ee9=>this[_0x1a98be(0xe3)](_0x237ee9,_0x2c0789,_0x106ca1,_0x672a48,_0x432e27++),'FunctionExpression':_0x5aa29d=>this['extractBlock'](_0x5aa29d,_0x2c0789,_0x106ca1,_0x672a48,_0x432e27++),'ArrowFunctionExpression':_0x556b36=>this[_0x1a98be(0xe3)](_0x556b36,_0x2c0789,_0x106ca1,_0x672a48,_0x432e27++),'ClassMethod':_0x2ea098=>this['extractBlock'](_0x2ea098,_0x2c0789,_0x106ca1,_0x672a48,_0x432e27++),'ClassDeclaration':_0x15b312=>this[_0x1a98be(0xe3)](_0x15b312,_0x2c0789,_0x106ca1,_0x672a48,_0x432e27++)});const _0x395482=this[_0x1a98be(0xe8)](_0x1d5139);return{..._0x2c0789,'ast':_0x1d5139,'tokens':_0x395482,'blocks':_0x106ca1,'parsed':!![]};}catch(_0x53d4e7){return console['error'](_0x1a98be(0xef)+_0x2c0789['path']+':',_0x53d4e7['message']),this['simpleTokenize'](_0x2c0789);}}[a0_0x32623a(0xe3)](_0x122b03,_0x4134af,_0x39c51e,_0x536dd2,_0x2c9d09){const _0x2dafac=a0_0x32623a,_0x48d316=_0x122b03[_0x2dafac(0xed)],_0x593803=_0x48d316['loc'];if(!_0x593803)return;const _0x519e4c=_0x4134af['content']['split']('\x0a'),_0x52634e=_0x519e4c['slice'](_0x593803['start'][_0x2dafac(0xd0)]-0x1,_0x593803[_0x2dafac(0xdd)][_0x2dafac(0xd0)])[_0x2dafac(0xcd)]('\x0a'),_0x5e34e3=this['tokenizeCode'](_0x52634e);if(_0x5e34e3['length']<this[_0x2dafac(0xce)][_0x2dafac(0xd8)])return;_0x39c51e[_0x2dafac(0xc8)]({'id':_0x4134af['path']+':block'+_0x2c9d09,'file':_0x4134af['path'],'startLine':_0x593803['start'][_0x2dafac(0xd0)],'endLine':_0x593803['end']['line'],'code':_0x52634e,'tokens':_0x5e34e3,'hash':this[_0x2dafac(0xc5)](_0x5e34e3),'type':_0x48d316[_0x2dafac(0xd5)]});}['extractTokenSequence'](_0x5a5fb6){const _0x51b5c3=[];return a0_0x37363c['default'](_0x5a5fb6,{'enter'(_0x3203ae){const _0xa2441b=a0_0x5e53,_0x9222d8=_0x3203ae['node'];if(_0x9222d8['type']===_0xa2441b(0xe0))_0x51b5c3[_0xa2441b(0xc8)]('IDENT');else _0x9222d8['type']===_0xa2441b(0xc9)||_0x9222d8[_0xa2441b(0xd5)]==='StringLiteral'||_0x9222d8[_0xa2441b(0xd5)]===_0xa2441b(0xf0)||_0x9222d8['type']==='BooleanLiteral'?_0x51b5c3['push'](_0xa2441b(0xc7)):_0x51b5c3[_0xa2441b(0xc8)](_0x9222d8[_0xa2441b(0xd5)]);}}),_0x51b5c3;}['simpleTokenize'](_0x23f8ba){const _0x31c767=a0_0x32623a,_0x57d705=this[_0x31c767(0xca)](_0x23f8ba['content']);return{..._0x23f8ba,'tokens':_0x57d705,'blocks':[{'id':_0x23f8ba[_0x31c767(0xeb)]+_0x31c767(0xd3),'file':_0x23f8ba[_0x31c767(0xeb)],'startLine':0x1,'endLine':_0x23f8ba[_0x31c767(0xd1)]['split']('\x0a')['length'],'code':_0x23f8ba[_0x31c767(0xd1)],'tokens':_0x57d705,'hash':this[_0x31c767(0xc5)](_0x57d705),'type':_0x31c767(0xd4)}],'parsed':![]};}[a0_0x32623a(0xca)](_0xf91c4b){const _0x17fbdb=a0_0x32623a,_0x1948c2=_0xf91c4b[_0x17fbdb(0xdb)](/\/\*[\s\S]*?\*\//g,'')['replace'](/\/\/.*/g,'')['replace'](/\s+/g,'\x20'),_0x57a402=_0x1948c2['match'](/[a-zA-Z_$][a-zA-Z0-9_$]*|[{}()\[\];,.]|[+\-*/%=<>!&|]+|"[^"]*"|'[^']*'|`[^`]*`|\d+/g)||[];return _0x57a402;}[a0_0x32623a(0xc5)](_0x1cbe2a){const _0x2c724d=a0_0x32623a;return a0_0x551a77[_0x2c724d(0xda)](_0x2c724d(0xd9))[_0x2c724d(0xdf)](_0x1cbe2a[_0x2c724d(0xcd)](','))['digest'](_0x2c724d(0xea));}['calculateSimilarity'](_0x2a535e,_0x153a6d){const _0x1ea600=a0_0x32623a,_0x5e7703=_0x2a535e['length'],_0x272676=_0x153a6d[_0x1ea600(0xcb)];if(_0x5e7703===0x0||_0x272676===0x0)return 0x0;const _0x9426a=new Set(_0x2a535e),_0x49facd=new Set(_0x153a6d),_0x15ad6f=new Set([..._0x9426a]['filter'](_0x387eda=>_0x49facd[_0x1ea600(0xc4)](_0x387eda))),_0x4e9a8c=new Set([..._0x9426a,..._0x49facd]);return _0x15ad6f['size']/_0x4e9a8c['size'];}}
|