pi-lens 3.8.37 → 3.8.38

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/CHANGELOG.md CHANGED
@@ -4,6 +4,17 @@ All notable changes to pi-lens will be documented in this file.
4
4
 
5
5
  ## [Unreleased]
6
6
 
7
+ ## [3.8.38] - 2026-05-02
8
+
9
+ ### Added
10
+
11
+ - **`RuleCache` respects `PILENS_DATA_DIR`** — tree-sitter rule cache files are now stored under `getProjectDataDir(rootDir)` instead of `<cwd>/.pi-lens/cache`, consistent with all other pi-lens data files. Projects using `PILENS_DATA_DIR` no longer get a stray `.pi-lens` directory created in the project root. (PR #47 by @tifandotme)
12
+
13
+ ### Fixed
14
+
15
+ - **ReDoS: `gleamRe` and `zigRe` compiler parsers** — residual `\s*` quantifiers (which match `\n` in JS) replaced with `[ \t]*` to eliminate cross-line backtracking. Completes the SonarCloud S5852 remediation started in 3.8.37.
16
+ - **Test env leak in `file-utils.test.ts`** — `PILENS_DATA_DIR` is now saved and restored in a `finally` block so it doesn't bleed into subsequent tests in the suite.
17
+
7
18
  ## [3.8.37] - 2026-05-02
8
19
 
9
20
  ### Fixed
package/README.md CHANGED
@@ -1,5 +1,5 @@
1
1
  <p align="center">
2
- <img src="https://raw.githubusercontent.com/apmantza/pi-lens/master/banner.svg" alt="pi-lens" width="1100">
2
+ <img src="https://raw.githubusercontent.com/apmantza/pi-lens/master/banner.png" alt="pi-lens" width="1100">
3
3
  </p>
4
4
 
5
5
  # pi-lens
package/banner.png ADDED
Binary file
package/banner.svg CHANGED
@@ -1,4 +1,4 @@
1
- <svg width="1100" height="280" viewBox="0 0 1100 280" xmlns="http://www.w3.org/2000/svg">
1
+ <svg width="1100" height="310" viewBox="0 0 1100 310" xmlns="http://www.w3.org/2000/svg">
2
2
  <defs>
3
3
  <linearGradient id="bg" x1="0%" y1="0%" x2="100%" y2="100%">
4
4
  <stop offset="0%" stop-color="#0d1117"/>
@@ -13,26 +13,26 @@
13
13
  <stop offset="100%" stop-color="#2f81f700"/>
14
14
  </linearGradient>
15
15
  <clipPath id="bounds">
16
- <rect width="1100" height="280" rx="12"/>
16
+ <rect width="1100" height="310" rx="12"/>
17
17
  </clipPath>
18
18
  </defs>
19
19
 
20
20
  <!-- Background -->
21
- <rect width="1100" height="280" fill="url(#bg)" rx="12"/>
21
+ <rect width="1100" height="310" fill="url(#bg)" rx="12"/>
22
22
 
23
23
  <!-- Top accent line -->
24
24
  <rect x="0" y="0" width="1100" height="3" fill="url(#accent)" rx="1.5" clip-path="url(#bounds)"/>
25
25
 
26
26
  <!-- Decorative aperture rings (right side) -->
27
27
  <g opacity="0.07" clip-path="url(#bounds)">
28
- <circle cx="920" cy="140" r="180" fill="none" stroke="#2f81f7" stroke-width="1.5"/>
29
- <circle cx="920" cy="140" r="145" fill="none" stroke="#2f81f7" stroke-width="1"/>
30
- <circle cx="920" cy="140" r="110" fill="none" stroke="#2f81f7" stroke-width="1"/>
31
- <circle cx="920" cy="140" r="75" fill="none" stroke="#2f81f7" stroke-width="1"/>
32
- <line x1="740" y1="140" x2="1100" y2="140" stroke="#2f81f7" stroke-width="0.8"/>
33
- <line x1="920" y1="-40" x2="920" y2="320" stroke="#2f81f7" stroke-width="0.8"/>
34
- <line x1="793" y1="13" x2="1047" y2="267" stroke="#2f81f7" stroke-width="0.6"/>
35
- <line x1="1047" y1="13" x2="793" y2="267" stroke="#2f81f7" stroke-width="0.6"/>
28
+ <circle cx="920" cy="155" r="180" fill="none" stroke="#2f81f7" stroke-width="1.5"/>
29
+ <circle cx="920" cy="155" r="145" fill="none" stroke="#2f81f7" stroke-width="1"/>
30
+ <circle cx="920" cy="155" r="110" fill="none" stroke="#2f81f7" stroke-width="1"/>
31
+ <circle cx="920" cy="155" r="75" fill="none" stroke="#2f81f7" stroke-width="1"/>
32
+ <line x1="740" y1="155" x2="1100" y2="155" stroke="#2f81f7" stroke-width="0.8"/>
33
+ <line x1="920" y1="-40" x2="920" y2="350" stroke="#2f81f7" stroke-width="0.8"/>
34
+ <line x1="793" y1="28" x2="1047" y2="282" stroke="#2f81f7" stroke-width="0.6"/>
35
+ <line x1="1047" y1="28" x2="793" y2="282" stroke="#2f81f7" stroke-width="0.6"/>
36
36
  </g>
37
37
 
38
38
  <!-- Lens icon -->
@@ -53,7 +53,7 @@
53
53
  <!-- Tagline -->
54
54
  <text x="261" y="164" font-family="-apple-system, BlinkMacSystemFont, 'Segoe UI', Helvetica, sans-serif" font-size="21" font-weight="400" fill="#8b949e" letter-spacing="0.3">Real-time code intelligence for AI agents</text>
55
55
 
56
- <!-- Feature pills -->
56
+ <!-- Feature pills — row 1 -->
57
57
  <g font-family="-apple-system, BlinkMacSystemFont, 'Segoe UI', Helvetica, sans-serif" font-size="12" font-weight="500">
58
58
  <rect x="261" y="196" width="56" height="24" rx="12" fill="#2f81f715" stroke="#2f81f740" stroke-width="1"/>
59
59
  <text x="289" y="213" fill="#58a6ff" text-anchor="middle">LSP</text>
@@ -64,10 +64,25 @@
64
64
  <rect x="405" y="196" width="90" height="24" rx="12" fill="#2f81f715" stroke="#2f81f740" stroke-width="1"/>
65
65
  <text x="450" y="213" fill="#58a6ff" text-anchor="middle">Formatters</text>
66
66
 
67
- <rect x="505" y="196" width="152" height="24" rx="12" fill="#2f81f715" stroke="#2f81f740" stroke-width="1"/>
68
- <text x="581" y="213" fill="#58a6ff" text-anchor="middle">Structural Analysis</text>
67
+ <rect x="505" y="196" width="84" height="24" rx="12" fill="#2f81f715" stroke="#2f81f740" stroke-width="1"/>
68
+ <text x="547" y="213" fill="#58a6ff" text-anchor="middle">Auto-Fix</text>
69
69
 
70
- <rect x="667" y="196" width="96" height="24" rx="12" fill="#2f81f715" stroke="#2f81f740" stroke-width="1"/>
71
- <text x="715" y="213" fill="#58a6ff" text-anchor="middle">Read-Guard</text>
70
+ <rect x="599" y="196" width="100" height="24" rx="12" fill="#2f81f715" stroke="#2f81f740" stroke-width="1"/>
71
+ <text x="649" y="213" fill="#58a6ff" text-anchor="middle">Read-Guard</text>
72
+ </g>
73
+
74
+ <!-- Feature pills — row 2 -->
75
+ <g font-family="-apple-system, BlinkMacSystemFont, 'Segoe UI', Helvetica, sans-serif" font-size="12" font-weight="500">
76
+ <rect x="261" y="228" width="152" height="24" rx="12" fill="#2f81f715" stroke="#2f81f740" stroke-width="1"/>
77
+ <text x="337" y="245" fill="#58a6ff" text-anchor="middle">Structural Analysis</text>
78
+
79
+ <rect x="423" y="228" width="96" height="24" rx="12" fill="#2f81f715" stroke="#2f81f740" stroke-width="1"/>
80
+ <text x="471" y="245" fill="#58a6ff" text-anchor="middle">Cascade</text>
81
+
82
+ <rect x="529" y="228" width="100" height="24" rx="12" fill="#2f81f715" stroke="#2f81f740" stroke-width="1"/>
83
+ <text x="579" y="245" fill="#58a6ff" text-anchor="middle">Tree-sitter</text>
84
+
85
+ <rect x="639" y="228" width="96" height="24" rx="12" fill="#2f81f715" stroke="#2f81f740" stroke-width="1"/>
86
+ <text x="687" y="245" fill="#58a6ff" text-anchor="middle">ast-grep</text>
72
87
  </g>
73
88
  </svg>
@@ -8,6 +8,7 @@
8
8
  import * as crypto from "node:crypto";
9
9
  import * as fs from "node:fs";
10
10
  import * as path from "node:path";
11
+ import { getProjectDataDir } from "../file-utils.js";
11
12
 
12
13
  const CACHE_VERSION = "v1";
13
14
 
@@ -34,7 +35,7 @@ export class RuleCache {
34
35
  private cacheDir: string;
35
36
 
36
37
  constructor(language: string, rootDir = process.cwd()) {
37
- this.cacheDir = path.join(rootDir, ".pi-lens", "cache");
38
+ this.cacheDir = path.join(getProjectDataDir(rootDir), "cache");
38
39
  this.cacheFile = path.join(
39
40
  this.cacheDir,
40
41
  `${language}-rules-${CACHE_VERSION}.json`,
@@ -1395,7 +1395,7 @@ export async function handleBooboo(
1395
1395
  });
1396
1396
  const output = (result.stdout || "") + (result.stderr || "");
1397
1397
  const gleamRe =
1398
- /^([^:\n]+):(\d+):(\d+)\s*(?:error|warning)[^\n]*\n([^\n]+)/gm;
1398
+ /^([^:\n]+):(\d+):(\d+)[ \t]*(?:error|warning)[^\n]*\n([^\n]+)/gm;
1399
1399
  for (const m of output.matchAll(gleamRe)) {
1400
1400
  const [, file, line, col, msg] = m;
1401
1401
  const absFile = path.isAbsolute(file)
@@ -1426,7 +1426,7 @@ export async function handleBooboo(
1426
1426
  timeout: 120_000,
1427
1427
  });
1428
1428
  const output = (result.stdout || "") + (result.stderr || "");
1429
- const zigRe = /^([^:\n]+):(\d+):(\d+):\s*(error|warning|note):\s*([^\n]+)/gm;
1429
+ const zigRe = /^([^:\n]+):(\d+):(\d+):[ \t]*(error|warning|note):[ \t]*([^\n]+)/gm;
1430
1430
  for (const m of output.matchAll(zigRe)) {
1431
1431
  const [, file, line, col, sev, msg] = m;
1432
1432
  const absFile = path.isAbsolute(file)
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "pi-lens",
3
- "version": "3.8.37",
3
+ "version": "3.8.38",
4
4
  "type": "module",
5
5
  "description": "Real-time code feedback for pi \u2014 LSP, linters, formatters, type-checking, structural analysis & booboo",
6
6
  "repository": {
@@ -55,7 +55,8 @@
55
55
  "tsconfig.json",
56
56
  "README.md",
57
57
  "CHANGELOG.md",
58
- "banner.svg"
58
+ "banner.svg",
59
+ "banner.png"
59
60
  ],
60
61
  "peerDependencies": {
61
62
  "@mariozechner/pi-coding-agent": "*"