pi-lens 3.8.73 → 3.8.74

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 (205) hide show
  1. package/CHANGELOG.md +1116 -0
  2. package/README.md +37 -21
  3. package/dist/clients/atomic-write.js +3 -3
  4. package/dist/clients/bus-events-logger.js +5 -1
  5. package/dist/clients/cache/rule-cache.js +43 -2
  6. package/dist/clients/cache-observability.js +211 -0
  7. package/dist/clients/call-graph.js +20 -0
  8. package/dist/clients/cascade-logger.js +5 -1
  9. package/dist/clients/complexity-client.js +4 -7
  10. package/dist/clients/dependency-checker.js +151 -20
  11. package/dist/clients/diagnostic-dispositions.js +22 -2
  12. package/dist/clients/dispatch/auxiliary-lsp.js +34 -0
  13. package/dist/clients/dispatch/dispatcher.js +16 -1
  14. package/dist/clients/dispatch/fact-store.js +11 -0
  15. package/dist/clients/dispatch/facts/function-facts.js +14 -0
  16. package/dist/clients/dispatch/facts/import-facts.js +100 -101
  17. package/dist/clients/dispatch/facts/tree-sitter-facts.js +5 -8
  18. package/dist/clients/dispatch/facts/try-catch-facts.js +13 -0
  19. package/dist/clients/dispatch/integration.js +94 -15
  20. package/dist/clients/dispatch/rules/async-noise.js +1 -0
  21. package/dist/clients/dispatch/rules/unsafe-boundary.js +7 -0
  22. package/dist/clients/dispatch/runners/ast-grep-napi.js +24 -1
  23. package/dist/clients/dispatch/runners/psscriptanalyzer.js +10 -1
  24. package/dist/clients/dispatch/runners/tree-sitter.js +153 -166
  25. package/dist/clients/dispatch/runners/utils/runner-helpers.js +17 -18
  26. package/dist/clients/feature-hints.js +53 -7
  27. package/dist/clients/file-kinds.js +86 -31
  28. package/dist/clients/fix-worklog.js +14 -2
  29. package/dist/clients/generated-artifacts.js +21 -0
  30. package/dist/clients/gzip-stage-write.js +84 -0
  31. package/dist/clients/installer/index.js +358 -129
  32. package/dist/clients/knip-client.js +64 -1
  33. package/dist/clients/language-profile.js +61 -72
  34. package/dist/clients/latency-logger.js +6 -16
  35. package/dist/clients/lens-config.js +128 -165
  36. package/dist/clients/lens-engine.js +39 -5
  37. package/dist/clients/lens-flag-registry.js +285 -0
  38. package/dist/clients/lens-map.js +2 -7
  39. package/dist/clients/log-cleanup.js +6 -17
  40. package/dist/clients/lsp/cascade-tier.js +22 -2
  41. package/dist/clients/lsp/client.js +74 -10
  42. package/dist/clients/lsp/config.js +62 -9
  43. package/dist/clients/lsp/index.js +34 -24
  44. package/dist/clients/lsp/language.js +4 -1
  45. package/dist/clients/lsp/launch.js +8 -6
  46. package/dist/clients/lsp/server.js +84 -29
  47. package/dist/clients/lsp-document-symbols.js +112 -0
  48. package/dist/clients/mcp/analyze.js +5 -4
  49. package/dist/clients/mcp/review.js +36 -3
  50. package/dist/clients/module-report.js +100 -80
  51. package/dist/clients/ndjson-logger.js +51 -21
  52. package/dist/clients/path-keyed-map.js +76 -0
  53. package/dist/clients/path-utils.js +35 -0
  54. package/dist/clients/performance-report.js +327 -0
  55. package/dist/clients/pipeline.js +7 -0
  56. package/dist/clients/project-changes.js +77 -4
  57. package/dist/clients/project-diagnostics/extractors.js +26 -115
  58. package/dist/clients/project-diagnostics/fresh-fetch.js +149 -19
  59. package/dist/clients/project-diagnostics/runner-adapters/call-graph-impact.js +109 -0
  60. package/dist/clients/project-diagnostics/runner-adapters/runner-findings.js +37 -5
  61. package/dist/clients/project-diagnostics/scanner.js +247 -127
  62. package/dist/clients/project-lens-config.js +53 -26
  63. package/dist/clients/project-report.js +39 -14
  64. package/dist/clients/project-scale.js +8 -10
  65. package/dist/clients/project-snapshot-persist-worker.js +6 -0
  66. package/dist/clients/project-snapshot.js +611 -7
  67. package/dist/clients/quiet-window.js +9 -1
  68. package/dist/clients/read-expansion.js +22 -12
  69. package/dist/clients/read-guard.js +78 -0
  70. package/dist/clients/redact/secrets.js +449 -0
  71. package/dist/clients/resource-sampler.js +133 -14
  72. package/dist/clients/reverse-deps.js +48 -0
  73. package/dist/clients/review-graph/builder.js +1522 -179
  74. package/dist/clients/review-graph/persist-worker.js +10 -0
  75. package/dist/clients/review-graph/query.js +5 -0
  76. package/dist/clients/review-graph/shared-extraction-ir.js +90 -0
  77. package/dist/clients/review-graph-logger.js +24 -0
  78. package/dist/clients/runtime-agent-end.js +4 -2
  79. package/dist/clients/runtime-coordinator.js +2 -2
  80. package/dist/clients/runtime-session.js +433 -59
  81. package/dist/clients/runtime-tool-call.js +46 -14
  82. package/dist/clients/runtime-turn.js +97 -26
  83. package/dist/clients/safe-spawn.js +102 -15
  84. package/dist/clients/session-start-observability.js +15 -0
  85. package/dist/clients/session-state-store.js +2 -1
  86. package/dist/clients/sessionstart-logger.js +18 -0
  87. package/dist/clients/sg-runner.js +48 -33
  88. package/dist/clients/source-filter.js +49 -25
  89. package/dist/clients/startup-marker.js +6 -0
  90. package/dist/clients/startup-timing.js +9 -0
  91. package/dist/clients/todo-scanner.js +30 -3
  92. package/dist/clients/tree-sitter-cache.js +147 -139
  93. package/dist/clients/tree-sitter-client.js +1340 -67
  94. package/dist/clients/tree-sitter-logger.js +43 -1
  95. package/dist/clients/tree-sitter-query-loader.js +110 -11
  96. package/dist/clients/tree-sitter-shared.js +43 -19
  97. package/dist/clients/tree-sitter-symbol-extractor.js +71 -4
  98. package/dist/clients/widget-state.js +50 -14
  99. package/dist/clients/word-index-logger.js +44 -0
  100. package/dist/clients/word-index.js +252 -35
  101. package/dist/clients/workspace-topology.js +11 -1
  102. package/dist/index.js +45544 -39255
  103. package/dist/mcp/analyze-cli.js +3 -0
  104. package/dist/mcp/cli.js +110 -0
  105. package/dist/mcp/server.js +63 -8
  106. package/dist/tools/lens-diagnostics.js +47 -5
  107. package/dist/tools/lsp-navigation.js +5 -28
  108. package/dist/tools/symbol-search.js +21 -2
  109. package/docs/agent-guide.md +247 -0
  110. package/docs/astplayground.md +3 -4
  111. package/docs/audit1.md +5 -5
  112. package/docs/environment-variables.md +153 -11
  113. package/docs/features.md +4 -3
  114. package/docs/globalconfig.md +56 -4
  115. package/docs/language-coverage.md +2 -2
  116. package/docs/mcp.md +17 -16
  117. package/docs/servercapabilities.md +5 -2
  118. package/docs/settings.md +181 -0
  119. package/docs/tools.md +14 -0
  120. package/docs/tree-sitter_rules_catalog.md +11 -31
  121. package/docs/usage.md +13 -0
  122. package/package.json +139 -138
  123. package/rules/ast-grep-rules/rule-tests/hardcoded-url-js-test.yml +1 -0
  124. package/rules/ast-grep-rules/rule-tests/hardcoded-url-test.yml +2 -0
  125. package/rules/ast-grep-rules/rule-tests/no-case-declarations-js-test.yml +10 -0
  126. package/rules/ast-grep-rules/rule-tests/no-case-declarations-test.yml +10 -0
  127. package/rules/ast-grep-rules/rule-tests/no-javascript-url-js-test.yml +10 -0
  128. package/rules/ast-grep-rules/rule-tests/no-javascript-url-test.yml +10 -0
  129. package/rules/ast-grep-rules/rule-tests/strict-equality-js-test.yml +3 -0
  130. package/rules/ast-grep-rules/rule-tests/strict-equality-test.yml +3 -0
  131. package/rules/ast-grep-rules/rule-tests/strict-inequality-js-test.yml +3 -0
  132. package/rules/ast-grep-rules/rule-tests/strict-inequality-test.yml +4 -0
  133. package/rules/ast-grep-rules/rules/hardcoded-url-js.yml +22 -4
  134. package/rules/ast-grep-rules/rules/hardcoded-url.yml +22 -4
  135. package/rules/ast-grep-rules/rules/no-case-declarations-js.yml +4 -3
  136. package/rules/ast-grep-rules/rules/no-case-declarations.yml +4 -3
  137. package/rules/ast-grep-rules/rules/no-console-except-error-js.yml +10 -0
  138. package/rules/ast-grep-rules/rules/no-console-except-error.yml +10 -0
  139. package/rules/ast-grep-rules/rules/no-javascript-url-js.yml +42 -6
  140. package/rules/ast-grep-rules/rules/no-javascript-url.yml +42 -6
  141. package/rules/ast-grep-rules/rules/strict-equality-js.yml +14 -1
  142. package/rules/ast-grep-rules/rules/strict-equality.yml +14 -1
  143. package/rules/ast-grep-rules/rules/strict-inequality-js.yml +14 -1
  144. package/rules/ast-grep-rules/rules/strict-inequality.yml +14 -1
  145. package/rules/tree-sitter-queries/cpp/no-memset-sensitive-data.yml +9 -3
  146. package/rules/tree-sitter-queries/cpp/no-scoped-lock-without-args.yml +6 -6
  147. package/rules/tree-sitter-queries/css/calc-spacing.yml +8 -6
  148. package/rules/tree-sitter-queries/go/go-mutex-copy.yml +21 -18
  149. package/rules/tree-sitter-queries/go/go-shared-map-write-goroutine.yml +3 -3
  150. package/rules/tree-sitter-queries/java/infinite-loop-java.yml +3 -3
  151. package/rules/tree-sitter-queries/java/junit-call-super.yml +6 -4
  152. package/rules/tree-sitter-queries/java/no-double-checked-locking.yml +10 -8
  153. package/rules/tree-sitter-queries/java/no-field-shadowing.yml +1 -1
  154. package/rules/tree-sitter-queries/java/prepared-statement-valid-indices.yml +2 -3
  155. package/rules/tree-sitter-queries/java/resources-closed.yml +2 -2
  156. package/rules/tree-sitter-queries/java/springboot-default-package.yml +6 -3
  157. package/rules/tree-sitter-queries/java/switch-fall-through.yml +6 -4
  158. package/rules/tree-sitter-queries/java/switch-non-case-labels.yml +4 -3
  159. package/rules/tree-sitter-queries/java/tests-include-assertions.yml +6 -5
  160. package/rules/tree-sitter-queries/javascript/switch-case-termination-js.yml +5 -8
  161. package/rules/tree-sitter-queries/javascript/switch-non-case-labels.yml +3 -2
  162. package/rules/tree-sitter-queries/kotlin/prepared-statement-indices.yml +9 -5
  163. package/rules/tree-sitter-queries/php/this-in-static-context.yml +5 -5
  164. package/rules/tree-sitter-queries/python/exit-signature-check.yml +2 -9
  165. package/rules/tree-sitter-queries/python/in-operator-unsupported.yml +3 -4
  166. package/rules/tree-sitter-queries/python/no-super-torchscript.yml +4 -8
  167. package/rules/tree-sitter-queries/python/notimplemented-boolean-context.yml +1 -5
  168. package/rules/tree-sitter-queries/python/python-empty-except.yml +1 -1
  169. package/rules/tree-sitter-queries/python/return-in-init.yml +0 -2
  170. package/rules/tree-sitter-queries/python/yield-return-outside-function.yml +0 -3
  171. package/rules/tree-sitter-queries/ruby/ruby-command-injection.yml +1 -12
  172. package/rules/tree-sitter-queries/ruby/ruby-eval.yml +1 -1
  173. package/rules/tree-sitter-queries/ruby/ruby-insecure-deserialization.yml +4 -4
  174. package/rules/tree-sitter-queries/ruby/ruby-insecure-random.yml +4 -11
  175. package/rules/tree-sitter-queries/ruby/ruby-open-struct.yml +1 -1
  176. package/rules/tree-sitter-queries/ruby/ruby-string-eval.yml +2 -3
  177. package/rules/tree-sitter-queries/ruby/ruby-weak-hash.yml +4 -4
  178. package/rules/tree-sitter-queries/rust/rust-lock-held-across-await.yml +4 -3
  179. package/rules/tree-sitter-queries/typescript/console-statement.yml +11 -0
  180. package/rules/tree-sitter-queries/typescript/duplicate-function-arg.yml +4 -9
  181. package/rules/tree-sitter-queries/typescript/empty-switch-case.yml +13 -9
  182. package/rules/tree-sitter-queries/typescript/infinite-loop.yml +2 -2
  183. package/rules/tree-sitter-queries/typescript/mixed-async-styles.yml +10 -1
  184. package/rules/tree-sitter-queries/typescript/switch-case-termination.yml +5 -8
  185. package/rules/tree-sitter-queries/typescript/ts-insecure-random.yml +7 -10
  186. package/rules/tree-sitter-queries/typescript/unsafe-regex.yml +4 -2
  187. package/rules/typos/_typos.toml +17 -0
  188. package/skills/pi-lens-write-tree-sitter-rule/SKILL.md +5 -0
  189. package/dist/clients/config-enabled-shape.js +0 -39
  190. package/docs/env_variables.md +0 -10
  191. package/rules/tree-sitter-queries/abap-disabled/delete-where.yml +0 -46
  192. package/rules/tree-sitter-queries/cpp/no-confused-move-forward.yml +0 -59
  193. package/rules/tree-sitter-queries/cpp/noexcept-functions.yml +0 -58
  194. package/rules/tree-sitter-queries/java/mockito-initialized.yml +0 -66
  195. package/rules/tree-sitter-queries/java/no-wait-notify-on-thread.yml +0 -58
  196. package/rules/tree-sitter-queries/java/short-circuit-logic.yml +0 -57
  197. package/rules/tree-sitter-queries/java/spring-session-attributes-setcomplete.yml +0 -75
  198. package/rules/tree-sitter-queries/plsql-disabled/delete-update-where.yml +0 -56
  199. package/rules/tree-sitter-queries/plsql-disabled/end-loop-semicolon.yml +0 -51
  200. package/rules/tree-sitter-queries/plsql-disabled/fetch-bulk-collect-limit.yml +0 -47
  201. package/rules/tree-sitter-queries/plsql-disabled/forallsave-exceptions.yml +0 -51
  202. package/rules/tree-sitter-queries/plsql-disabled/nchar-nvarchar2-bytes.yml +0 -54
  203. package/rules/tree-sitter-queries/plsql-disabled/not-null-initialization.yml +0 -59
  204. package/rules/tree-sitter-queries/plsql-disabled/raise-application-error-codes.yml +0 -50
  205. package/rules/tree-sitter-queries/typescript-disabled/ts-path-traversal.yml +0 -71
package/package.json CHANGED
@@ -1,140 +1,141 @@
1
1
  {
2
- "name": "pi-lens",
3
- "version": "3.8.73",
4
- "type": "module",
5
- "description": "Real-time code feedback for pi — LSP, linters, formatters, type-checking, structural analysis & booboo",
6
- "repository": {
7
- "type": "git",
8
- "url": "git+https://github.com/apmantza/pi-lens.git"
9
- },
10
- "main": "./dist/index.js",
11
- "bin": {
12
- "pi-lens-mcp": "dist/mcp/server.js",
13
- "pi-lens-analyze": "dist/mcp/analyze-cli.js"
14
- },
15
- "scripts": {
16
- "build": "tsc --project tsconfig.build.json",
17
- "build:dist": "node -e \"require('fs').rmSync('dist',{recursive:true,force:true})\" && npx --yes -p typescript@7.0.2 tsc --project tsconfig.dist.json --noCheck && npm run bundle:dist",
18
- "bundle:dist": "node scripts/bundle-dist.mjs",
19
- "prepare": "npm run build:dist && node scripts/download-grammars.js --core --dest grammars",
20
- "lint": "tsc --project tsconfig.json",
21
- "watch": "tsc --watch",
22
- "test": "vitest run",
23
- "test:unit": "vitest run --ignore tests/index-integration.test.ts --ignore tests/clients/lsp/integration.test.ts",
24
- "test:integration": "vitest run tests/index-integration.test.ts tests/clients/lsp/integration.test.ts",
25
- "test:watch": "vitest",
26
- "check": "node scripts/check-extensions.mjs",
27
- "selftest:install": "node scripts/install-selftest.mjs",
28
- "check:lockfile": "node scripts/check-lockfile-sync.mjs",
29
- "check:grammars": "node scripts/check-grammar-provenance.mjs",
30
- "check:grammar-load": "node scripts/check-grammar-load.mjs",
31
- "audit:tree-sitter": "node scripts/audit-tree-sitter-rules.mjs",
32
- "audit:rule-catalog": "node scripts/validate-rule-catalog.mjs",
33
- "audit:astgrep-rule-pairs": "node scripts/audit-astgrep-rule-pairs.mjs",
34
- "audit:playground": "node scripts/playground-verify-rule.mjs",
35
- "logs:smells": "node scripts/analyze-pi-lens-logs.mjs",
36
- "changelog:check": "node scripts/changelog-release.mjs --check",
37
- "changelog:release": "node scripts/changelog-release.mjs",
38
- "changelog:extract": "node scripts/changelog-extract.mjs",
39
- "release:backfill-notes": "node scripts/backfill-github-releases.mjs",
40
- "release:backfill-thanks": "node scripts/backfill-release-thanks.mjs",
41
- "docs:rule-catalogs": "node scripts/gen-rule-catalogs.mjs",
42
- "banner": "npx -y sharp-cli --input banner.svg --output banner.png resize 2200 620",
43
- "download-grammars": "node scripts/download-grammars.js",
44
- "harness:poc": "node scripts/run-harness.mjs cases/ts/pipeline-dispatch-poc --pi-bin \"C:\\Users\\R3LiC\\AppData\\Roaming\\npm\\pi.cmd\"",
45
- "harness:python-poc": "node scripts/run-harness.mjs cases/python/pipeline-dispatch-poc --pi-bin \"C:\\Users\\R3LiC\\AppData\\Roaming\\npm\\pi.cmd\"",
46
- "harness:ts-format-poc": "node scripts/run-harness.mjs cases/ts/format-default-poc --pi-bin \"C:\\Users\\R3LiC\\AppData\\Roaming\\npm\\pi.cmd\"",
47
- "harness:python-autofix-poc": "node scripts/run-harness.mjs cases/python/autofix-default-poc --pi-bin \"C:\\Users\\R3LiC\\AppData\\Roaming\\npm\\pi.cmd\"",
48
- "harness:go-poc": "node scripts/run-harness.mjs cases/go/pipeline-dispatch-poc --pi-bin \"C:\\Users\\R3LiC\\AppData\\Roaming\\npm\\pi.cmd\""
49
- },
50
- "keywords": [
51
- "pi",
52
- "pi-extension",
53
- "pi-package",
54
- "linter",
55
- "biome",
56
- "ast-grep",
57
- "ruff",
58
- "typescript",
59
- "code-quality",
60
- "feedback",
61
- "type-coverage",
62
- "jscpd",
63
- "knip"
64
- ],
65
- "author": "Apostolos Mantzaris",
66
- "license": "MIT",
67
- "files": [
68
- "dist/",
69
- "docs/",
70
- "grammars/",
71
- "config/",
72
- "rules/",
73
- "skills/",
74
- "scripts/download-grammars.js",
75
- "scripts/grammars.lock.json",
76
- "scripts/analyze-pi-lens-logs.mjs",
77
- "scripts/install-selftest.mjs",
78
- "scripts/rpc-load-check.mjs",
79
- "README.md",
80
- "CHANGELOG.md",
81
- "banner.svg",
82
- "banner.png"
83
- ],
84
- "dependencies": {
85
- "@ast-grep/cli": "^0.45.0",
86
- "@ast-grep/napi": "^0.45.0",
87
- "@earendil-works/pi-tui": "^0.82.1",
88
- "js-yaml": "^5.2.2",
89
- "minimatch": "^10.2.5",
90
- "pidusage": "^4.0.1",
91
- "typebox": "^1.0.0",
92
- "vscode-jsonrpc": "^9.0.0"
93
- },
94
- "peerDependencies": {
95
- "@earendil-works/pi-coding-agent": "*"
96
- },
97
- "peerDependenciesMeta": {
98
- "@earendil-works/pi-coding-agent": {
99
- "optional": true
100
- }
101
- },
102
- "optionalDependencies": {
103
- "web-tree-sitter": "0.25.10"
104
- },
105
- "devDependencies": {
106
- "@biomejs/biome": "^2.4.10",
107
- "@earendil-works/pi-coding-agent": "^0.82.1",
108
- "@types/node": "^26.0.0",
109
- "@types/pidusage": "^2.0.5",
110
- "@vitest/coverage-v8": "^4.1.5",
111
- "typescript": "^7.0.2",
112
- "typescript-language-server": "^5.1.3",
113
- "vitest": "^4.1.1"
114
- },
115
- "pi": {
116
- "extensions": [
117
- "./dist/index.js"
118
- ],
119
- "skills": [
120
- "../../skills"
121
- ]
122
- },
123
- "knip": {
124
- "entry": [
125
- "index.ts"
126
- ],
127
- "project": [
128
- "**/*.ts",
129
- "!**/*.test.ts"
130
- ],
131
- "ignore": [
132
- "**/*.test.ts"
133
- ]
134
- },
135
- "allowScripts": {
136
- "@ast-grep/cli@0.44.1": true,
137
- "@google/genai@1.52.0": true,
138
- "protobufjs@7.6.4": true
139
- }
2
+ "name": "pi-lens",
3
+ "version": "3.8.74",
4
+ "type": "module",
5
+ "description": "Real-time code feedback for pi — LSP, linters, formatters, type-checking, structural analysis & booboo",
6
+ "repository": {
7
+ "type": "git",
8
+ "url": "git+https://github.com/apmantza/pi-lens.git"
9
+ },
10
+ "main": "./dist/index.js",
11
+ "bin": {
12
+ "pi-lens": "dist/mcp/cli.js",
13
+ "pi-lens-mcp": "dist/mcp/server.js",
14
+ "pi-lens-analyze": "dist/mcp/analyze-cli.js"
15
+ },
16
+ "scripts": {
17
+ "build": "tsc --project tsconfig.build.json",
18
+ "build:dist": "node -e \"require('fs').rmSync('dist',{recursive:true,force:true})\" && npx --yes -p typescript@7.0.2 tsc --project tsconfig.dist.json --noCheck && npm run bundle:dist",
19
+ "bundle:dist": "node scripts/bundle-dist.mjs",
20
+ "prepare": "npm run build:dist && node scripts/download-grammars.js --core --dest grammars",
21
+ "lint": "tsc --project tsconfig.json",
22
+ "watch": "tsc --watch",
23
+ "test": "vitest run",
24
+ "test:unit": "vitest run --ignore tests/index-integration.test.ts --ignore tests/clients/lsp/integration.test.ts",
25
+ "test:integration": "vitest run tests/index-integration.test.ts tests/clients/lsp/integration.test.ts",
26
+ "test:watch": "vitest",
27
+ "check": "node scripts/check-extensions.mjs",
28
+ "selftest:install": "node scripts/install-selftest.mjs",
29
+ "check:lockfile": "node scripts/check-lockfile-sync.mjs",
30
+ "check:grammars": "node scripts/check-grammar-provenance.mjs",
31
+ "check:grammar-load": "node scripts/check-grammar-load.mjs",
32
+ "audit:tree-sitter": "node scripts/audit-tree-sitter-rules.mjs",
33
+ "audit:rule-catalog": "node scripts/validate-rule-catalog.mjs",
34
+ "audit:astgrep-rule-pairs": "node scripts/audit-astgrep-rule-pairs.mjs",
35
+ "audit:playground": "node scripts/playground-verify-rule.mjs",
36
+ "logs:smells": "node scripts/analyze-pi-lens-logs.mjs",
37
+ "changelog:check": "node scripts/changelog-release.mjs --check",
38
+ "changelog:release": "node scripts/changelog-release.mjs",
39
+ "changelog:extract": "node scripts/changelog-extract.mjs",
40
+ "release:backfill-notes": "node scripts/backfill-github-releases.mjs",
41
+ "release:backfill-thanks": "node scripts/backfill-release-thanks.mjs",
42
+ "docs:rule-catalogs": "node scripts/gen-rule-catalogs.mjs",
43
+ "banner": "npx -y sharp-cli --input banner.svg --output banner.png resize 2200 620",
44
+ "download-grammars": "node scripts/download-grammars.js",
45
+ "harness:poc": "node scripts/run-harness.mjs cases/ts/pipeline-dispatch-poc --pi-bin \"C:\\Users\\R3LiC\\AppData\\Roaming\\npm\\pi.cmd\"",
46
+ "harness:python-poc": "node scripts/run-harness.mjs cases/python/pipeline-dispatch-poc --pi-bin \"C:\\Users\\R3LiC\\AppData\\Roaming\\npm\\pi.cmd\"",
47
+ "harness:ts-format-poc": "node scripts/run-harness.mjs cases/ts/format-default-poc --pi-bin \"C:\\Users\\R3LiC\\AppData\\Roaming\\npm\\pi.cmd\"",
48
+ "harness:python-autofix-poc": "node scripts/run-harness.mjs cases/python/autofix-default-poc --pi-bin \"C:\\Users\\R3LiC\\AppData\\Roaming\\npm\\pi.cmd\"",
49
+ "harness:go-poc": "node scripts/run-harness.mjs cases/go/pipeline-dispatch-poc --pi-bin \"C:\\Users\\R3LiC\\AppData\\Roaming\\npm\\pi.cmd\""
50
+ },
51
+ "keywords": [
52
+ "pi",
53
+ "pi-extension",
54
+ "pi-package",
55
+ "linter",
56
+ "biome",
57
+ "ast-grep",
58
+ "ruff",
59
+ "typescript",
60
+ "code-quality",
61
+ "feedback",
62
+ "type-coverage",
63
+ "jscpd",
64
+ "knip"
65
+ ],
66
+ "author": "Apostolos Mantzaris",
67
+ "license": "MIT",
68
+ "files": [
69
+ "dist/",
70
+ "docs/",
71
+ "grammars/",
72
+ "config/",
73
+ "rules/",
74
+ "skills/",
75
+ "scripts/download-grammars.js",
76
+ "scripts/grammars.lock.json",
77
+ "scripts/analyze-pi-lens-logs.mjs",
78
+ "scripts/install-selftest.mjs",
79
+ "scripts/rpc-load-check.mjs",
80
+ "README.md",
81
+ "CHANGELOG.md",
82
+ "banner.svg",
83
+ "banner.png"
84
+ ],
85
+ "dependencies": {
86
+ "@ast-grep/cli": "^0.45.0",
87
+ "@ast-grep/napi": "^0.45.0",
88
+ "@earendil-works/pi-tui": "^0.82.1",
89
+ "js-yaml": "^5.2.2",
90
+ "minimatch": "^10.2.5",
91
+ "pidusage": "^4.0.1",
92
+ "typebox": "^1.0.0",
93
+ "vscode-jsonrpc": "^9.0.0"
94
+ },
95
+ "peerDependencies": {
96
+ "@earendil-works/pi-coding-agent": "*"
97
+ },
98
+ "peerDependenciesMeta": {
99
+ "@earendil-works/pi-coding-agent": {
100
+ "optional": true
101
+ }
102
+ },
103
+ "optionalDependencies": {
104
+ "web-tree-sitter": "0.25.10"
105
+ },
106
+ "devDependencies": {
107
+ "@biomejs/biome": "^2.4.10",
108
+ "@earendil-works/pi-coding-agent": "^0.82.1",
109
+ "@types/node": "^26.0.0",
110
+ "@types/pidusage": "^2.0.5",
111
+ "@vitest/coverage-v8": "^4.1.5",
112
+ "typescript": "^7.0.2",
113
+ "typescript-language-server": "^5.1.3",
114
+ "vitest": "^4.1.1"
115
+ },
116
+ "pi": {
117
+ "extensions": [
118
+ "./dist/index.js"
119
+ ],
120
+ "skills": [
121
+ "../../skills"
122
+ ]
123
+ },
124
+ "knip": {
125
+ "entry": [
126
+ "index.ts"
127
+ ],
128
+ "project": [
129
+ "**/*.ts",
130
+ "!**/*.test.ts"
131
+ ],
132
+ "ignore": [
133
+ "**/*.test.ts"
134
+ ]
135
+ },
136
+ "allowScripts": {
137
+ "@ast-grep/cli@0.44.1": true,
138
+ "@google/genai@1.52.0": true,
139
+ "protobufjs@7.6.4": true
140
+ }
140
141
  }
@@ -2,6 +2,7 @@ id: hardcoded-url-js
2
2
  valid:
3
3
  - 'const url = process.env.API_URL'
4
4
  - 'const x = "hello"'
5
+ - 'export const BASE_URL_CLINE = "https://api.cline.bot";'
5
6
  invalid:
6
7
  - 'const url = "https://api.example.com"'
7
8
  - 'const endpoint = "http://localhost:3000"'
@@ -2,6 +2,8 @@ id: hardcoded-url
2
2
  valid:
3
3
  - 'const url = process.env.API_URL'
4
4
  - 'const x = "hello"'
5
+ - 'export const BASE_URL_CLINE = "https://api.cline.bot";'
6
+ - 'export const URL_KILO_TOS = "https://kilo.dev/tos";'
5
7
  invalid:
6
8
  - 'const url = "https://api.example.com"'
7
9
  - 'const endpoint = "http://localhost:3000"'
@@ -7,6 +7,16 @@ valid:
7
7
  break;
8
8
  }
9
9
  }
10
+ - |
11
+ switch (x) {
12
+ case 1: {
13
+ if (x) {
14
+ const y = 1;
15
+ consume(y);
16
+ }
17
+ break;
18
+ }
19
+ }
10
20
  - |
11
21
  var z = 1; switch (x) { case 1: break; }
12
22
  invalid:
@@ -7,6 +7,16 @@ valid:
7
7
  break;
8
8
  }
9
9
  }
10
+ - |
11
+ switch (x) {
12
+ case 1: {
13
+ if (x) {
14
+ const y = 1;
15
+ consume(y);
16
+ }
17
+ break;
18
+ }
19
+ }
10
20
  - |
11
21
  var z = 1; switch (x) { case 1: break; }
12
22
  invalid:
@@ -8,7 +8,17 @@ valid:
8
8
  it("rejects javascript: urls", () => {
9
9
  expect(openBrowser("javascript:alert(1)")).toBe(false);
10
10
  });
11
+ - 'const links = arr.filter((l) => !l.startsWith("javascript:"))'
12
+ - 'if (url.includes("javascript:")) return null;'
13
+ - 'const isBlocked = url === "javascript:alert(1)"'
14
+ - 'const safe = url !== "javascript:alert(1)"'
15
+ - 'url?.startsWith("javascript:")'
11
16
  invalid:
12
17
  - 'a.href = "javascript:alert(1)"'
13
18
  - 'a.href = "javascript:void(0)"'
14
19
  - 'const u = "javascript:alert(1)"'
20
+ - 'a.href = str.replace("http:", "javascript:alert(1)")'
21
+ - 'if (candidates.includes(link.href = "javascript:alert(1)")) { doThing(); }'
22
+ - 'someArray.includes((a.href = "javascript:alert(1)", true));'
23
+ - 'if ((a.href = "javascript:alert(1)") === expected) { doThing(); }'
24
+ - 'const ok = (typeof (a.href = "javascript:alert(1)")) === "string";'
@@ -12,7 +12,17 @@ valid:
12
12
  test.each(["javascript:alert(1)"])("rejects %s", (url) => {
13
13
  expect(openBrowser(url)).toBe(false);
14
14
  });
15
+ - 'const links = arr.filter((l) => !l.startsWith("javascript:"))'
16
+ - 'if (url.includes("javascript:")) return null;'
17
+ - 'const isBlocked = url === "javascript:alert(1)"'
18
+ - 'const safe = url !== "javascript:alert(1)"'
19
+ - 'url?.startsWith("javascript:")'
15
20
  invalid:
16
21
  - 'a.href = "javascript:alert(1)"'
17
22
  - 'a.href = "javascript:void(0)"'
18
23
  - 'const u = "javascript:alert(1)"'
24
+ - 'a.href = str.replace("http:", "javascript:alert(1)")'
25
+ - 'if (candidates.includes(link.href = "javascript:alert(1)")) { doThing(); }'
26
+ - 'someArray.includes((a.href = "javascript:alert(1)", true));'
27
+ - 'if ((a.href = "javascript:alert(1)") === expected) { doThing(); }'
28
+ - 'const ok = (typeof (a.href = "javascript:alert(1)")) === "string";'
@@ -3,6 +3,9 @@ valid:
3
3
  - 'a === b'
4
4
  - 'a !== b'
5
5
  - 'a = b'
6
+ - 'value == null'
7
+ - 'null == value'
8
+ - 'value == undefined'
6
9
  invalid:
7
10
  - 'a == b'
8
11
  - 'a == "x"'
@@ -3,6 +3,9 @@ valid:
3
3
  - 'a === b'
4
4
  - 'a !== b'
5
5
  - 'a = b'
6
+ - 'value == null'
7
+ - 'null == value'
8
+ - 'value == undefined'
6
9
  invalid:
7
10
  - 'a == b'
8
11
  - 'a == "x"'
@@ -3,6 +3,9 @@ valid:
3
3
  - 'a !== b'
4
4
  - 'a === b'
5
5
  - 'a < b'
6
+ - 'value != null'
7
+ - 'null != value'
8
+ - 'value != undefined'
6
9
  invalid:
7
10
  - 'a != b'
8
11
  - 'a != "x"'
@@ -3,6 +3,10 @@ valid:
3
3
  - 'a !== b'
4
4
  - 'a === b'
5
5
  - 'a < b'
6
+ - 'value != null'
7
+ - 'null != value'
8
+ - 'thinkingMap != null'
9
+ - 'value != undefined'
6
10
  invalid:
7
11
  - 'a != b'
8
12
  - 'a != "x"'
@@ -9,9 +9,27 @@ note: |
9
9
  level for some shapes; using a regex on `variable_declarator` (the
10
10
  inner `name = value` node) catches all const/let/var URL assignments
11
11
  regardless of the surrounding keyword.
12
+ A `SCREAMING_SNAKE_CASE` name is the project-wide convention for a
13
+ deliberate, named constant (see e.g. `check_secret_pattern` in
14
+ tree-sitter-client.ts, which trusts the same convention for secrets).
15
+ Provider/integration endpoint constants (`BASE_URL_CLINE`, `URL_KILO_TOS`,
16
+ …) are declared this way on purpose — they are configuration, just
17
+ expressed as a JS constant instead of an env var — so exempting that
18
+ naming shape removes the low-signal noise while still catching a URL
19
+ hardcoded under an ordinary lower/camelCase name (#964).
12
20
  rule:
13
21
  any:
14
- - kind: variable_declarator
15
- regex: '"https?://'
16
- - kind: assignment_expression
17
- regex: '"https?://'
22
+ - all:
23
+ - kind: variable_declarator
24
+ regex: '"https?://'
25
+ - not:
26
+ has:
27
+ field: name
28
+ regex: "^[A-Z][A-Z0-9_]*$"
29
+ - all:
30
+ - kind: assignment_expression
31
+ regex: '"https?://'
32
+ - not:
33
+ has:
34
+ field: left
35
+ regex: "^[A-Z][A-Z0-9_]*$"
@@ -9,9 +9,27 @@ note: |
9
9
  level for some shapes; using a regex on `variable_declarator` (the
10
10
  inner `name = value` node) catches all const/let/var URL assignments
11
11
  regardless of the surrounding keyword.
12
+ A `SCREAMING_SNAKE_CASE` name is the project-wide convention for a
13
+ deliberate, named constant (see e.g. `check_secret_pattern` in
14
+ tree-sitter-client.ts, which trusts the same convention for secrets).
15
+ Provider/integration endpoint constants (`BASE_URL_CLINE`, `URL_KILO_TOS`,
16
+ …) are declared this way on purpose — they are configuration, just
17
+ expressed as a TS constant instead of an env var — so exempting that
18
+ naming shape removes the low-signal noise while still catching a URL
19
+ hardcoded under an ordinary lower/camelCase name (#964).
12
20
  rule:
13
21
  any:
14
- - kind: variable_declarator
15
- regex: '"https?://'
16
- - kind: assignment_expression
17
- regex: '"https?://'
22
+ - all:
23
+ - kind: variable_declarator
24
+ regex: '"https?://'
25
+ - not:
26
+ has:
27
+ field: name
28
+ regex: "^[A-Z][A-Z0-9_]*$"
29
+ - all:
30
+ - kind: assignment_expression
31
+ regex: '"https?://'
32
+ - not:
33
+ has:
34
+ field: left
35
+ regex: "^[A-Z][A-Z0-9_]*$"
@@ -1,6 +1,8 @@
1
1
  id: no-case-declarations-js
2
2
  language: JavaScript
3
- message: "Unexpected lexical declaration in case block — wrap in braces to restrict scope"
3
+ message: >-
4
+ Unexpected lexical declaration in case block — wrap in braces to restrict
5
+ scope
4
6
  severity: error
5
7
  note: |
6
8
  Variables declared with let/const in a case clause are accessible to the
@@ -17,5 +19,4 @@ rule:
17
19
  - not:
18
20
  inside:
19
21
  kind: statement_block
20
- inside:
21
- kind: switch_case
22
+ stopBy: end
@@ -1,6 +1,8 @@
1
1
  id: no-case-declarations
2
2
  language: TypeScript
3
- message: "Unexpected lexical declaration in case block — wrap in braces to restrict scope"
3
+ message: >-
4
+ Unexpected lexical declaration in case block — wrap in braces to restrict
5
+ scope
4
6
  severity: error
5
7
  note: |
6
8
  Variables declared with let/const in a case clause are accessible to the
@@ -17,5 +19,4 @@ rule:
17
19
  - not:
18
20
  inside:
19
21
  kind: statement_block
20
- inside:
21
- kind: switch_case
22
+ stopBy: end
@@ -6,6 +6,16 @@ note: |
6
6
  console.log/debug/warn usually indicate leftover debug output shipped to
7
7
  production. Allow console.error ONLY inside catch blocks (logging the
8
8
  error there is useful for production triage).
9
+ Console output IS the point in a CLI script's own stdout contract and in
10
+ a logging implementation's console fallback/sink — flagging it there
11
+ just trains users to ignore the rule; `ignores` below carves those paths
12
+ out while application/library code elsewhere still gets flagged (#965).
13
+ ignores:
14
+ - "scripts/**"
15
+ - "bin/**"
16
+ - "**/logger.ts"
17
+ - "**/logger.js"
18
+ - "**/logger.mjs"
9
19
  rule:
10
20
  any:
11
21
  - pattern: console.error($$$)
@@ -6,6 +6,16 @@ note: |
6
6
  console.log/debug/warn usually indicate leftover debug output shipped to
7
7
  production. Allow console.error ONLY inside catch blocks (logging the
8
8
  error there is useful for production triage).
9
+ Console output IS the point in a CLI script's own stdout contract and in
10
+ a logging implementation's console fallback/sink — flagging it there
11
+ just trains users to ignore the rule; `ignores` below carves those paths
12
+ out while application/library code elsewhere still gets flagged (#965).
13
+ ignores:
14
+ - "scripts/**"
15
+ - "bin/**"
16
+ - "**/logger.ts"
17
+ - "**/logger.js"
18
+ - "**/logger.mjs"
9
19
  rule:
10
20
  any:
11
21
  - pattern: console.error($$$)
@@ -15,13 +15,49 @@ note: |
15
15
  `.only`/`.skip`/`.each` variants): a test asserting that a guard REJECTS a
16
16
  `javascript:` URL — e.g. `expect(openBrowser("javascript:...")).toBe(false)`
17
17
  — is the adversarial input the code is meant to reject, not a real sink.
18
+
19
+ Also excludes literals used as the needle in a defensive string check —
20
+ `url.startsWith("javascript:")`, `.endsWith(...)`, `.includes(...)`,
21
+ `.indexOf(...)`, `.search(...)`, `.match(...)` — or as one side of an
22
+ equality/inequality comparison (`url === "javascript:..."`). These are the
23
+ code detecting/rejecting a javascript: URL, not introducing one (refs
24
+ #533). Deliberately NOT excluded: `.replace(...)`/`.replaceAll(...)`,
25
+ since the literal there could be the replacement (second) argument —
26
+ i.e. the malicious payload being substituted IN — and excluding the
27
+ whole call would hide that true positive.
28
+
29
+ IMPORTANT: unlike the expect/it/test/describe exclusion above, these two
30
+ new exclusions deliberately do NOT use `stopBy: end`. `inside` without
31
+ `stopBy` only checks the immediate parent, so the literal must be a
32
+ DIRECT argument/operand of the defensive call/comparison — not merely
33
+ somewhere in its subtree. Without this constraint, a real sink smuggled
34
+ inside the call/comparison would go unflagged, e.g.
35
+ `candidates.includes(link.href = "javascript:alert(1)")` (assignment
36
+ nested in `.includes()`'s argument), `arr.includes((a.href =
37
+ "javascript:...", true))` (comma operator), or `(a.href =
38
+ "javascript:...") === expected` (assignment nested in a `===` operand) —
39
+ in all three the literal's immediate parent is the assignment
40
+ expression, not the `arguments`/`binary_expression` node, so it stays
41
+ flagged.
18
42
  rule:
19
43
  kind: string
20
44
  regex: '^"javascript:'
21
45
  not:
22
- inside:
23
- stopBy: end
24
- kind: call_expression
25
- has:
26
- field: function
27
- regex: "^(expect|it|test|describe)(\\.\\w+)?$"
46
+ any:
47
+ - inside:
48
+ stopBy: end
49
+ kind: call_expression
50
+ has:
51
+ field: function
52
+ regex: "^(expect|it|test|describe)(\\.\\w+)?$"
53
+ - inside:
54
+ kind: arguments
55
+ inside:
56
+ kind: call_expression
57
+ has:
58
+ field: function
59
+ regex: "\\.(startsWith|endsWith|includes|indexOf|search|match)$"
60
+ - inside:
61
+ kind: binary_expression
62
+ has:
63
+ regex: "^(===|!==|==|!=)$"