pi-lens 1.3.7 → 1.3.8

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.
@@ -238,6 +238,7 @@ function long(): number {
238
238
  maintainabilityIndex: 75,
239
239
  linesOfCode: 100,
240
240
  commentLines: 10,
241
+ codeEntropy: 0.5,
241
242
  };
242
243
 
243
244
  const formatted = client.formatMetrics(metrics);
@@ -259,6 +260,7 @@ function long(): number {
259
260
  maintainabilityIndex: 25,
260
261
  linesOfCode: 500,
261
262
  commentLines: 10,
263
+ codeEntropy: 0.5,
262
264
  };
263
265
 
264
266
  const formatted = client.formatMetrics(metrics);
@@ -34,6 +34,7 @@ export interface FileComplexity {
34
34
  maintainabilityIndex: number; // 0-100
35
35
  linesOfCode: number;
36
36
  commentLines: number;
37
+ codeEntropy: number; // Shannon entropy (0-1, lower = more predictable)
37
38
  }
38
39
 
39
40
  export interface FunctionMetrics {
@@ -195,6 +196,9 @@ export class ComplexityClient {
195
196
  commentLines
196
197
  );
197
198
 
199
+ // Code Entropy (Shannon entropy of code tokens)
200
+ const codeEntropy = this.calculateCodeEntropy(content);
201
+
198
202
  return {
199
203
  filePath: path.relative(process.cwd(), absolutePath),
200
204
  maxNestingDepth,
@@ -208,6 +212,7 @@ export class ComplexityClient {
208
212
  maintainabilityIndex: Math.round(maintainabilityIndex * 10) / 10,
209
213
  linesOfCode: codeLines,
210
214
  commentLines,
215
+ codeEntropy: Math.round(codeEntropy * 1000) / 1000,
211
216
  };
212
217
  } catch (err: any) {
213
218
  this.log(`Analysis error for ${filePath}: ${err.message}`);
@@ -242,6 +247,13 @@ export class ComplexityClient {
242
247
  parts.push(` Max nesting: ${metrics.maxNestingDepth} levels (consider extracting)`);
243
248
  }
244
249
 
250
+ // Code entropy (0-1, lower = more predictable)
251
+ if (metrics.codeEntropy > 0.8) {
252
+ parts.push(` Entropy: ${metrics.codeEntropy} (high — code may be unpredictable/AI-generated)`);
253
+ } else if (metrics.codeEntropy < 0.3) {
254
+ parts.push(` Entropy: ${metrics.codeEntropy} (low — repetitive patterns detected)`);
255
+ }
256
+
245
257
  // Function length
246
258
  if (metrics.maxFunctionLength > 50) {
247
259
  parts.push(` Longest function: ${metrics.maxFunctionLength} lines (avg: ${metrics.avgFunctionLength})`);
@@ -491,6 +503,45 @@ export class ComplexityClient {
491
503
  return totalOps * Math.log2(uniqueOps);
492
504
  }
493
505
 
506
+ /**
507
+ * Calculate Shannon entropy of code tokens
508
+ * Measures predictability/uniformity of code
509
+ * 0 = completely uniform, 1 = maximum entropy
510
+ */
511
+ private calculateCodeEntropy(sourceText: string): number {
512
+ // Tokenize by splitting on whitespace and common delimiters
513
+ const tokens = sourceText
514
+ .replace(/\/\/.*/g, "") // Remove single-line comments
515
+ .replace(/\/\*[\s\S]*?\*\//g, "") // Remove multi-line comments
516
+ .replace(/["'`][^"'`]*["'`]/g, "STR") // Normalize strings
517
+ .replace(/\b\d+(\.\d+)?\b/g, "NUM") // Normalize numbers
518
+ .split(/[\s\n\r\t,;:()[\]{}=<>!&|+\-*/%^~?]+/)
519
+ .filter(t => t.length > 0);
520
+
521
+ if (tokens.length === 0) return 0;
522
+
523
+ // Count token frequencies
524
+ const freq = new Map<string, number>();
525
+ for (const token of tokens) {
526
+ freq.set(token, (freq.get(token) || 0) + 1);
527
+ }
528
+
529
+ // Calculate Shannon entropy: H = -sum(p * log2(p))
530
+ let entropy = 0;
531
+ for (const count of freq.values()) {
532
+ const p = count / tokens.length;
533
+ if (p > 0) {
534
+ entropy -= p * Math.log2(p);
535
+ }
536
+ }
537
+
538
+ // Normalize to 0-1 range
539
+ const maxEntropy = Math.log2(freq.size);
540
+ if (maxEntropy === 0) return 0;
541
+
542
+ return Math.min(1, entropy / maxEntropy);
543
+ }
544
+
494
545
  private isKeyword(text: string): boolean {
495
546
  const keywords = new Set([
496
547
  "if", "else", "for", "while", "do", "switch", "case", "break", "continue",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "pi-lens",
3
- "version": "1.3.7",
3
+ "version": "1.3.8",
4
4
  "description": "Real-time code feedback for pi — TypeScript LSP, Biome, ast-grep, Ruff, TODO scanner, dead code, duplicate detection, type coverage",
5
5
  "repository": {
6
6
  "type": "git",