@herbertgao/pi-extensions 2026.8.13 → 2026.8.15
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 +19 -14
- package/THIRD_PARTY_NOTICES.md +0 -1
- package/node_modules/@czottmann/pi-automode/CHANGELOG.md +19 -0
- package/node_modules/@czottmann/pi-automode/README.md +5 -1
- package/node_modules/@czottmann/pi-automode/extensions/auto-mode/classifier.ts +126 -13
- package/node_modules/@czottmann/pi-automode/extensions/auto-mode/config.ts +7 -3
- package/node_modules/@czottmann/pi-automode/extensions/auto-mode/constants.ts +2 -0
- package/node_modules/@czottmann/pi-automode/extensions/auto-mode/hard-deny.ts +134 -23
- package/node_modules/@czottmann/pi-automode/package.json +1 -1
- package/node_modules/@herbertgao/{pi-stash → pi-bark}/LICENSE +4 -5
- package/node_modules/@herbertgao/pi-bark/README.md +44 -0
- package/node_modules/@herbertgao/pi-bark/assets/pi-icon.png +0 -0
- package/node_modules/@herbertgao/pi-bark/package.json +53 -0
- package/node_modules/@herbertgao/pi-bark/src/index.ts +178 -0
- package/node_modules/@herbertgao/pi-cc-extensions/README.en.md +1 -1
- package/node_modules/@herbertgao/pi-cc-extensions/README.md +1 -1
- package/node_modules/@herbertgao/pi-cc-extensions/package.json +3 -3
- package/node_modules/@herbertgao/pi-subagents/CHANGELOG.md +6 -0
- package/node_modules/@herbertgao/pi-subagents/package.json +2 -1
- package/node_modules/@herbertgao/pi-subagents/src/ui/conversation-viewer.ts +8 -1
- package/node_modules/@juicesharp/rpiv-ask-user-question/package.json +2 -2
- package/node_modules/@narumitw/pi-btw/README.md +125 -88
- package/node_modules/@narumitw/pi-btw/dist/index.ts +140 -45
- package/node_modules/@narumitw/pi-btw/dist/index.ts.map +2 -2
- package/node_modules/@narumitw/pi-btw/package.json +5 -8
- package/node_modules/@narumitw/pi-btw/src/btw.ts +31 -26
- package/node_modules/@narumitw/pi-btw/src/fullscreen-ui.ts +106 -17
- package/node_modules/@narumitw/pi-btw/src/menu.ts +34 -2
- package/node_modules/@narumitw/pi-btw/src/settings.ts +16 -0
- package/node_modules/@tifan/pi-handoff/README.md +36 -13
- package/node_modules/@tifan/pi-handoff/package.json +2 -2
- package/node_modules/@tifan/pi-handoff/src/index.ts +160 -4
- package/node_modules/@tifan/pi-preferred-thinking/README.md +1 -1
- package/node_modules/@tifan/pi-preferred-thinking/package.json +1 -1
- package/node_modules/@tifan/pi-preferred-thinking/src/index.ts +15 -2
- package/node_modules/@tifan/pi-recap/README.md +1 -1
- package/node_modules/@tifan/pi-recap/package.json +2 -2
- package/node_modules/@tifan/pi-recap/src/index.ts +15 -0
- package/node_modules/@tifan/pi-rename/README.md +42 -21
- package/node_modules/@tifan/pi-rename/package.json +1 -1
- package/node_modules/@tifan/pi-rename/src/index.ts +62 -11
- package/node_modules/@tifan/pi-rename/src/language.ts +18 -0
- package/node_modules/@tifan/pi-rename/src/models.ts +69 -13
- package/node_modules/@tifan/pi-rename/src/naming.ts +36 -7
- package/node_modules/@tifan/pi-rename/src/sanitize.ts +22 -14
- package/node_modules/pi-lens/CHANGELOG.md +320 -0
- package/node_modules/pi-lens/config/dependency-cruiser-eager-allowlist.json +79 -0
- package/node_modules/pi-lens/dist/clients/actionable-warnings-logger.js +16 -1
- package/node_modules/pi-lens/dist/clients/ast-grep-client.js +13 -6
- package/node_modules/pi-lens/dist/clients/availability-probe-flight.js +12 -0
- package/node_modules/pi-lens/dist/clients/biome-client.js +7 -0
- package/node_modules/pi-lens/dist/clients/blocker-freshness.js +20 -0
- package/node_modules/pi-lens/dist/clients/bounded-telemetry.js +56 -19
- package/node_modules/pi-lens/dist/clients/build-identity.js +95 -0
- package/node_modules/pi-lens/dist/clients/bus-publish.js +3 -0
- package/node_modules/pi-lens/dist/clients/cache/rule-cache.js +2 -1
- package/node_modules/pi-lens/dist/clients/cache-observability.js +2 -1
- package/node_modules/pi-lens/dist/clients/cascade-logger.js +15 -1
- package/node_modules/pi-lens/dist/clients/dead-code-client.js +14 -11
- package/node_modules/pi-lens/dist/clients/degradation-ledger.js +56 -4
- package/node_modules/pi-lens/dist/clients/demoted-finding-render.js +14 -0
- package/node_modules/pi-lens/dist/clients/dependency-checker.js +20 -3
- package/node_modules/pi-lens/dist/clients/deps/minimatch.js +1 -1
- package/node_modules/pi-lens/dist/clients/dispatch/collect-later-tier.js +39 -0
- package/node_modules/pi-lens/dist/clients/dispatch/dispatcher.js +150 -9
- package/node_modules/pi-lens/dist/clients/dispatch/fact-store.js +231 -9
- package/node_modules/pi-lens/dist/clients/dispatch/integration.js +205 -100
- package/node_modules/pi-lens/dist/clients/dispatch/pending-runner-findings.js +87 -0
- package/node_modules/pi-lens/dist/clients/dispatch/plan.js +21 -5
- package/node_modules/pi-lens/dist/clients/dispatch/runners/ast-grep-napi.js +174 -55
- package/node_modules/pi-lens/dist/clients/dispatch/runners/eslint.js +5 -1
- package/node_modules/pi-lens/dist/clients/dispatch/runners/helm-lint.js +16 -3
- package/node_modules/pi-lens/dist/clients/dispatch/runners/helm-render.js +54 -9
- package/node_modules/pi-lens/dist/clients/dispatch/runners/index.js +1 -3
- package/node_modules/pi-lens/dist/clients/dispatch/runners/lsp.js +37 -1
- package/node_modules/pi-lens/dist/clients/dispatch/runners/markdownlint.js +4 -1
- package/node_modules/pi-lens/dist/clients/dispatch/runners/oxlint.js +11 -4
- package/node_modules/pi-lens/dist/clients/dispatch/runners/psscriptanalyzer.js +4 -0
- package/node_modules/pi-lens/dist/clients/dispatch/runners/rust-clippy.js +8 -3
- package/node_modules/pi-lens/dist/clients/dispatch/runners/utils/runner-helpers.js +76 -25
- package/node_modules/pi-lens/dist/clients/dispatch/runners/utils/spawn-outcome.js +4 -0
- package/node_modules/pi-lens/dist/clients/dispatch/runners/utils/tool-failure.js +19 -7
- package/node_modules/pi-lens/dist/clients/dispatch/runners/utils/toolchain-availability.js +7 -13
- package/node_modules/pi-lens/dist/clients/dispatch/runners/yaml-rule-parser.js +51 -17
- package/node_modules/pi-lens/dist/clients/event-loop-monitor.js +66 -1
- package/node_modules/pi-lens/dist/clients/file-utils.js +157 -7
- package/node_modules/pi-lens/dist/clients/finding-delivery-gate.js +5 -0
- package/node_modules/pi-lens/dist/clients/formatters.js +28 -3
- package/node_modules/pi-lens/dist/clients/git-guard.js +197 -47
- package/node_modules/pi-lens/dist/clients/git-tracked-ignore.js +32 -1
- package/node_modules/pi-lens/dist/clients/govulncheck-client.js +5 -1
- package/node_modules/pi-lens/dist/clients/gzip-stage-write.js +7 -0
- package/node_modules/pi-lens/dist/clients/installer/index.js +131 -34
- package/node_modules/pi-lens/dist/clients/installer/managed-tool-refresh.js +3 -1
- package/node_modules/pi-lens/dist/clients/instance-reaper.js +4 -13
- package/node_modules/pi-lens/dist/clients/instance-registry-lock.js +145 -0
- package/node_modules/pi-lens/dist/clients/instance-registry.js +432 -122
- package/node_modules/pi-lens/dist/clients/jscpd-client.js +6 -1
- package/node_modules/pi-lens/dist/clients/language-profile.js +4 -2
- package/node_modules/pi-lens/dist/clients/latency-logger.js +19 -1
- package/node_modules/pi-lens/dist/clients/lens-flag-registry.js +8 -0
- package/node_modules/pi-lens/dist/clients/lens-map.js +3 -1
- package/node_modules/pi-lens/dist/clients/lsp/cascade-tier.js +4 -0
- package/node_modules/pi-lens/dist/clients/lsp/client.js +516 -31
- package/node_modules/pi-lens/dist/clients/lsp/config.js +25 -2
- package/node_modules/pi-lens/dist/clients/lsp/diagnostic-binding.js +9 -4
- package/node_modules/pi-lens/dist/clients/lsp/index.js +509 -182
- package/node_modules/pi-lens/dist/clients/lsp/jvm-runtime.js +5 -0
- package/node_modules/pi-lens/dist/clients/lsp/launch.js +36 -8
- package/node_modules/pi-lens/dist/clients/lsp/pending-aux-coverage.js +116 -4
- package/node_modules/pi-lens/dist/clients/lsp/server.js +142 -13
- package/node_modules/pi-lens/dist/clients/lsp/session-roots.js +99 -0
- package/node_modules/pi-lens/dist/clients/lsp/workspace-diagnostics-cache.js +16 -6
- package/node_modules/pi-lens/dist/clients/lsp/workspace-sweep-hold.js +32 -23
- package/node_modules/pi-lens/dist/clients/lsp-mutation.js +16 -2
- package/node_modules/pi-lens/dist/clients/mcp/analyze.js +12 -6
- package/node_modules/pi-lens/dist/clients/mcp/session.js +14 -1
- package/node_modules/pi-lens/dist/clients/memory-sampler.js +23 -1
- package/node_modules/pi-lens/dist/clients/message-end-attribution.js +30 -0
- package/node_modules/pi-lens/dist/clients/metrics-history.js +21 -4
- package/node_modules/pi-lens/dist/clients/opaque-mutation-scan.js +232 -18
- package/node_modules/pi-lens/dist/clients/package-manager.js +6 -18
- package/node_modules/pi-lens/dist/clients/path-keyed-map.js +14 -1
- package/node_modules/pi-lens/dist/clients/path-utils.js +32 -0
- package/node_modules/pi-lens/dist/clients/pipeline.js +0 -8
- package/node_modules/pi-lens/dist/clients/process-singletons.js +210 -0
- package/node_modules/pi-lens/dist/clients/project-diagnostics/runner-adapters/madge.js +2 -1
- package/node_modules/pi-lens/dist/clients/project-diagnostics/scanner.js +10 -4
- package/node_modules/pi-lens/dist/clients/project-snapshot.js +33 -11
- package/node_modules/pi-lens/dist/clients/read-guard-logger.js +24 -2
- package/node_modules/pi-lens/dist/clients/read-guard.js +74 -7
- package/node_modules/pi-lens/dist/clients/recent-touches.js +17 -5
- package/node_modules/pi-lens/dist/clients/review-graph/builder.js +639 -62
- package/node_modules/pi-lens/dist/clients/review-graph/tsconfig-paths.js +5 -1
- package/node_modules/pi-lens/dist/clients/review-graph-logger.js +21 -1
- package/node_modules/pi-lens/dist/clients/runtime-coordinator.js +68 -0
- package/node_modules/pi-lens/dist/clients/runtime-session.js +30 -12
- package/node_modules/pi-lens/dist/clients/runtime-tool-call.js +15 -0
- package/node_modules/pi-lens/dist/clients/runtime-tool-result.js +106 -7
- package/node_modules/pi-lens/dist/clients/runtime-turn.js +242 -27
- package/node_modules/pi-lens/dist/clients/safe-spawn.js +158 -18
- package/node_modules/pi-lens/dist/clients/security-scan-client.js +48 -17
- package/node_modules/pi-lens/dist/clients/session-lifecycle.js +238 -42
- package/node_modules/pi-lens/dist/clients/sg-runner.js +27 -15
- package/node_modules/pi-lens/dist/clients/shared-checkout-guard.js +338 -0
- package/node_modules/pi-lens/dist/clients/spawn-output-cap.js +37 -0
- package/node_modules/pi-lens/dist/clients/spawn-timeout-cooldown.js +15 -1
- package/node_modules/pi-lens/dist/clients/startup-scan.js +6 -7
- package/node_modules/pi-lens/dist/clients/startup-timing.js +69 -4
- package/node_modules/pi-lens/dist/clients/string-utils.js +20 -0
- package/node_modules/pi-lens/dist/clients/test-runner-client.js +419 -88
- package/node_modules/pi-lens/dist/clients/tool-policy.js +1 -1
- package/node_modules/pi-lens/dist/clients/tree-sitter-client.js +11 -5
- package/node_modules/pi-lens/dist/clients/tree-sitter-logger.js +17 -1
- package/node_modules/pi-lens/dist/clients/warm-attach.js +8 -10
- package/node_modules/pi-lens/dist/clients/word-index-logger.js +13 -1
- package/node_modules/pi-lens/dist/clients/word-index-store.js +448 -0
- package/node_modules/pi-lens/dist/clients/word-index.js +582 -104
- package/node_modules/pi-lens/dist/clients/workspace-topology.js +17 -0
- package/node_modules/pi-lens/dist/clients/zizmor-config.js +26 -6
- package/node_modules/pi-lens/dist/index.js +11243 -6651
- package/node_modules/pi-lens/dist/mcp/build-staleness.js +8 -7
- package/node_modules/pi-lens/dist/mcp/cli.js +3 -1
- package/node_modules/pi-lens/dist/mcp/server.js +6 -1
- package/node_modules/pi-lens/dist/tools/lens-diagnostics.js +4 -0
- package/node_modules/pi-lens/dist/tools/lsp-diagnostics.js +14 -5
- package/node_modules/pi-lens/dist/tools/lsp-navigation.js +3 -1
- package/node_modules/pi-lens/docs/agent-guide.md +4 -2
- package/node_modules/pi-lens/docs/ast-grep_rules_catalog.md +41 -10
- package/node_modules/pi-lens/docs/astplayground.md +26 -17
- package/node_modules/pi-lens/package.json +5 -1
- package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/c-no-malloc-free-test.yml +20 -0
- package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/cpp-no-malloc-free-test.yml +25 -0
- package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/cpp-no-printf-test.yml +19 -0
- package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/go-no-fmt-println-test.yml +19 -0
- package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/go-no-panic-in-lib-test.yml +17 -0
- package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/go-no-underscore-func-name-test.yml +18 -0
- package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/go-prefer-errors-is-test.yml +15 -0
- package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/go-prefer-string-builder-test.yml +21 -0
- package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/hyphenated-svg-attribute-test.yml +11 -0
- package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/kotlin-no-lateinit-test.yml +17 -0
- package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/kotlin-no-nullable-boolean-test.yml +15 -0
- package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/kotlin-no-println-test.yml +19 -0
- package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/kotlin-no-unnecessary-let-test.yml +7 -0
- package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/kotlin-no-unsafe-cast-test.yml +7 -0
- package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/kotlin-no-var-test.yml +7 -0
- package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/kotlin-prefer-data-class-test.yml +25 -0
- package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/kotlin-prefer-is-empty-test.yml +11 -0
- package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/no-important-test.yml +21 -0
- package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/no-raw-types-test.yml +30 -0
- package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/no-string-concat-in-loop-test.yml +100 -0
- package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/no-system-out-println-test.yml +7 -0
- package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/prefer-string-is-empty-test.yml +7 -0
- package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/python-optional-type-test.yml +9 -0
- package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/reducible-list-comprehension-test.yml +11 -0
- package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/ruby-symbol-to-proc-candidate-test.yml +10 -0
- package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/rust-no-chars-enumerate-test.yml +7 -0
- package/node_modules/pi-lens/rules/ast-grep-rules/rules/c-no-malloc-free.yml +39 -0
- package/node_modules/pi-lens/rules/ast-grep-rules/rules/cpp-no-malloc-free.yml +45 -0
- package/node_modules/pi-lens/rules/ast-grep-rules/rules/cpp-no-printf.yml +41 -0
- package/node_modules/pi-lens/rules/ast-grep-rules/rules/go-no-fmt-println.yml +43 -0
- package/node_modules/pi-lens/rules/ast-grep-rules/rules/go-no-panic-in-lib.yml +41 -0
- package/node_modules/pi-lens/rules/ast-grep-rules/rules/go-no-underscore-func-name.yml +35 -0
- package/node_modules/pi-lens/rules/ast-grep-rules/rules/go-prefer-errors-is.yml +40 -0
- package/node_modules/pi-lens/rules/ast-grep-rules/rules/go-prefer-string-builder.yml +43 -0
- package/node_modules/pi-lens/rules/ast-grep-rules/rules/hyphenated-svg-attribute.yml +32 -0
- package/node_modules/pi-lens/rules/ast-grep-rules/rules/kotlin-no-lateinit.yml +37 -0
- package/node_modules/pi-lens/rules/ast-grep-rules/rules/kotlin-no-nullable-boolean.yml +33 -0
- package/node_modules/pi-lens/rules/ast-grep-rules/rules/kotlin-no-println.yml +42 -0
- package/node_modules/pi-lens/rules/ast-grep-rules/rules/kotlin-no-unnecessary-let.yml +28 -0
- package/node_modules/pi-lens/rules/ast-grep-rules/rules/kotlin-no-unsafe-cast.yml +28 -0
- package/node_modules/pi-lens/rules/ast-grep-rules/rules/kotlin-no-var.yml +35 -0
- package/node_modules/pi-lens/rules/ast-grep-rules/rules/kotlin-prefer-data-class.yml +66 -0
- package/node_modules/pi-lens/rules/ast-grep-rules/rules/kotlin-prefer-is-empty.yml +35 -0
- package/node_modules/pi-lens/rules/ast-grep-rules/rules/no-important.yml +21 -0
- package/node_modules/pi-lens/rules/ast-grep-rules/rules/no-raw-types.yml +33 -0
- package/node_modules/pi-lens/rules/ast-grep-rules/rules/no-string-concat-in-loop.yml +90 -0
- package/node_modules/pi-lens/rules/ast-grep-rules/rules/no-system-out-println.yml +16 -0
- package/node_modules/pi-lens/rules/ast-grep-rules/rules/prefer-string-is-empty.yml +11 -0
- package/node_modules/pi-lens/rules/ast-grep-rules/rules/python-optional-type.yml +22 -0
- package/node_modules/pi-lens/rules/ast-grep-rules/rules/reducible-list-comprehension.yml +29 -0
- package/node_modules/pi-lens/rules/ast-grep-rules/rules/ruby-symbol-to-proc-candidate.yml +25 -0
- package/node_modules/pi-lens/rules/ast-grep-rules/rules/rust-no-chars-enumerate.yml +19 -0
- package/node_modules/pi-mcp-adapter/CHANGELOG.md +35 -0
- package/node_modules/pi-mcp-adapter/README.md +5 -2
- package/node_modules/pi-mcp-adapter/cli.js +4 -4
- package/node_modules/pi-mcp-adapter/commands.ts +1 -1
- package/node_modules/pi-mcp-adapter/config.ts +1 -0
- package/node_modules/pi-mcp-adapter/dist/config.js +1 -0
- package/node_modules/pi-mcp-adapter/dist/config.js.map +1 -1
- package/node_modules/pi-mcp-adapter/dist/mcp-bearer-store.d.ts +24 -0
- package/node_modules/pi-mcp-adapter/dist/mcp-bearer-store.js +336 -0
- package/node_modules/pi-mcp-adapter/dist/mcp-bearer-store.js.map +1 -0
- package/node_modules/pi-mcp-adapter/dist/types.d.ts +3 -1
- package/node_modules/pi-mcp-adapter/dist/types.js.map +1 -1
- package/node_modules/pi-mcp-adapter/index.ts +90 -6
- package/node_modules/pi-mcp-adapter/mcp-auth-flow.ts +124 -32
- package/node_modules/pi-mcp-adapter/mcp-bearer-store.ts +0 -2
- package/node_modules/pi-mcp-adapter/mcp-oauth-provider.ts +89 -0
- package/node_modules/pi-mcp-adapter/mcp-references.ts +9 -1
- package/node_modules/pi-mcp-adapter/package.json +1 -1
- package/node_modules/pi-mcp-adapter/proxy-modes.ts +62 -22
- package/node_modules/pi-mcp-adapter/request-headers-command.ts +1 -1
- package/node_modules/pi-mcp-adapter/server-manager.ts +6 -0
- package/node_modules/pi-mcp-adapter/types.ts +3 -1
- package/node_modules/pi-web-access/CHANGELOG.md +42 -0
- package/node_modules/pi-web-access/README.md +26 -10
- package/node_modules/pi-web-access/curator-page.ts +12 -3
- package/node_modules/pi-web-access/curator-server.ts +3 -1
- package/node_modules/pi-web-access/extract.ts +88 -13
- package/node_modules/pi-web-access/gemini-search.ts +10 -5
- package/node_modules/pi-web-access/github-extract.ts +47 -3
- package/node_modules/pi-web-access/index.ts +40 -40
- package/node_modules/pi-web-access/package.json +1 -1
- package/node_modules/pi-web-access/page-query.ts +61 -8
- package/node_modules/pi-web-access/xcrawl.ts +264 -0
- package/package.json +19 -22
- package/node_modules/@herbertgao/pi-stash/README.md +0 -34
- package/node_modules/@herbertgao/pi-stash/package.json +0 -51
- package/node_modules/@herbertgao/pi-stash/src/index.ts +0 -118
- package/node_modules/@tifan/pi-titlebar-spinner/README.md +0 -24
- package/node_modules/@tifan/pi-titlebar-spinner/package.json +0 -39
- package/node_modules/@tifan/pi-titlebar-spinner/src/index.ts +0 -49
|
@@ -50,22 +50,23 @@ export function computeBuildStamp(entryPath, stat = realStat) {
|
|
|
50
50
|
const info = stat(entryPath);
|
|
51
51
|
if (!info)
|
|
52
52
|
return undefined;
|
|
53
|
-
return { entryPath, mtimeMs: info.mtimeMs };
|
|
53
|
+
return { entryPath, mtimeMs: info.mtimeMs, size: info.size };
|
|
54
54
|
}
|
|
55
55
|
/**
|
|
56
56
|
* One-shot comparison: re-stats `stamp.entryPath` and compares against the
|
|
57
|
-
* startup mtime
|
|
58
|
-
*
|
|
59
|
-
*
|
|
60
|
-
*
|
|
61
|
-
*
|
|
57
|
+
* startup mtime AND size (#2300 — a same-mtime-bucket rebuild that changes
|
|
58
|
+
* the bundle's length is otherwise invisible). A failed re-stat (file briefly
|
|
59
|
+
* missing mid-rebuild-write, or an installed-package layout) is treated as
|
|
60
|
+
* NOT stale — we only ever flag a build change we can positively observe,
|
|
61
|
+
* never assume one from an I/O hiccup (false positives would make every tool
|
|
62
|
+
* call route to fresh, which defeats the warm server's entire purpose).
|
|
62
63
|
*/
|
|
63
64
|
export function checkStaleness(stamp, stat = realStat) {
|
|
64
65
|
const info = stat(stamp.entryPath);
|
|
65
66
|
if (!info)
|
|
66
67
|
return { stale: false, stamp, currentMtimeMs: undefined };
|
|
67
68
|
return {
|
|
68
|
-
stale: info.mtimeMs !== stamp.mtimeMs,
|
|
69
|
+
stale: info.mtimeMs !== stamp.mtimeMs || info.size !== stamp.size,
|
|
69
70
|
stamp,
|
|
70
71
|
currentMtimeMs: info.mtimeMs,
|
|
71
72
|
};
|
|
@@ -47,7 +47,9 @@ async function buildGraph() {
|
|
|
47
47
|
if (!stat.isDirectory())
|
|
48
48
|
fail(`cwd is not a directory: ${cwd}`);
|
|
49
49
|
const startedAt = Date.now();
|
|
50
|
-
|
|
50
|
+
// Subject labels this store's capacity-eviction telemetry distinctly from
|
|
51
|
+
// the other five production FactStore instances (#2243 review round 3, F1).
|
|
52
|
+
const graph = await buildOrUpdateGraph(cwd, [], new FactStore("mcp-cli"));
|
|
51
53
|
const attempt = getLastReviewGraphBuildAttempt(cwd);
|
|
52
54
|
// "succeeded" can still carry a `reason` string — persistGraph() stamps one
|
|
53
55
|
// on to explain a partial (over-cap) persist, which is NOT a failure (#960
|
|
@@ -32,6 +32,7 @@ import { createLensDiagnosticsTool } from "../tools/lens-diagnostics.js";
|
|
|
32
32
|
import { peekMcpSessionRuntime } from "../clients/mcp/session.js";
|
|
33
33
|
import { createLspDiagnosticsTool } from "../tools/lsp-diagnostics.js";
|
|
34
34
|
import { createLspNavigationTool } from "../tools/lsp-navigation.js";
|
|
35
|
+
import { shouldInitializeSessionRoot } from "../clients/lsp/session-roots.js";
|
|
35
36
|
import { computeBuildStamp, STALE_SERVED_BY_FRESH, STALE_WARN_ONLY, StalenessGate, stalenessCheckEnabled, } from "./build-staleness.js";
|
|
36
37
|
// Any stray stdout write corrupts the JSON-RPC stream; force it onto stderr.
|
|
37
38
|
console.log = (...args) => {
|
|
@@ -131,8 +132,12 @@ const REPO_ROOT = process.env.PI_LENS_MCP_REPO_ROOT
|
|
|
131
132
|
: findRepoRoot(SERVER_DIR);
|
|
132
133
|
async function ensureReady(cwd) {
|
|
133
134
|
const normalized = path.resolve(cwd);
|
|
134
|
-
|
|
135
|
+
// #2052 R1: the session-root registry evicts old roots at a fixed cap. The
|
|
136
|
+
// readiness memo is only a fast path; consult the registry so an evicted
|
|
137
|
+
// root can initialize again when it is used later.
|
|
138
|
+
if (!shouldInitializeSessionRoot(normalized, lspReadyCwds)) {
|
|
135
139
|
return;
|
|
140
|
+
}
|
|
136
141
|
try {
|
|
137
142
|
await ensureLspConfig(normalized);
|
|
138
143
|
// pi-lens-ignore: missing-error-propagation
|
|
@@ -929,6 +929,9 @@ const UNCONFIRMED_REASON_SENTENCE = {
|
|
|
929
929
|
// completely different failure from a timeout. Must never collapse into
|
|
930
930
|
// "within budget", the exact string this PR exists to stop misrendering.
|
|
931
931
|
binding_mismatch: "the file changed on disk since this result was computed",
|
|
932
|
+
// #2052: no server was asked. Say WHY and say it is permanent for this
|
|
933
|
+
// path, so the reader does not read an empty result as "clean" or retry it.
|
|
934
|
+
outside_project_root: "the file is outside every initialized session project root, so no language server was asked",
|
|
932
935
|
};
|
|
933
936
|
// Short per-reason label used only when MORE than one reason is present, so
|
|
934
937
|
// the note can still say "N timed out, M errored" instead of collapsing to
|
|
@@ -940,6 +943,7 @@ const UNCONFIRMED_REASON_COUNT_LABEL = {
|
|
|
940
943
|
service_destroyed: "service reset mid-sweep",
|
|
941
944
|
error: "errored",
|
|
942
945
|
binding_mismatch: "stale binding",
|
|
946
|
+
outside_project_root: "outside project root",
|
|
943
947
|
};
|
|
944
948
|
/**
|
|
945
949
|
* #1618: a result predating the `unconfirmedReason` field (a legacy/test
|
|
@@ -559,6 +559,7 @@ async function collectDiagnosticsForFile(absPath, lspService, waitMs, serverScop
|
|
|
559
559
|
return {
|
|
560
560
|
diagnostics: filtered,
|
|
561
561
|
timedOut,
|
|
562
|
+
skipReason: touched?.skipReason,
|
|
562
563
|
confirmedByTouch,
|
|
563
564
|
// #1470: only a touch actually contributes a coverage gap; the
|
|
564
565
|
// openFile+getDiagnostics fallback never reports one, which is honest —
|
|
@@ -813,7 +814,7 @@ onConfirmedNoBlockers) {
|
|
|
813
814
|
};
|
|
814
815
|
}
|
|
815
816
|
}
|
|
816
|
-
const { diagnostics: rawDiags, timedOut, confirmedByTouch, unconfirmedServerIds, content: collectedContent, binding, } = await collectDiagnosticsForFile(file, lspService, waitMs, serverScope);
|
|
817
|
+
const { diagnostics: rawDiags, timedOut, confirmedByTouch, unconfirmedServerIds, content: collectedContent, binding, skipReason, } = await collectDiagnosticsForFile(file, lspService, waitMs, serverScope);
|
|
817
818
|
const health = lspService.getDiagnosticsHealth?.(file);
|
|
818
819
|
// #570: a timed-out priming check is never a confirmed "clean" — treat it
|
|
819
820
|
// as unconfirmed without consulting the (unrelated) silent-tier
|
|
@@ -824,7 +825,10 @@ onConfirmedNoBlockers) {
|
|
|
824
825
|
// be merged in rather than discarded.
|
|
825
826
|
let effectiveRawDiags = rawDiags;
|
|
826
827
|
let confirmation;
|
|
827
|
-
if (
|
|
828
|
+
if (skipReason !== undefined) {
|
|
829
|
+
confirmation = "unconfirmed";
|
|
830
|
+
}
|
|
831
|
+
else if (timedOut) {
|
|
828
832
|
if (applySeverityFilter(rawDiags, severity).length === 0) {
|
|
829
833
|
confirmation = "unconfirmed";
|
|
830
834
|
}
|
|
@@ -887,7 +891,7 @@ onConfirmedNoBlockers) {
|
|
|
887
891
|
unconfirmedServerIds.length === 0) {
|
|
888
892
|
cacheCtx.record(file, scopeKey, effectiveRawDiags, stat.mtimeMs, collectedContent !== undefined
|
|
889
893
|
? hashDiagnosticContent(collectedContent)
|
|
890
|
-
: undefined);
|
|
894
|
+
: undefined, stat.size);
|
|
891
895
|
}
|
|
892
896
|
return {
|
|
893
897
|
file,
|
|
@@ -895,6 +899,7 @@ onConfirmedNoBlockers) {
|
|
|
895
899
|
unavailable: lspUnavailableMessage(file, health),
|
|
896
900
|
confirmation,
|
|
897
901
|
timedOut: confirmation === "unconfirmed" ? timedOut : undefined,
|
|
902
|
+
...(skipReason !== undefined && { skipReason }),
|
|
898
903
|
primaryServerId: primaryServerId(file),
|
|
899
904
|
};
|
|
900
905
|
}
|
|
@@ -905,7 +910,7 @@ onConfirmedNoBlockers) {
|
|
|
905
910
|
// Reserve the token before awaiting this file's LSP result. The direct-file
|
|
906
911
|
// path performs its own confirmation/reconciliation below (#1198).
|
|
907
912
|
const writeIndex = nextWriteIndex?.();
|
|
908
|
-
const { diagnostics: rawDiags, timedOut, confirmedByTouch, unconfirmedServerIds, content: collectedContent, binding, } = await collectDiagnosticsForFile(absPath, lspService, waitMs, serverScope);
|
|
913
|
+
const { diagnostics: rawDiags, timedOut, confirmedByTouch, unconfirmedServerIds, content: collectedContent, binding, skipReason, } = await collectDiagnosticsForFile(absPath, lspService, waitMs, serverScope);
|
|
909
914
|
const lspHealth = lspService.getDiagnosticsHealth?.(absPath);
|
|
910
915
|
const unavailable = lspUnavailableMessage(absPath, lspHealth);
|
|
911
916
|
// #533: an empty result needs a confirmed/unconfirmed verdict — a push-only,
|
|
@@ -919,7 +924,10 @@ onConfirmedNoBlockers) {
|
|
|
919
924
|
// diagnostics it surfaces are merged in, not discarded.
|
|
920
925
|
let effectiveRawDiags = rawDiags;
|
|
921
926
|
let confirmation;
|
|
922
|
-
if (
|
|
927
|
+
if (skipReason !== undefined) {
|
|
928
|
+
confirmation = "unconfirmed";
|
|
929
|
+
}
|
|
930
|
+
else if (timedOut) {
|
|
923
931
|
if (applySeverityFilter(rawDiags, severity).length === 0) {
|
|
924
932
|
confirmation = "unconfirmed";
|
|
925
933
|
}
|
|
@@ -1060,6 +1068,7 @@ onConfirmedNoBlockers) {
|
|
|
1060
1068
|
truncated,
|
|
1061
1069
|
unconfirmed,
|
|
1062
1070
|
timedOut: unconfirmed ? timedOut : undefined,
|
|
1071
|
+
...(skipReason !== undefined && { skipReason }),
|
|
1063
1072
|
// #1470: which servers this result does NOT speak for. Absent when it
|
|
1064
1073
|
// speaks for all of them.
|
|
1065
1074
|
...(unconfirmedServerIds.length > 0 && {
|
|
@@ -467,6 +467,8 @@ function formatCapabilities(snapshots, filePath) {
|
|
|
467
467
|
["hover", (s) => !!s.operationSupport.hover],
|
|
468
468
|
["rename", (s) => !!s.operationSupport.rename],
|
|
469
469
|
["codeAction", (s) => !!s.operationSupport.codeAction],
|
|
470
|
+
["codeAction/resolve", (s) => !!s.operationSupport.codeActionResolve],
|
|
471
|
+
["workspace/willRenameFiles", (s) => !!s.operationSupport.willRenameFiles],
|
|
470
472
|
["workspaceSymbol", (s) => !!s.operationSupport.workspaceSymbol],
|
|
471
473
|
["implementation", (s) => !!s.operationSupport.implementation],
|
|
472
474
|
["signatureHelp", (s) => !!s.operationSupport.signatureHelp],
|
|
@@ -480,7 +482,7 @@ function formatCapabilities(snapshots, filePath) {
|
|
|
480
482
|
[
|
|
481
483
|
"rename_file",
|
|
482
484
|
() => true,
|
|
483
|
-
"
|
|
485
|
+
"filesystem rename; preflight support shown above",
|
|
484
486
|
],
|
|
485
487
|
];
|
|
486
488
|
const lines = [];
|
|
@@ -143,8 +143,10 @@ Edits fail or warn when:
|
|
|
143
143
|
|
|
144
144
|
A blocked edit returns a retryable message, e.g.:
|
|
145
145
|
|
|
146
|
-
|
|
147
|
-
|
|
146
|
+
```text
|
|
147
|
+
🔄 RETRYABLE — Edit without read: you have not read `<file>` in this
|
|
148
|
+
conversation. Read it first, then retry: `read path="<file>"`.
|
|
149
|
+
```
|
|
148
150
|
|
|
149
151
|
**Correct behavior:** read the file (or the relevant range/symbol) *before* editing.
|
|
150
152
|
Helpful mechanics you can rely on:
|
|
@@ -2,16 +2,17 @@
|
|
|
2
2
|
|
|
3
3
|
<!-- GENERATED by scripts/gen-rule-catalogs.mjs — do not edit by hand. Run `npm run docs:rule-catalogs` after changing rules. -->
|
|
4
4
|
|
|
5
|
-
pi-lens bundles **
|
|
5
|
+
pi-lens bundles **481 enabled** ast-grep rules (297 pi-lens-authored + 184 vendored from CodeRabbit) across **17 languages**, plus 16 disabled.
|
|
6
6
|
|
|
7
7
|
See [`docs/custom-rules.md`](custom-rules.md) to add your own. Rule sources: `rules/ast-grep-rules/rules/` (pi-lens), `rules/ast-grep-rules/coderabbit/rules/` (vendored).
|
|
8
8
|
|
|
9
9
|
## Enabled rules
|
|
10
10
|
|
|
11
|
-
### C (
|
|
11
|
+
### C (10)
|
|
12
12
|
|
|
13
13
|
| Rule | Severity | Fixable | Source | Description |
|
|
14
14
|
|---|---|---|---|---|
|
|
15
|
+
| `c-no-malloc-free` | warning | no | pi-lens | Manual malloc/calloc/realloc/free; verify ownership and error handling |
|
|
15
16
|
| `dont-call-system-c` | warning | no | CodeRabbit | Don't call `system`. It's a high-level wrapper that allows for stacking multiple commands. Always prefer a more restrictive API such as cal… |
|
|
16
17
|
| `file-access-before-action-c` | warning | no | CodeRabbit | A check is done with `access` and then the file is later used. There is no guarantee that the status of the file has not changed since the… |
|
|
17
18
|
| `file-stat-before-action-c` | warning | no | CodeRabbit | A check is done with `stat` and then the file is used. There is no guarantee that the status of the file has not changed since the call to… |
|
|
@@ -22,10 +23,12 @@ See [`docs/custom-rules.md`](custom-rules.md) to add your own. Rule sources: `ru
|
|
|
22
23
|
| `small-key-size-c` | warning | no | CodeRabbit | $KEY_FUNCTION` is using a key size of only $KEY_BITS bits. This is less than the recommended key size of 2048 bits. |
|
|
23
24
|
| `world-writable-file-c` | warning | no | CodeRabbit | This call makes a world-writable file which allows any user on a machine to write to the file. This may allow attackers to influence the be… |
|
|
24
25
|
|
|
25
|
-
### C++ (
|
|
26
|
+
### C++ (17)
|
|
26
27
|
|
|
27
28
|
| Rule | Severity | Fixable | Source | Description |
|
|
28
29
|
|---|---|---|---|---|
|
|
30
|
+
| `cpp-no-malloc-free` | warning | no | pi-lens | Manual malloc/calloc/realloc/free in C++; consider RAII (new/unique_ptr/vector) |
|
|
31
|
+
| `cpp-no-printf` | warning | no | pi-lens | Avoid printf in C++; prefer std::cout/std::format for type-safe formatting |
|
|
29
32
|
| `dont-call-system-cpp` | warning | no | CodeRabbit | Don't call `system`. It's a high-level wrapper that allows for stacking multiple commands. Always prefer a more restrictive API such as cal… |
|
|
30
33
|
| `file-access-before-action-cpp` | warning | no | CodeRabbit | A check is done with `access` and then the file is later used. There is no guarantee that the status of the file has not changed since the… |
|
|
31
34
|
| `file-stat-before-action-cpp` | warning | no | CodeRabbit | A check is done with `stat` and then the file is used. There is no guarantee that the status of the file has not changed since the call to… |
|
|
@@ -58,13 +61,24 @@ See [`docs/custom-rules.md`](custom-rules.md) to add your own. Rule sources: `ru
|
|
|
58
61
|
| `stacktrace-disclosure-csharp` | warning | no | CodeRabbit | Stacktrace information is displayed in a non-Development environment. Accidentally disclosing sensitive stack trace information in a produc… |
|
|
59
62
|
| `use-ecb-mode-csharp` | warning | no | CodeRabbit | "Usage of the insecure ECB mode detected. You should use an authenticated encryption mode instead, which is implemented by the classes AesG… |
|
|
60
63
|
|
|
61
|
-
###
|
|
64
|
+
### CSS (1)
|
|
65
|
+
|
|
66
|
+
| Rule | Severity | Fixable | Source | Description |
|
|
67
|
+
|---|---|---|---|---|
|
|
68
|
+
| `no-important` | warning | no | pi-lens | Avoid `!important` — increase selector specificity instead |
|
|
69
|
+
|
|
70
|
+
### Go (28)
|
|
62
71
|
|
|
63
72
|
| Rule | Severity | Fixable | Source | Description |
|
|
64
73
|
|---|---|---|---|---|
|
|
65
74
|
| `avoid-bind-to-all-interfaces-go` | warning | no | CodeRabbit | "Detected a network listener listening on 0.0.0.0 or an empty string. This could unexpectedly expose the server publicly as it binds to all… |
|
|
66
75
|
| `defer-in-loop` | warning | no | pi-lens | defer is used inside a loop. This defers execution until after the entire function, not each iteration. |
|
|
67
76
|
| `go-defer-func-call-antipattern` | warning | yes | pi-lens | defer with function-call args — arguments are evaluated immediately, not at defer time |
|
|
77
|
+
| `go-no-fmt-println` | warning | no | pi-lens | Avoid fmt.Println/Printf-family calls in production code; use a structured logger |
|
|
78
|
+
| `go-no-panic-in-lib` | warning | no | pi-lens | Avoid panic() in library code; return errors instead |
|
|
79
|
+
| `go-no-underscore-func-name` | hint | no | pi-lens | Use camelCase for Go function names, not snake_case |
|
|
80
|
+
| `go-prefer-errors-is` | hint | no | pi-lens | Use errors.Is(err, target) instead of direct comparison for error checking |
|
|
81
|
+
| `go-prefer-string-builder` | hint | no | pi-lens | Use strings.Builder instead of repeated string concatenation |
|
|
68
82
|
| `go-test-functions` | warning | yes | pi-lens | Go test function detected — verify it follows the project's test naming convention |
|
|
69
83
|
| `gorilla-cookie-store-hardcoded-session-key-go` | warning | no | CodeRabbit | A secret is hard-coded in the application. Secrets stored in source code, such as credentials, identifiers, and other types of sensitive da… |
|
|
70
84
|
| `gorilla-csrf-hardcoded-auth-key-go` | warning | no | CodeRabbit | A secret is hard-coded in the application. Secrets stored in source code, such as credentials, identifiers, and other types of sensitive da… |
|
|
@@ -92,7 +106,7 @@ See [`docs/custom-rules.md`](custom-rules.md) to add your own. Rule sources: `ru
|
|
|
92
106
|
|---|---|---|---|---|
|
|
93
107
|
| `plaintext-http-link-html` | warning | no | CodeRabbit | "This link points to a plaintext HTTP URL. Prefer an encrypted HTTPS URL if possible." |
|
|
94
108
|
|
|
95
|
-
### Java (
|
|
109
|
+
### Java (40)
|
|
96
110
|
|
|
97
111
|
| Rule | Severity | Fixable | Source | Description |
|
|
98
112
|
|---|---|---|---|---|
|
|
@@ -118,7 +132,11 @@ See [`docs/custom-rules.md`](custom-rules.md) to add your own. Rule sources: `ru
|
|
|
118
132
|
| `missing-httponly-java` | warning | no | CodeRabbit | Detected a cookie where the `HttpOnly` flag is either missing or disabled. The `HttpOnly` cookie flag instructs the browser to forbid clien… |
|
|
119
133
|
| `missing-secure-java` | warning | no | CodeRabbit | Detected a cookie where the `Secure` flag is either missing or disabled. The `Secure` cookie flag instructs the browser to forbid sending t… |
|
|
120
134
|
| `no-null-cipher-java` | warning | no | CodeRabbit | NullCipher was detected. This will not encrypt anything; the cipher text will be the same as the plain text. Use a valid, secure cipher: Ci… |
|
|
135
|
+
| `no-raw-types` | warning | no | pi-lens | Use parameterized types instead of raw types. |
|
|
136
|
+
| `no-string-concat-in-loop` | warning | no | pi-lens | Use StringBuilder instead of string concatenation in loops. |
|
|
137
|
+
| `no-system-out-println` | warning | no | pi-lens | Avoid System.out.println; use a logging framework instead. |
|
|
121
138
|
| `passwordauthentication-hardcoded-password-java` | warning | no | CodeRabbit | A secret is hard-coded in the application. Secrets stored in source code, such as credentials, identifiers, and other types of sensitive da… |
|
|
139
|
+
| `prefer-string-is-empty` | warning | no | pi-lens | Use .isEmpty() instead of .length() == 0 or .equals(""). |
|
|
122
140
|
| `rsa-no-padding-java` | warning | no | CodeRabbit | Using RSA without OAEP mode weakens the encryption. |
|
|
123
141
|
| `simple-command-injection-direct-input-java` | warning | no | CodeRabbit | "Untrusted input might be injected into a command executed by the application, which can lead to a command injection vulnerability. An atta… |
|
|
124
142
|
| `system-setproperty-hardcoded-secret-java` | warning | no | CodeRabbit | A secret is hard-coded in the application. Secrets stored in source code, such as credentials, identifiers, and other types of sensitive da… |
|
|
@@ -217,13 +235,21 @@ See [`docs/custom-rules.md`](custom-rules.md) to add your own. Rule sources: `ru
|
|
|
217
235
|
| `unchecked-throwing-call-js` | error | no | pi-lens | $CALL without try/catch — throws on invalid input |
|
|
218
236
|
| `weak-rsa-key-js` | error | no | pi-lens | Weak RSA key size — use at least 2048 bits |
|
|
219
237
|
|
|
220
|
-
### Kotlin (
|
|
238
|
+
### Kotlin (13)
|
|
221
239
|
|
|
222
240
|
| Rule | Severity | Fixable | Source | Description |
|
|
223
241
|
|---|---|---|---|---|
|
|
224
242
|
| `des-is-deprecated-kotlin` | warning | no | CodeRabbit | DES is considered deprecated. AES is the recommended cipher. Upgrade to use AES. See https://www.nist.gov/news-events/news/2005/06/nist-wit… |
|
|
225
243
|
| `desede-is-deprecated-kotlin` | warning | no | CodeRabbit | Triple DES (3DES or DESede) is considered deprecated. AES is the recommended cipher. Upgrade to use AES. |
|
|
226
244
|
| `jwt-hardcode-kotlin` | warning | no | CodeRabbit | A secret is hard-coded in the application. Secrets stored in source code, such as credentials, identifiers, and other types of sensitive da… |
|
|
245
|
+
| `kotlin-no-lateinit` | warning | no | pi-lens | Avoid lateinit var; prefer a nullable type or constructor injection |
|
|
246
|
+
| `kotlin-no-nullable-boolean` | warning | no | pi-lens | Avoid a nullable Boolean; a two-value enum or a non-null default is usually clearer |
|
|
247
|
+
| `kotlin-no-println` | warning | no | pi-lens | Avoid println/print; use a structured logger |
|
|
248
|
+
| `kotlin-no-unnecessary-let` | warning | no | pi-lens | let on a non-null-checked receiver adds indirection; use the value directly |
|
|
249
|
+
| `kotlin-no-unsafe-cast` | warning | no | pi-lens | Unsafe cast (as) throws ClassCastException on a mismatch; consider as? |
|
|
250
|
+
| `kotlin-no-var` | warning | no | pi-lens | Prefer val over var; mutability should be explicit and scoped |
|
|
251
|
+
| `kotlin-prefer-data-class` | warning | no | pi-lens | This class looks like a plain value holder; consider a data class |
|
|
252
|
+
| `kotlin-prefer-is-empty` | warning | no | pi-lens | Use isEmpty() instead of comparing size/length to zero |
|
|
227
253
|
| `rsa-no-padding-kotlin` | warning | no | CodeRabbit | Using RSA without OAEP mode weakens the encryption. |
|
|
228
254
|
| `system-setproperty-hardcoded-secret-kotlin` | warning | no | CodeRabbit | A secret is hard-coded in the application. Secrets stored in source code, such as credentials, identifiers, and other types of sensitive da… |
|
|
229
255
|
|
|
@@ -234,7 +260,7 @@ See [`docs/custom-rules.md`](custom-rules.md) to add your own. Rule sources: `ru
|
|
|
234
260
|
| `openssl-cbc-static-iv-php` | warning | no | CodeRabbit | Static IV used with AES in CBC mode. Static IVs enable chosen-plaintext attacks against encrypted data. |
|
|
235
261
|
| `search-active-debug-php` | warning | no | CodeRabbit | Debug logging is explicitly enabled. This can potentially disclose sensitive information and should never be active on production systems. |
|
|
236
262
|
|
|
237
|
-
### Python (
|
|
263
|
+
### Python (98)
|
|
238
264
|
|
|
239
265
|
| Rule | Severity | Fixable | Source | Description |
|
|
240
266
|
|---|---|---|---|---|
|
|
@@ -308,6 +334,7 @@ See [`docs/custom-rules.md`](custom-rules.md) to add your own. Rule sources: `ru
|
|
|
308
334
|
| `python-mysqlclient-hardcoded-secret-python` | warning | no | CodeRabbit | A secret is hard-coded in the application. Secrets stored in source code, such as credentials, identifiers, and other types of sensitive da… |
|
|
309
335
|
| `python-neo4j-empty-password-python` | warning | no | CodeRabbit | The application creates a database connection with an empty password. This can lead to unauthorized access by either an internal or externa… |
|
|
310
336
|
| `python-neo4j-hardcoded-secret-python` | warning | no | CodeRabbit | A secret is hard-coded in the application. Secrets stored in source code, such as credentials, identifiers, and other types of sensitive da… |
|
|
337
|
+
| `python-optional-type` | hint | no | pi-lens | Optional[T] requires Python 3.10+ to rewrite as T \| None |
|
|
311
338
|
| `python-peewee-mysql-empty-password-python` | warning | no | CodeRabbit | The application creates a database connection with an empty password. This can lead to unauthorized access by either an internal or externa… |
|
|
312
339
|
| `python-peewee-mysql-hardcoded-secret-python` | warning | no | CodeRabbit | A secret is hard-coded in the application. Secrets stored in source code, such as credentials, identifiers, and other types of sensitive da… |
|
|
313
340
|
| `python-peewee-pg-empty-password-python` | warning | no | CodeRabbit | The application creates a database connection with an empty password. This can lead to unauthorized access by either an internal or externa… |
|
|
@@ -333,9 +360,10 @@ See [`docs/custom-rules.md`](custom-rules.md) to add your own. Rule sources: `ru
|
|
|
333
360
|
| `python-urllib3-hardcoded-secret-python` | warning | no | CodeRabbit | A secret is hard-coded in the application. Secrets stored in source code, such as credentials, identifiers, and other types of sensitive da… |
|
|
334
361
|
| `python-webrepl-empty-password-python` | warning | no | CodeRabbit | The application creates a database connection with an empty password. This can lead to unauthorized access by either an internal or externa… |
|
|
335
362
|
| `python-webrepl-hardcoded-secret-python` | warning | no | CodeRabbit | A secret is hard-coded in the application. Secrets stored in source code, such as credentials, identifiers, and other types of sensitive da… |
|
|
363
|
+
| `reducible-list-comprehension` | warning | yes | pi-lens | A list comprehension is unnecessary here; use a generator expression |
|
|
336
364
|
| `unchecked-throwing-call-python` | error | no | pi-lens | Call without try/except — throws on invalid input or missing file |
|
|
337
365
|
|
|
338
|
-
### Ruby (
|
|
366
|
+
### Ruby (20)
|
|
339
367
|
|
|
340
368
|
| Rule | Severity | Fixable | Source | Description |
|
|
341
369
|
|---|---|---|---|---|
|
|
@@ -358,8 +386,9 @@ See [`docs/custom-rules.md`](custom-rules.md) to add your own. Rule sources: `ru
|
|
|
358
386
|
| `ruby-pg-hardcoded-secret-ruby` | warning | no | CodeRabbit | A secret is hard-coded in the application. Secrets stored in source code, such as credentials, identifiers, and other types of sensitive da… |
|
|
359
387
|
| `ruby-redis-empty-password-ruby` | warning | no | CodeRabbit | The application creates a database connection with an empty password. This can lead to unauthorized access by either an internal or externa… |
|
|
360
388
|
| `ruby-redis-hardcoded-secret-ruby` | warning | no | CodeRabbit | A secret is hard-coded in the application. Secrets stored in source code, such as credentials, identifiers, and other types of sensitive da… |
|
|
389
|
+
| `ruby-symbol-to-proc-candidate` | warning | yes | pi-lens | Use a symbol-to-proc shorthand for this simple iterator block |
|
|
361
390
|
|
|
362
|
-
### Rust (
|
|
391
|
+
### Rust (12)
|
|
363
392
|
|
|
364
393
|
| Rule | Severity | Fixable | Source | Description |
|
|
365
394
|
|---|---|---|---|---|
|
|
@@ -370,6 +399,7 @@ See [`docs/custom-rules.md`](custom-rules.md) to add your own. Rule sources: `ru
|
|
|
370
399
|
| `redundant-unsafe-function` | error | no | pi-lens | Unsafe function without unsafe block inside |
|
|
371
400
|
| `reqwest-accept-invalid-rust` | warning | no | CodeRabbit | Dangerously accepting invalid TLS |
|
|
372
401
|
| `rust-2024-let-chain-candidate` | info | no | pi-lens | nested if conditions can be collapsed into a Rust 2024 let-chain |
|
|
402
|
+
| `rust-no-chars-enumerate` | warning | no | pi-lens | chars().enumerate() may confuse character indices with byte offsets |
|
|
373
403
|
| `secrets-reqwest-hardcoded-auth-rust` | warning | no | CodeRabbit | A secret is hard-coded in the application. Secrets stored in source code, such as credentials, identifiers, and other types of sensitive da… |
|
|
374
404
|
| `ssl-verify-none-rust` | warning | no | CodeRabbit | SSL verification disabled, this allows for MitM attacks |
|
|
375
405
|
| `tokio-postgres-empty-password-rust` | warning | no | CodeRabbit | The application uses an empty credential. This can lead to unauthorized access by either an internal or external malicious actor. It is rec… |
|
|
@@ -392,10 +422,11 @@ See [`docs/custom-rules.md`](custom-rules.md) to add your own. Rule sources: `ru
|
|
|
392
422
|
| `insecure-biometrics-swift` | info | no | CodeRabbit | The application was observed to leverage biometrics via Local Authentication, which returns a simple boolean result for authentication. Thi… |
|
|
393
423
|
| `rabbit-hardcoded-secret-swift` | warning | no | CodeRabbit | A secret is hard-coded in the application. Secrets stored in source code, such as credentials, identifiers, and other types of sensitive da… |
|
|
394
424
|
|
|
395
|
-
### TSX (
|
|
425
|
+
### TSX (8)
|
|
396
426
|
|
|
397
427
|
| Rule | Severity | Fixable | Source | Description |
|
|
398
428
|
|---|---|---|---|---|
|
|
429
|
+
| `hyphenated-svg-attribute` | warning | no | pi-lens | Use camelCase for this known SVG attribute in JSX |
|
|
399
430
|
| `inline-styles` | hint | no | pi-lens | Inline styles — use CSS modules or styled components |
|
|
400
431
|
| `jsx-boolean-short-circuit` | error | yes | pi-lens | React JSX && pitfall — potentially renders 0 or NaN |
|
|
401
432
|
| `no-nested-links` | error | no | pi-lens | Nested <a> tags are invalid HTML and cause unexpected behavior |
|
|
@@ -27,38 +27,49 @@ released `ast-grep`), so we get a fresh-engine cross-check.
|
|
|
27
27
|
|
|
28
28
|
## What the playground actually does
|
|
29
29
|
|
|
30
|
-
The
|
|
31
|
-
|
|
30
|
+
The verifier encodes `--code` into the playground's URL-hash state so the
|
|
31
|
+
upstream engine matches the rule against it. The state (`ast-grep/ast-
|
|
32
|
+
grep.github.io`, `website/src/components/astGrep/state.ts` +
|
|
33
|
+
`index.ts`) carries:
|
|
32
34
|
|
|
33
35
|
- `mode: "Config"` + `config: <rule YAML>` (the rule)
|
|
34
|
-
- `
|
|
36
|
+
- `source: <code>` — the code the rule is matched against, in **both**
|
|
37
|
+
modes
|
|
38
|
+
- `query` — an ast-grep pattern string, used only in `mode: "Pattern"`
|
|
39
|
+
(irrelevant here; the verifier always requests Config mode)
|
|
35
40
|
|
|
36
|
-
So this verifier
|
|
37
|
-
|
|
41
|
+
So this verifier checks: "does the rule match `--code` on the upstream
|
|
42
|
+
engine, and does the count agree with the local `ast-grep` CLI?" It catches:
|
|
38
43
|
|
|
39
44
|
- **YAML/pattern rejection** — the playground shows an error if the rule's
|
|
40
45
|
YAML uses features the upstream engine doesn't support
|
|
41
46
|
- **Pattern-engine divergence** — local ast-grep matches but upstream
|
|
42
47
|
doesn't (or vice versa)
|
|
43
48
|
- **Match-count drift** — `Found N match(es)` count differs between local
|
|
44
|
-
and upstream
|
|
49
|
+
and upstream, for the *same* source
|
|
45
50
|
|
|
46
|
-
|
|
47
|
-
|
|
51
|
+
#2208: earlier versions of this verifier wrote `--code` into `query`
|
|
52
|
+
instead of `source`. Since `query` is ignored in Config mode, the hash
|
|
53
|
+
carried no source at all, and the playground's `{...defaultState,
|
|
54
|
+
...parsed}` state merge silently fell back to its own hardcoded sample —
|
|
55
|
+
every run graded that fixed sample, not `--code`. Every "ok:true
|
|
56
|
+
matches:N" this verifier produced before the fix reflected the playground's
|
|
57
|
+
sample source, never the caller's code.
|
|
48
58
|
|
|
49
59
|
## Usage
|
|
50
60
|
|
|
51
61
|
```bash
|
|
52
|
-
# Smoke-test a single rule
|
|
53
|
-
|
|
62
|
+
# Smoke-test a single rule against a snippet it matches
|
|
63
|
+
# (auto-launches headless Chrome on 9224, then kills it)
|
|
64
|
+
node scripts/playground-verify-rule.mjs rules/ast-grep-rules/rules/no-console-except-error.yml --code "console.log('x');"
|
|
54
65
|
|
|
55
66
|
# Assert a specific match count
|
|
56
67
|
node scripts/playground-verify-rule.mjs rules/ast-grep-rules/rules/jsx-boolean-short-circuit.yml \
|
|
57
|
-
--code "
|
|
68
|
+
--code "const a = 1;" --expected 0
|
|
58
69
|
|
|
59
70
|
# Keep Chrome alive for follow-up runs (avoids the 5–10s cold-start cost)
|
|
60
71
|
node scripts/playground-verify-rule.mjs rules/ast-grep-rules/rules/no-console-except-error.yml \
|
|
61
|
-
--code "
|
|
72
|
+
--code "console.log('x');" --keep-chrome
|
|
62
73
|
|
|
63
74
|
```
|
|
64
75
|
|
|
@@ -142,7 +153,9 @@ Three scripts, one job each:
|
|
|
142
153
|
resolution, accessibility tree, and network tracing stripped out.
|
|
143
154
|
- `playground-verify-rule.mjs` — the CLI the user invokes. Reads the rule,
|
|
144
155
|
builds the playground URL, runs the page through CDP, scrapes the
|
|
145
|
-
result, prints JSON, kills Chrome.
|
|
156
|
+
result, prints JSON, and kills Chrome. Its source-drift sentinel reads only
|
|
157
|
+
the first `.monaco-editor` in the source pane, not the config editor, so a
|
|
158
|
+
rule note cannot satisfy the check by repeating the fixture text.
|
|
146
159
|
|
|
147
160
|
## Skipping the test
|
|
148
161
|
|
|
@@ -165,10 +178,6 @@ auto-skipped when Google Chrome is not on `PATH` and
|
|
|
165
178
|
|
|
166
179
|
## Known limitations
|
|
167
180
|
|
|
168
|
-
- **Source is fixed.** The playground uses its own hardcoded sample
|
|
169
|
-
source. Custom source code passed via `--code` is ignored by the
|
|
170
|
-
upstream playground in `mode: "Config"`. This is by design — the
|
|
171
|
-
playground is a manual tool, not a test harness.
|
|
172
181
|
- **Slow.** ~11s per rule. Don't enable in the default `npm test` run.
|
|
173
182
|
- **Line numbers are best-effort.** The playground's gutter layout
|
|
174
183
|
changes between builds. If the line-extraction JS misses, `lines` is
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "pi-lens",
|
|
3
|
-
"version": "4.1.
|
|
3
|
+
"version": "4.1.3",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "Real-time code feedback for pi — LSP, linters, formatters, type-checking, structural analysis & booboo",
|
|
6
6
|
"repository": {
|
|
@@ -19,6 +19,7 @@
|
|
|
19
19
|
"bundle:dist": "node scripts/bundle-dist.mjs",
|
|
20
20
|
"prepare": "npm run build:dist && node scripts/download-grammars.js --core --dest grammars && node scripts/setup-git-hooks.mjs && node scripts/warm-loader-cache.mjs",
|
|
21
21
|
"lint": "tsc --project tsconfig.json",
|
|
22
|
+
"depcruise:check": "depcruise --validate --config .dependency-cruiser.cjs --ignore-known .dependency-cruiser-known-violations.json --output-type err index.ts \"clients/**/*.ts\"",
|
|
22
23
|
"fmt": "oxfmt",
|
|
23
24
|
"fmt:check": "oxfmt --check",
|
|
24
25
|
"watch": "tsc --watch",
|
|
@@ -38,6 +39,7 @@
|
|
|
38
39
|
"astgrep:self-scan:update-baseline": "node scripts/run-astgrep-pi-lens.mjs --update-baseline",
|
|
39
40
|
"audit:playground": "node scripts/playground-verify-rule.mjs",
|
|
40
41
|
"bench:cascade-budget": "node scripts/bench-cascade-budget.mjs",
|
|
42
|
+
"bench:word-index-replacement": "node scripts/bench-word-index-replacement.mjs",
|
|
41
43
|
"logs:smells": "node scripts/analyze-pi-lens-logs.mjs",
|
|
42
44
|
"changelog:check": "node scripts/rollup-changelog.mjs --check",
|
|
43
45
|
"changelog:release": "node scripts/changelog-release.mjs",
|
|
@@ -126,7 +128,9 @@
|
|
|
126
128
|
"@types/node": "^26.0.0",
|
|
127
129
|
"@types/pidusage": "^2.0.5",
|
|
128
130
|
"@vitest/coverage-v8": "^4.1.5",
|
|
131
|
+
"dependency-cruiser": "^18.2.0",
|
|
129
132
|
"husky": "^9.1.7",
|
|
133
|
+
"json5": "^2.2.3",
|
|
130
134
|
"oxfmt": "0.64.0",
|
|
131
135
|
"oxlint": "1.79.0",
|
|
132
136
|
"typebox": "^1.0.0",
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
id: c-no-malloc-free
|
|
2
|
+
valid:
|
|
3
|
+
- |
|
|
4
|
+
int sum(const int *values, int count) {
|
|
5
|
+
int total = 0;
|
|
6
|
+
for (int i = 0; i < count; i++) {
|
|
7
|
+
total += values[i];
|
|
8
|
+
}
|
|
9
|
+
return total;
|
|
10
|
+
}
|
|
11
|
+
invalid:
|
|
12
|
+
- |
|
|
13
|
+
int *make_buffer(int count) {
|
|
14
|
+
int *buf = malloc(sizeof(int) * count);
|
|
15
|
+
return buf;
|
|
16
|
+
}
|
|
17
|
+
- |
|
|
18
|
+
void release(int *buf) {
|
|
19
|
+
free(buf);
|
|
20
|
+
}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
id: cpp-no-malloc-free
|
|
2
|
+
valid:
|
|
3
|
+
- |
|
|
4
|
+
std::unique_ptr<int[]> make_buffer(int count) {
|
|
5
|
+
return std::make_unique<int[]>(count);
|
|
6
|
+
}
|
|
7
|
+
invalid:
|
|
8
|
+
- |
|
|
9
|
+
int* make_buffer(int count) {
|
|
10
|
+
int* buf = static_cast<int*>(malloc(sizeof(int) * count));
|
|
11
|
+
return buf;
|
|
12
|
+
}
|
|
13
|
+
- |
|
|
14
|
+
void release(int* buf) {
|
|
15
|
+
free(buf);
|
|
16
|
+
}
|
|
17
|
+
- |
|
|
18
|
+
int* make_buffer(int count) {
|
|
19
|
+
int* buf = static_cast<int*>(std::malloc(sizeof(int) * count));
|
|
20
|
+
return buf;
|
|
21
|
+
}
|
|
22
|
+
- |
|
|
23
|
+
void release(int* buf) {
|
|
24
|
+
::free(buf);
|
|
25
|
+
}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
id: cpp-no-printf
|
|
2
|
+
valid:
|
|
3
|
+
- |
|
|
4
|
+
void report(int count) {
|
|
5
|
+
std::cout << "count: " << count << "\n";
|
|
6
|
+
}
|
|
7
|
+
- |
|
|
8
|
+
void log(const char* msg) {
|
|
9
|
+
fprintf(stderr, "%s\n", msg);
|
|
10
|
+
}
|
|
11
|
+
invalid:
|
|
12
|
+
- |
|
|
13
|
+
void report(int count) {
|
|
14
|
+
printf("count: %d\n", count);
|
|
15
|
+
}
|
|
16
|
+
- |
|
|
17
|
+
void report(int count) {
|
|
18
|
+
std::printf("count: %d\n", count);
|
|
19
|
+
}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
id: go-no-fmt-println
|
|
2
|
+
valid:
|
|
3
|
+
- |
|
|
4
|
+
func main() {
|
|
5
|
+
slog.Info("hello", "key", "value")
|
|
6
|
+
}
|
|
7
|
+
- |
|
|
8
|
+
func main() {
|
|
9
|
+
log.Printf("started on port %d", port)
|
|
10
|
+
}
|
|
11
|
+
invalid:
|
|
12
|
+
- |
|
|
13
|
+
func main() {
|
|
14
|
+
fmt.Println("hello")
|
|
15
|
+
}
|
|
16
|
+
- |
|
|
17
|
+
func main() {
|
|
18
|
+
fmt.Printf("value: %d\n", 42)
|
|
19
|
+
}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
id: go-no-panic-in-lib
|
|
2
|
+
valid:
|
|
3
|
+
- |
|
|
4
|
+
func divide(a, b int) (int, error) {
|
|
5
|
+
if b == 0 {
|
|
6
|
+
return 0, errors.New("division by zero")
|
|
7
|
+
}
|
|
8
|
+
return a / b, nil
|
|
9
|
+
}
|
|
10
|
+
invalid:
|
|
11
|
+
- |
|
|
12
|
+
func mustDivide(a, b int) int {
|
|
13
|
+
if b == 0 {
|
|
14
|
+
panic("division by zero")
|
|
15
|
+
}
|
|
16
|
+
return a / b
|
|
17
|
+
}
|
package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/go-no-underscore-func-name-test.yml
ADDED
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
id: go-no-underscore-func-name
|
|
2
|
+
valid:
|
|
3
|
+
- |
|
|
4
|
+
func handleRequest(w http.ResponseWriter, r *http.Request) {
|
|
5
|
+
}
|
|
6
|
+
- |
|
|
7
|
+
func getUserName(id int) string {
|
|
8
|
+
return ""
|
|
9
|
+
}
|
|
10
|
+
invalid:
|
|
11
|
+
- |
|
|
12
|
+
func _helper() string {
|
|
13
|
+
return ""
|
|
14
|
+
}
|
|
15
|
+
- |
|
|
16
|
+
func get_user_name(id int) string {
|
|
17
|
+
return ""
|
|
18
|
+
}
|
package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/go-prefer-string-builder-test.yml
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
id: go-prefer-string-builder
|
|
2
|
+
valid:
|
|
3
|
+
- |
|
|
4
|
+
func build(parts []string) string {
|
|
5
|
+
var b strings.Builder
|
|
6
|
+
for _, p := range parts {
|
|
7
|
+
b.WriteString(p)
|
|
8
|
+
}
|
|
9
|
+
return b.String()
|
|
10
|
+
}
|
|
11
|
+
invalid:
|
|
12
|
+
- |
|
|
13
|
+
func concat(a string, b string) string {
|
|
14
|
+
a = a + b
|
|
15
|
+
return a
|
|
16
|
+
}
|
|
17
|
+
- |
|
|
18
|
+
func appendSuffix(s string) string {
|
|
19
|
+
s += "suffix"
|
|
20
|
+
return s
|
|
21
|
+
}
|