linguclaw 0.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (168) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +161 -0
  3. package/dist/agent-system.d.ts +196 -0
  4. package/dist/agent-system.d.ts.map +1 -0
  5. package/dist/agent-system.js +738 -0
  6. package/dist/agent-system.js.map +1 -0
  7. package/dist/alphabeta.d.ts +54 -0
  8. package/dist/alphabeta.d.ts.map +1 -0
  9. package/dist/alphabeta.js +193 -0
  10. package/dist/alphabeta.js.map +1 -0
  11. package/dist/browser.d.ts +62 -0
  12. package/dist/browser.d.ts.map +1 -0
  13. package/dist/browser.js +224 -0
  14. package/dist/browser.js.map +1 -0
  15. package/dist/cli.d.ts +7 -0
  16. package/dist/cli.d.ts.map +1 -0
  17. package/dist/cli.js +565 -0
  18. package/dist/cli.js.map +1 -0
  19. package/dist/code-parser.d.ts +39 -0
  20. package/dist/code-parser.d.ts.map +1 -0
  21. package/dist/code-parser.js +385 -0
  22. package/dist/code-parser.js.map +1 -0
  23. package/dist/config.d.ts +66 -0
  24. package/dist/config.d.ts.map +1 -0
  25. package/dist/config.js +232 -0
  26. package/dist/config.js.map +1 -0
  27. package/dist/core/engine.d.ts +359 -0
  28. package/dist/core/engine.d.ts.map +1 -0
  29. package/dist/core/engine.js +127 -0
  30. package/dist/core/engine.js.map +1 -0
  31. package/dist/daemon.d.ts +29 -0
  32. package/dist/daemon.d.ts.map +1 -0
  33. package/dist/daemon.js +212 -0
  34. package/dist/daemon.js.map +1 -0
  35. package/dist/email-receiver.d.ts +63 -0
  36. package/dist/email-receiver.d.ts.map +1 -0
  37. package/dist/email-receiver.js +553 -0
  38. package/dist/email-receiver.js.map +1 -0
  39. package/dist/git-integration.d.ts +180 -0
  40. package/dist/git-integration.d.ts.map +1 -0
  41. package/dist/git-integration.js +850 -0
  42. package/dist/git-integration.js.map +1 -0
  43. package/dist/inbox.d.ts +84 -0
  44. package/dist/inbox.d.ts.map +1 -0
  45. package/dist/inbox.js +198 -0
  46. package/dist/inbox.js.map +1 -0
  47. package/dist/index.d.ts +6 -0
  48. package/dist/index.d.ts.map +1 -0
  49. package/dist/index.js +41 -0
  50. package/dist/index.js.map +1 -0
  51. package/dist/languages/cpp.d.ts +51 -0
  52. package/dist/languages/cpp.d.ts.map +1 -0
  53. package/dist/languages/cpp.js +930 -0
  54. package/dist/languages/cpp.js.map +1 -0
  55. package/dist/languages/csharp.d.ts +79 -0
  56. package/dist/languages/csharp.d.ts.map +1 -0
  57. package/dist/languages/csharp.js +1776 -0
  58. package/dist/languages/csharp.js.map +1 -0
  59. package/dist/languages/go.d.ts +50 -0
  60. package/dist/languages/go.d.ts.map +1 -0
  61. package/dist/languages/go.js +882 -0
  62. package/dist/languages/go.js.map +1 -0
  63. package/dist/languages/java.d.ts +47 -0
  64. package/dist/languages/java.d.ts.map +1 -0
  65. package/dist/languages/java.js +649 -0
  66. package/dist/languages/java.js.map +1 -0
  67. package/dist/languages/python.d.ts +47 -0
  68. package/dist/languages/python.d.ts.map +1 -0
  69. package/dist/languages/python.js +655 -0
  70. package/dist/languages/python.js.map +1 -0
  71. package/dist/languages/rust.d.ts +61 -0
  72. package/dist/languages/rust.d.ts.map +1 -0
  73. package/dist/languages/rust.js +1064 -0
  74. package/dist/languages/rust.js.map +1 -0
  75. package/dist/logger.d.ts +20 -0
  76. package/dist/logger.d.ts.map +1 -0
  77. package/dist/logger.js +133 -0
  78. package/dist/logger.js.map +1 -0
  79. package/dist/longterm-memory.d.ts +47 -0
  80. package/dist/longterm-memory.d.ts.map +1 -0
  81. package/dist/longterm-memory.js +300 -0
  82. package/dist/longterm-memory.js.map +1 -0
  83. package/dist/memory.d.ts +42 -0
  84. package/dist/memory.d.ts.map +1 -0
  85. package/dist/memory.js +274 -0
  86. package/dist/memory.js.map +1 -0
  87. package/dist/messaging.d.ts +103 -0
  88. package/dist/messaging.d.ts.map +1 -0
  89. package/dist/messaging.js +645 -0
  90. package/dist/messaging.js.map +1 -0
  91. package/dist/multi-provider.d.ts +69 -0
  92. package/dist/multi-provider.d.ts.map +1 -0
  93. package/dist/multi-provider.js +484 -0
  94. package/dist/multi-provider.js.map +1 -0
  95. package/dist/orchestrator.d.ts +65 -0
  96. package/dist/orchestrator.d.ts.map +1 -0
  97. package/dist/orchestrator.js +441 -0
  98. package/dist/orchestrator.js.map +1 -0
  99. package/dist/plugins.d.ts +52 -0
  100. package/dist/plugins.d.ts.map +1 -0
  101. package/dist/plugins.js +215 -0
  102. package/dist/plugins.js.map +1 -0
  103. package/dist/prism-orchestrator.d.ts +26 -0
  104. package/dist/prism-orchestrator.d.ts.map +1 -0
  105. package/dist/prism-orchestrator.js +191 -0
  106. package/dist/prism-orchestrator.js.map +1 -0
  107. package/dist/prism.d.ts +46 -0
  108. package/dist/prism.d.ts.map +1 -0
  109. package/dist/prism.js +188 -0
  110. package/dist/prism.js.map +1 -0
  111. package/dist/privacy.d.ts +23 -0
  112. package/dist/privacy.d.ts.map +1 -0
  113. package/dist/privacy.js +220 -0
  114. package/dist/privacy.js.map +1 -0
  115. package/dist/proactive.d.ts +30 -0
  116. package/dist/proactive.d.ts.map +1 -0
  117. package/dist/proactive.js +260 -0
  118. package/dist/proactive.js.map +1 -0
  119. package/dist/refactoring-engine.d.ts +100 -0
  120. package/dist/refactoring-engine.d.ts.map +1 -0
  121. package/dist/refactoring-engine.js +717 -0
  122. package/dist/refactoring-engine.js.map +1 -0
  123. package/dist/resilience.d.ts +43 -0
  124. package/dist/resilience.d.ts.map +1 -0
  125. package/dist/resilience.js +200 -0
  126. package/dist/resilience.js.map +1 -0
  127. package/dist/safety.d.ts +40 -0
  128. package/dist/safety.d.ts.map +1 -0
  129. package/dist/safety.js +133 -0
  130. package/dist/safety.js.map +1 -0
  131. package/dist/sandbox.d.ts +33 -0
  132. package/dist/sandbox.d.ts.map +1 -0
  133. package/dist/sandbox.js +173 -0
  134. package/dist/sandbox.js.map +1 -0
  135. package/dist/scheduler.d.ts +72 -0
  136. package/dist/scheduler.d.ts.map +1 -0
  137. package/dist/scheduler.js +374 -0
  138. package/dist/scheduler.js.map +1 -0
  139. package/dist/semantic-memory.d.ts +70 -0
  140. package/dist/semantic-memory.d.ts.map +1 -0
  141. package/dist/semantic-memory.js +430 -0
  142. package/dist/semantic-memory.js.map +1 -0
  143. package/dist/skills.d.ts +97 -0
  144. package/dist/skills.d.ts.map +1 -0
  145. package/dist/skills.js +575 -0
  146. package/dist/skills.js.map +1 -0
  147. package/dist/static/dashboard.html +853 -0
  148. package/dist/static/hub.html +772 -0
  149. package/dist/static/index.html +818 -0
  150. package/dist/static/logo.svg +24 -0
  151. package/dist/static/workflow-editor.html +913 -0
  152. package/dist/tools.d.ts +67 -0
  153. package/dist/tools.d.ts.map +1 -0
  154. package/dist/tools.js +303 -0
  155. package/dist/tools.js.map +1 -0
  156. package/dist/types.d.ts +295 -0
  157. package/dist/types.d.ts.map +1 -0
  158. package/dist/types.js +90 -0
  159. package/dist/types.js.map +1 -0
  160. package/dist/web.d.ts +76 -0
  161. package/dist/web.d.ts.map +1 -0
  162. package/dist/web.js +2139 -0
  163. package/dist/web.js.map +1 -0
  164. package/dist/workflow-engine.d.ts +114 -0
  165. package/dist/workflow-engine.d.ts.map +1 -0
  166. package/dist/workflow-engine.js +855 -0
  167. package/dist/workflow-engine.js.map +1 -0
  168. package/package.json +77 -0
@@ -0,0 +1,655 @@
1
+ "use strict";
2
+ /**
3
+ * Python Language Support for LinguClaw
4
+ * Advanced Python parser using AST analysis
5
+ */
6
+ Object.defineProperty(exports, "__esModule", { value: true });
7
+ exports.PythonLanguageSupport = exports.PythonAnalyzer = exports.PythonParser = void 0;
8
+ class PythonParser {
9
+ source = '';
10
+ lines = [];
11
+ parse(source, filePath) {
12
+ this.source = source;
13
+ this.lines = source.split('\n');
14
+ try {
15
+ // Use Python's ast module via child process for accurate parsing
16
+ const ast = this.parseWithPythonAST(source);
17
+ return {
18
+ ast: this.convertToGenericAST(ast, filePath),
19
+ errors: [],
20
+ warnings: [],
21
+ tokens: [],
22
+ comments: this.extractComments(),
23
+ };
24
+ }
25
+ catch (error) {
26
+ // Fallback to regex-based parsing
27
+ return this.fallbackParse(filePath);
28
+ }
29
+ }
30
+ async *parseStream(source) {
31
+ const reader = source.getReader();
32
+ let buffer = '';
33
+ while (true) {
34
+ const { done, value } = await reader.read();
35
+ if (done)
36
+ break;
37
+ buffer += value;
38
+ // Try to parse complete statements
39
+ const chunks = this.splitIntoChunks(buffer);
40
+ for (const chunk of chunks.complete) {
41
+ yield this.parse(chunk, '<stream>');
42
+ }
43
+ buffer = chunks.remaining;
44
+ }
45
+ // Parse remaining
46
+ if (buffer.trim()) {
47
+ yield this.parse(buffer, '<stream>');
48
+ }
49
+ }
50
+ parseWithPythonAST(source) {
51
+ // In real implementation, this would spawn Python process
52
+ // python -c "import ast; print(ast.dump(ast.parse(source)))"
53
+ return this.createMockPythonAST(source);
54
+ }
55
+ createMockPythonAST(source) {
56
+ // Simplified mock AST for demonstration
57
+ return {
58
+ type: 'Module',
59
+ body: this.extractPythonStructure(source),
60
+ };
61
+ }
62
+ extractPythonStructure(source) {
63
+ const nodes = [];
64
+ const lines = source.split('\n');
65
+ let currentIndent = 0;
66
+ let inClass = false;
67
+ let inFunction = false;
68
+ let className = '';
69
+ let functionName = '';
70
+ for (let i = 0; i < lines.length; i++) {
71
+ const line = lines[i];
72
+ const stripped = line.trim();
73
+ const indent = line.search(/\S/);
74
+ if (stripped.startsWith('class ')) {
75
+ const match = stripped.match(/class\s+(\w+)/);
76
+ if (match) {
77
+ inClass = true;
78
+ className = match[1];
79
+ nodes.push({
80
+ type: 'ClassDef',
81
+ name: className,
82
+ lineno: i + 1,
83
+ col_offset: indent,
84
+ });
85
+ }
86
+ }
87
+ else if (stripped.startsWith('def ')) {
88
+ const match = stripped.match(/def\s+(\w+)/);
89
+ if (match) {
90
+ inFunction = true;
91
+ functionName = match[1];
92
+ nodes.push({
93
+ type: 'FunctionDef',
94
+ name: functionName,
95
+ lineno: i + 1,
96
+ col_offset: indent,
97
+ parent_class: inClass && indent > 0 ? className : undefined,
98
+ });
99
+ }
100
+ }
101
+ else if (stripped.startsWith('import ') || stripped.startsWith('from ')) {
102
+ nodes.push({
103
+ type: 'Import',
104
+ line: stripped,
105
+ lineno: i + 1,
106
+ });
107
+ }
108
+ // Detect dedent
109
+ if (indent <= currentIndent && (inClass || inFunction)) {
110
+ if (indent === 0) {
111
+ inClass = false;
112
+ inFunction = false;
113
+ }
114
+ }
115
+ currentIndent = indent;
116
+ }
117
+ return nodes;
118
+ }
119
+ convertToGenericAST(pythonAST, filePath) {
120
+ const convertNode = (node, parent) => {
121
+ const generic = {
122
+ type: this.mapPythonNodeType(node.type),
123
+ id: `${filePath}:${node.lineno || 0}:${node.col_offset || 0}`,
124
+ location: {
125
+ file: filePath,
126
+ startLine: node.lineno || 0,
127
+ startColumn: node.col_offset || 0,
128
+ endLine: node.end_lineno || node.lineno || 0,
129
+ endColumn: node.end_col_offset || 0,
130
+ byteOffset: 0,
131
+ },
132
+ children: [],
133
+ parent,
134
+ metadata: { ...node },
135
+ };
136
+ // Convert children
137
+ if (node.body && Array.isArray(node.body)) {
138
+ generic.children = node.body.map((child) => convertNode(child, generic));
139
+ }
140
+ return generic;
141
+ };
142
+ return convertNode(pythonAST);
143
+ }
144
+ mapPythonNodeType(pythonType) {
145
+ const typeMap = {
146
+ 'Module': 'Program',
147
+ 'FunctionDef': 'FunctionDeclaration',
148
+ 'AsyncFunctionDef': 'FunctionDeclaration',
149
+ 'ClassDef': 'ClassDeclaration',
150
+ 'Import': 'ImportDeclaration',
151
+ 'ImportFrom': 'ImportDeclaration',
152
+ 'Assign': 'VariableDeclaration',
153
+ 'AnnAssign': 'VariableDeclaration',
154
+ 'If': 'IfStatement',
155
+ 'For': 'ForStatement',
156
+ 'While': 'WhileStatement',
157
+ 'Try': 'TryStatement',
158
+ 'With': 'WithStatement',
159
+ 'Return': 'ReturnStatement',
160
+ 'Expr': 'ExpressionStatement',
161
+ 'Call': 'CallExpression',
162
+ 'Attribute': 'MemberExpression',
163
+ 'Name': 'Identifier',
164
+ 'Constant': 'Literal',
165
+ 'List': 'ArrayExpression',
166
+ 'Dict': 'ObjectExpression',
167
+ };
168
+ return typeMap[pythonType] || pythonType;
169
+ }
170
+ extractComments() {
171
+ const comments = [];
172
+ const lines = this.source.split('\n');
173
+ for (let i = 0; i < lines.length; i++) {
174
+ const line = lines[i];
175
+ const hashIndex = line.indexOf('#');
176
+ if (hashIndex !== -1) {
177
+ comments.push({
178
+ type: 'Line',
179
+ value: line.substring(hashIndex + 1).trim(),
180
+ line: i + 1,
181
+ });
182
+ }
183
+ }
184
+ return comments;
185
+ }
186
+ fallbackParse(filePath) {
187
+ // Basic regex-based fallback
188
+ const ast = {
189
+ type: 'Program',
190
+ id: `${filePath}:0:0`,
191
+ location: {
192
+ file: filePath,
193
+ startLine: 0,
194
+ startColumn: 0,
195
+ endLine: this.lines.length,
196
+ endColumn: 0,
197
+ byteOffset: 0,
198
+ },
199
+ children: this.extractPythonStructure(this.source).map(node => ({
200
+ type: this.mapPythonNodeType(node.type),
201
+ id: `${filePath}:${node.lineno || 0}:0`,
202
+ location: {
203
+ file: filePath,
204
+ startLine: node.lineno || 0,
205
+ startColumn: node.col_offset || 0,
206
+ endLine: node.lineno || 0,
207
+ endColumn: 0,
208
+ byteOffset: 0,
209
+ },
210
+ children: [],
211
+ metadata: node,
212
+ })),
213
+ metadata: {},
214
+ };
215
+ return {
216
+ ast,
217
+ errors: [],
218
+ warnings: [{ message: 'Using fallback parser' }],
219
+ tokens: [],
220
+ comments: this.extractComments(),
221
+ };
222
+ }
223
+ splitIntoChunks(buffer) {
224
+ // Split by blank lines or dedent
225
+ const lines = buffer.split('\n');
226
+ const chunks = [];
227
+ let currentChunk = [];
228
+ for (const line of lines) {
229
+ if (line.trim() === '' && currentChunk.length > 0) {
230
+ chunks.push(currentChunk.join('\n'));
231
+ currentChunk = [];
232
+ }
233
+ else {
234
+ currentChunk.push(line);
235
+ }
236
+ }
237
+ return {
238
+ complete: chunks,
239
+ remaining: currentChunk.join('\n'),
240
+ };
241
+ }
242
+ }
243
+ exports.PythonParser = PythonParser;
244
+ class PythonAnalyzer {
245
+ analyze(ast, context) {
246
+ const symbolTable = this.buildSymbolTable(ast);
247
+ const metrics = this.calculateMetrics(ast);
248
+ const securityIssues = this.findSecurityIssues(ast);
249
+ return {
250
+ symbols: symbolTable,
251
+ callGraph: this.buildCallGraph(ast),
252
+ dataFlow: { definitions: new Map(), uses: new Map(), taintedSources: [], sinks: [] },
253
+ controlFlow: this.buildControlFlow(ast),
254
+ typeInference: new Map(),
255
+ metrics,
256
+ suggestions: this.generateSuggestions(ast, metrics, securityIssues),
257
+ };
258
+ }
259
+ buildSymbolTable(ast) {
260
+ const variables = new Map();
261
+ const functions = new Map();
262
+ const classes = new Map();
263
+ const traverse = (node) => {
264
+ switch (node.type) {
265
+ case 'FunctionDeclaration':
266
+ functions.set(node.metadata.name, {
267
+ name: node.metadata.name,
268
+ signature: this.extractSignature(node),
269
+ parameters: [],
270
+ returnType: 'Any',
271
+ async: false,
272
+ pure: this.isPureFunction(node),
273
+ recursive: this.isRecursive(node),
274
+ complexity: this.calculateComplexity(node),
275
+ callers: [],
276
+ callees: this.findCallees(node),
277
+ });
278
+ break;
279
+ case 'ClassDeclaration':
280
+ classes.set(node.metadata.name, {
281
+ name: node.metadata.name,
282
+ superClass: node.metadata.bases?.[0],
283
+ interfaces: [],
284
+ methods: [],
285
+ properties: [],
286
+ isAbstract: false,
287
+ isFinal: false,
288
+ });
289
+ break;
290
+ case 'VariableDeclaration':
291
+ const varName = this.extractVariableName(node);
292
+ if (varName) {
293
+ variables.set(varName, {
294
+ name: varName,
295
+ type: 'Any',
296
+ mutable: true,
297
+ scope: 'local',
298
+ initialized: true,
299
+ references: [],
300
+ });
301
+ }
302
+ break;
303
+ }
304
+ node.children.forEach(traverse);
305
+ };
306
+ traverse(ast);
307
+ return {
308
+ variables,
309
+ functions,
310
+ classes,
311
+ modules: new Map(),
312
+ imports: this.extractImports(ast),
313
+ exports: [],
314
+ };
315
+ }
316
+ extractSignature(node) {
317
+ return `def ${node.metadata.name}(...)`;
318
+ }
319
+ isPureFunction(node) {
320
+ // Check for side effects
321
+ let hasSideEffects = false;
322
+ const checkSideEffects = (n) => {
323
+ if (n.type === 'CallExpression') {
324
+ const funcName = n.metadata.func?.name || '';
325
+ if (['print', 'open', 'write', 'exec', 'eval'].includes(funcName)) {
326
+ hasSideEffects = true;
327
+ }
328
+ }
329
+ n.children.forEach(checkSideEffects);
330
+ };
331
+ checkSideEffects(node);
332
+ return !hasSideEffects;
333
+ }
334
+ isRecursive(node) {
335
+ const funcName = node.metadata.name;
336
+ let callsSelf = false;
337
+ const checkRecursion = (n) => {
338
+ if (n.type === 'CallExpression' && n.metadata.func?.name === funcName) {
339
+ callsSelf = true;
340
+ }
341
+ n.children.forEach(checkRecursion);
342
+ };
343
+ checkRecursion(node);
344
+ return callsSelf;
345
+ }
346
+ calculateComplexity(node) {
347
+ let branches = 0;
348
+ let nesting = 0;
349
+ let maxNesting = 0;
350
+ const traverse = (n, depth) => {
351
+ maxNesting = Math.max(maxNesting, depth);
352
+ if (['IfStatement', 'ForStatement', 'WhileStatement', 'TryStatement'].includes(n.type)) {
353
+ branches++;
354
+ nesting = depth;
355
+ }
356
+ n.children.forEach(child => traverse(child, depth + 1));
357
+ };
358
+ traverse(node, 0);
359
+ return {
360
+ cyclomatic: branches + 1,
361
+ cognitive: branches + maxNesting,
362
+ nestingDepth: maxNesting,
363
+ parameterCount: node.metadata.args?.length || 0,
364
+ };
365
+ }
366
+ findCallees(node) {
367
+ const callees = [];
368
+ const traverse = (n) => {
369
+ if (n.type === 'CallExpression' && n.metadata.func?.name) {
370
+ callees.push(n.metadata.func.name);
371
+ }
372
+ n.children.forEach(traverse);
373
+ };
374
+ traverse(node);
375
+ return callees;
376
+ }
377
+ extractVariableName(node) {
378
+ // Extract variable name from assignment
379
+ return node.metadata.targets?.[0]?.name || null;
380
+ }
381
+ extractImports(ast) {
382
+ const imports = [];
383
+ const traverse = (node) => {
384
+ if (node.type === 'ImportDeclaration') {
385
+ imports.push({
386
+ source: node.metadata.module || node.metadata.line,
387
+ names: node.metadata.names || [],
388
+ });
389
+ }
390
+ node.children.forEach(traverse);
391
+ };
392
+ traverse(ast);
393
+ return imports;
394
+ }
395
+ calculateMetrics(ast) {
396
+ let linesOfCode = 0;
397
+ let logicalLines = 0;
398
+ let commentLines = 0;
399
+ let blankLines = 0;
400
+ // This would need access to source
401
+ // Simplified calculation
402
+ const countNodes = (node) => {
403
+ return 1 + node.children.reduce((sum, child) => sum + countNodes(child), 0);
404
+ };
405
+ const totalNodes = countNodes(ast);
406
+ return {
407
+ linesOfCode: totalNodes * 3, // Rough estimate
408
+ logicalLines: Math.floor(totalNodes * 1.5),
409
+ commentLines: 0,
410
+ blankLines: 0,
411
+ cyclomaticComplexity: this.calculateCyclomatic(ast),
412
+ cognitiveComplexity: 0,
413
+ halsteadMetrics: this.calculateHalstead(ast),
414
+ maintainabilityIndex: 70,
415
+ duplicateRate: 0,
416
+ };
417
+ }
418
+ calculateCyclomatic(ast) {
419
+ let branches = 0;
420
+ const traverse = (node) => {
421
+ if (['IfStatement', 'ForStatement', 'WhileStatement', 'TryStatement', 'ConditionalExpression'].includes(node.type)) {
422
+ branches++;
423
+ }
424
+ node.children.forEach(traverse);
425
+ };
426
+ traverse(ast);
427
+ return branches + 1;
428
+ }
429
+ calculateHalstead(ast) {
430
+ // Simplified Halstead metrics
431
+ const operators = new Set();
432
+ const operands = new Set();
433
+ const traverse = (node) => {
434
+ if (node.type === 'BinaryExpression' || node.type === 'UnaryExpression') {
435
+ operators.add(node.metadata.op);
436
+ }
437
+ if (node.type === 'Identifier' || node.type === 'Literal') {
438
+ operands.add(node.metadata.name || node.metadata.value);
439
+ }
440
+ node.children.forEach(traverse);
441
+ };
442
+ traverse(ast);
443
+ const n1 = operators.size;
444
+ const n2 = operands.size;
445
+ const N1 = operators.size * 2; // Estimated
446
+ const N2 = operands.size * 2;
447
+ const vocabulary = n1 + n2;
448
+ const length = N1 + N2;
449
+ const volume = length * Math.log2(vocabulary || 1);
450
+ const difficulty = (n1 / 2) * (N2 / (n2 || 1));
451
+ const effort = difficulty * volume;
452
+ return {
453
+ operators: n1,
454
+ operands: n2,
455
+ uniqueOperators: n1,
456
+ uniqueOperands: n2,
457
+ volume: Math.round(volume),
458
+ difficulty: Math.round(difficulty),
459
+ effort: Math.round(effort),
460
+ timeToProgram: Math.round(effort / 18),
461
+ bugsDelivered: Math.round(volume / 3000),
462
+ };
463
+ }
464
+ findSecurityIssues(ast) {
465
+ const issues = [];
466
+ const traverse = (node) => {
467
+ // Check for dangerous functions
468
+ if (node.type === 'CallExpression') {
469
+ const funcName = node.metadata.func?.name || '';
470
+ const funcAttr = node.metadata.func?.attr || '';
471
+ // SQL Injection
472
+ if (['execute', 'executemany', 'raw'].includes(funcName)) {
473
+ const hasStringConcat = this.hasStringConcat(node);
474
+ if (hasStringConcat) {
475
+ issues.push({
476
+ id: 'PY001',
477
+ severity: 'critical',
478
+ category: 'sql-injection',
479
+ location: node.location,
480
+ description: 'Potential SQL injection via string concatenation',
481
+ remediation: 'Use parameterized queries',
482
+ falsePositiveLikelihood: 0.3,
483
+ });
484
+ }
485
+ }
486
+ // Command Injection
487
+ if (['os.system', 'subprocess.call', 'subprocess.run', 'subprocess.Popen'].includes(funcAttr)) {
488
+ const hasUserInput = this.hasUserInput(node);
489
+ if (hasUserInput) {
490
+ issues.push({
491
+ id: 'PY002',
492
+ severity: 'critical',
493
+ category: 'command-injection',
494
+ location: node.location,
495
+ description: 'Potential command injection',
496
+ remediation: 'Use list arguments instead of shell=True',
497
+ falsePositiveLikelihood: 0.2,
498
+ });
499
+ }
500
+ }
501
+ // eval/exec
502
+ if (['eval', 'exec', 'compile'].includes(funcName)) {
503
+ issues.push({
504
+ id: 'PY003',
505
+ severity: 'high',
506
+ category: 'insecure-deserialization',
507
+ location: node.location,
508
+ description: 'Dangerous use of eval/exec',
509
+ remediation: 'Use ast.literal_eval for safe evaluation',
510
+ falsePositiveLikelihood: 0.1,
511
+ });
512
+ }
513
+ // Pickle
514
+ if (['pickle.load', 'pickle.loads', 'cPickle.load'].includes(funcAttr)) {
515
+ issues.push({
516
+ id: 'PY004',
517
+ severity: 'high',
518
+ category: 'insecure-deserialization',
519
+ location: node.location,
520
+ description: 'Unsafe deserialization with pickle',
521
+ remediation: 'Use json or msgpack instead',
522
+ falsePositiveLikelihood: 0.2,
523
+ });
524
+ }
525
+ // Hardcoded secrets
526
+ if (funcName === 'password' || funcAttr?.includes('password')) {
527
+ const args = node.metadata.args || [];
528
+ for (const arg of args) {
529
+ if (arg.type === 'Literal' && typeof arg.value === 'string' && arg.value.length > 0) {
530
+ issues.push({
531
+ id: 'PY005',
532
+ severity: 'critical',
533
+ category: 'sensitive-data-exposure',
534
+ location: node.location,
535
+ description: 'Potential hardcoded password',
536
+ remediation: 'Use environment variables or secret management',
537
+ falsePositiveLikelihood: 0.4,
538
+ });
539
+ }
540
+ }
541
+ }
542
+ }
543
+ // Check for debug mode
544
+ if (node.type === 'Assignment' && node.metadata.name === 'DEBUG') {
545
+ if (node.metadata.value === true) {
546
+ issues.push({
547
+ id: 'PY006',
548
+ severity: 'medium',
549
+ category: 'sensitive-data-exposure',
550
+ location: node.location,
551
+ description: 'DEBUG mode enabled',
552
+ remediation: 'Set DEBUG=False in production',
553
+ falsePositiveLikelihood: 0.1,
554
+ });
555
+ }
556
+ }
557
+ node.children.forEach(traverse);
558
+ };
559
+ traverse(ast);
560
+ return issues;
561
+ }
562
+ hasStringConcat(node) {
563
+ // Check for string concatenation or formatting
564
+ let found = false;
565
+ const traverse = (n) => {
566
+ if (n.type === 'BinaryExpression' && n.metadata.op === '+') {
567
+ found = true;
568
+ }
569
+ if (n.type === 'CallExpression' && ['format', 'f-string'].includes(n.metadata.func?.name)) {
570
+ found = true;
571
+ }
572
+ n.children.forEach(traverse);
573
+ };
574
+ traverse(node);
575
+ return found;
576
+ }
577
+ hasUserInput(node) {
578
+ // Check for user input sources
579
+ let found = false;
580
+ const traverse = (n) => {
581
+ if (n.type === 'CallExpression') {
582
+ const funcName = n.metadata.func?.name || '';
583
+ if (['input', 'request', 'argv'].includes(funcName)) {
584
+ found = true;
585
+ }
586
+ }
587
+ n.children.forEach(traverse);
588
+ };
589
+ traverse(node);
590
+ return found;
591
+ }
592
+ buildCallGraph(ast) {
593
+ const nodes = [];
594
+ const edges = [];
595
+ const traverse = (node) => {
596
+ if (node.type === 'FunctionDeclaration') {
597
+ const funcName = node.metadata.name;
598
+ nodes.push(funcName);
599
+ // Find calls within this function
600
+ const findCalls = (n) => {
601
+ if (n.type === 'CallExpression') {
602
+ const callee = n.metadata.func?.name;
603
+ if (callee) {
604
+ edges.push({ from: funcName, to: callee });
605
+ }
606
+ }
607
+ n.children.forEach(findCalls);
608
+ };
609
+ findCalls(node);
610
+ }
611
+ node.children.forEach(traverse);
612
+ };
613
+ traverse(ast);
614
+ return { nodes, edges, entryPoints: nodes.filter(n => !edges.some(e => e.to === n)), deadCode: [] };
615
+ }
616
+ buildControlFlow(ast) {
617
+ // Simplified control flow graph
618
+ return {
619
+ nodes: [],
620
+ edges: [],
621
+ loops: [],
622
+ branches: [],
623
+ };
624
+ }
625
+ generateSuggestions(ast, metrics, issues) {
626
+ const suggestions = [];
627
+ // Complexity suggestions
628
+ if (metrics.cyclomaticComplexity > 10) {
629
+ suggestions.push({
630
+ type: 'refactor',
631
+ message: 'Function is too complex. Consider breaking it down.',
632
+ severity: 'warning',
633
+ });
634
+ }
635
+ // Security suggestions
636
+ for (const issue of issues) {
637
+ suggestions.push({
638
+ type: 'security',
639
+ message: issue.description,
640
+ severity: issue.severity,
641
+ remediation: issue.remediation,
642
+ });
643
+ }
644
+ return suggestions;
645
+ }
646
+ }
647
+ exports.PythonAnalyzer = PythonAnalyzer;
648
+ exports.PythonLanguageSupport = {
649
+ id: 'python',
650
+ name: 'Python',
651
+ extensions: ['.py', '.pyw', '.pyi'],
652
+ parser: new PythonParser(),
653
+ analyzer: new PythonAnalyzer(),
654
+ };
655
+ //# sourceMappingURL=python.js.map