@herbertgao/pi-extensions 2026.8.6 → 2026.8.8
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +8 -6
- package/node_modules/@herbertgao/pi-cc-extensions/README.en.md +2 -2
- package/node_modules/@herbertgao/pi-cc-extensions/README.md +2 -2
- package/node_modules/@herbertgao/pi-cc-extensions/extensions/config/config.ts +19 -7
- package/node_modules/@herbertgao/pi-cc-extensions/extensions/config/panel.ts +30 -9
- package/node_modules/@herbertgao/pi-cc-extensions/extensions/feature/compact-thinking.ts +320 -22
- package/node_modules/@herbertgao/pi-cc-extensions/extensions/renderer/compact-mode.ts +94 -77
- package/node_modules/@herbertgao/pi-cc-extensions/extensions/renderer/message-display.ts +79 -17
- package/node_modules/@herbertgao/pi-cc-extensions/extensions/renderer/mouse/hover.ts +27 -0
- package/node_modules/@herbertgao/pi-cc-extensions/extensions/renderer/mouse/interaction.ts +66 -17
- package/node_modules/@herbertgao/pi-cc-extensions/extensions/renderer/mouse/layout.ts +41 -2
- package/node_modules/@herbertgao/pi-cc-extensions/extensions/renderer/tool/diff/diff-renderer.ts +75 -6
- package/node_modules/@herbertgao/pi-cc-extensions/extensions/renderer/tool/diff/types.ts +7 -3
- package/node_modules/@herbertgao/pi-cc-extensions/extensions/renderer/tool/grouping.ts +64 -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/README.md +30 -22
- package/node_modules/@herbertgao/pi-subagents/examples/agent-tool-description.md +5 -5
- package/node_modules/@herbertgao/pi-subagents/package.json +7 -7
- package/node_modules/@herbertgao/pi-subagents/src/agent-file-toggle.ts +7 -1
- package/node_modules/@herbertgao/pi-subagents/src/agent-manager.ts +48 -19
- package/node_modules/@herbertgao/pi-subagents/src/agent-runner.ts +17 -13
- package/node_modules/@herbertgao/pi-subagents/src/custom-agents.ts +26 -2
- package/node_modules/@herbertgao/pi-subagents/src/index.ts +219 -40
- package/node_modules/@herbertgao/pi-subagents/src/invocation-config.ts +101 -3
- package/node_modules/@herbertgao/pi-subagents/src/nested-tools.ts +18 -4
- package/node_modules/@herbertgao/pi-subagents/src/settings.ts +99 -0
- package/node_modules/@herbertgao/pi-subagents/src/types.ts +22 -3
- package/node_modules/@herbertgao/pi-subagents/src/ui/agent-widget.ts +51 -3
- package/node_modules/@herbertgao/pi-subagents/src/ui/conversation-viewer.ts +20 -2
- package/node_modules/@herbertgao/pi-subagents/src/ui/fleet-list.ts +21 -6
- package/node_modules/@herbertgao/pi-subagents/src/usage.ts +129 -1
- package/node_modules/@herbertgao/pi-subagents/src/worktree.ts +20 -0
- package/node_modules/@juicesharp/rpiv-ask-user-question/README.md +5 -4
- package/node_modules/@juicesharp/rpiv-ask-user-question/ask-user-question.ts +174 -100
- package/node_modules/@juicesharp/rpiv-ask-user-question/config.ts +25 -0
- package/node_modules/@juicesharp/rpiv-ask-user-question/docs/configuration.md +13 -4
- package/node_modules/@juicesharp/rpiv-ask-user-question/docs/hosts.md +5 -1
- package/node_modules/@juicesharp/rpiv-ask-user-question/docs/keyboard.md +10 -2
- package/node_modules/@juicesharp/rpiv-ask-user-question/docs/localization.md +10 -6
- package/node_modules/@juicesharp/rpiv-ask-user-question/docs/tool-schema.md +11 -5
- package/node_modules/@juicesharp/rpiv-ask-user-question/locales/en.json +5 -2
- package/node_modules/@juicesharp/rpiv-ask-user-question/locales/zh.json +2 -2
- package/node_modules/@juicesharp/rpiv-ask-user-question/package.json +3 -2
- package/node_modules/@juicesharp/rpiv-ask-user-question/state/build-questionnaire.ts +10 -0
- package/node_modules/@juicesharp/rpiv-ask-user-question/state/key-router.ts +140 -97
- package/node_modules/@juicesharp/rpiv-ask-user-question/state/questionnaire-session.ts +63 -28
- package/node_modules/@juicesharp/rpiv-ask-user-question/state/selectors/projections.ts +22 -15
- package/node_modules/@juicesharp/rpiv-ask-user-question/state/state-reducer.ts +11 -1
- package/node_modules/@juicesharp/rpiv-ask-user-question/state/state.ts +14 -6
- package/node_modules/@juicesharp/rpiv-ask-user-question/tool/response-envelope.ts +11 -0
- package/node_modules/@juicesharp/rpiv-ask-user-question/tool/types.ts +11 -0
- package/node_modules/@juicesharp/rpiv-ask-user-question/view/components/multi-select-view.ts +31 -17
- package/node_modules/@juicesharp/rpiv-ask-user-question/view/components/preview/preview-block-renderer.ts +15 -6
- package/node_modules/@juicesharp/rpiv-ask-user-question/view/components/wrapping-select.ts +15 -6
- package/node_modules/@juicesharp/rpiv-ask-user-question/view/dialog-builder.ts +86 -38
- package/node_modules/@juicesharp/rpiv-ask-user-question/view/tab-content-strategy.ts +76 -9
- package/node_modules/@narumitw/pi-btw/README.md +120 -111
- package/node_modules/@narumitw/pi-btw/dist/index.ts +2898 -0
- package/node_modules/@narumitw/pi-btw/dist/index.ts.map +7 -0
- package/node_modules/@narumitw/pi-btw/package.json +10 -6
- package/node_modules/@narumitw/pi-btw/src/btw.ts +36 -40
- package/node_modules/@narumitw/pi-btw/src/fullscreen-ui.ts +55 -10
- package/node_modules/@narumitw/pi-btw/src/main-tree-picker.ts +390 -0
- package/node_modules/@narumitw/pi-btw/src/menu.ts +45 -2
- package/node_modules/@narumitw/pi-btw/src/transcript-pager.ts +136 -45
- package/node_modules/@pi-plugins/fast-mode/dist/index.mjs +44 -1856
- package/node_modules/@pi-plugins/fast-mode/dist/index.mjs.map +1 -1
- package/node_modules/@pi-plugins/fast-mode/package.json +4 -6
- package/node_modules/pi-lens/CHANGELOG.md +999 -0
- package/node_modules/pi-lens/README.md +117 -3
- package/node_modules/pi-lens/config/ruff/core.toml +42 -0
- package/node_modules/pi-lens/dist/clients/actionable-warnings.js +130 -27
- package/node_modules/pi-lens/dist/clients/advisory-provenance.js +126 -13
- package/node_modules/pi-lens/dist/clients/agent-nudge.js +67 -11
- package/node_modules/pi-lens/dist/clients/ast-grep-client.js +9 -3
- package/node_modules/pi-lens/dist/clients/atomic-write.js +9 -3
- package/node_modules/pi-lens/dist/clients/bash-file-access.js +381 -13
- package/node_modules/pi-lens/dist/clients/biome-client.js +61 -30
- package/node_modules/pi-lens/dist/clients/blocker-freshness.js +428 -0
- package/node_modules/pi-lens/dist/clients/blocker-past-eof.js +129 -0
- package/node_modules/pi-lens/dist/clients/bootstrap.js +12 -1
- package/node_modules/pi-lens/dist/clients/bounded-pid-file-lock.js +12 -3
- package/node_modules/pi-lens/dist/clients/bounded-telemetry.js +206 -0
- package/node_modules/pi-lens/dist/clients/cache-observability.js +353 -76
- package/node_modules/pi-lens/dist/clients/cascade-budget.js +196 -0
- package/node_modules/pi-lens/dist/clients/cascade-format.js +20 -1
- package/node_modules/pi-lens/dist/clients/cascade-types.js +9 -1
- package/node_modules/pi-lens/dist/clients/child-unref.js +54 -6
- package/node_modules/pi-lens/dist/clients/code-quality-warnings.js +76 -24
- package/node_modules/pi-lens/dist/clients/dead-code-client.js +123 -31
- package/node_modules/pi-lens/dist/clients/deadline-utils.js +8 -1
- package/node_modules/pi-lens/dist/clients/debug-handles.js +5 -0
- package/node_modules/pi-lens/dist/clients/degradation-ledger.js +84 -14
- package/node_modules/pi-lens/dist/clients/demoted-finding-render.js +155 -0
- package/node_modules/pi-lens/dist/clients/dependency-checker.js +25 -3
- package/node_modules/pi-lens/dist/clients/deps/pi-tui.js +8 -2
- package/node_modules/pi-lens/dist/clients/deps/typebox.js +8 -3
- package/node_modules/pi-lens/dist/clients/diagnostic-dispositions.js +147 -33
- package/node_modules/pi-lens/dist/clients/diagnostic-line-freshness.js +298 -0
- package/node_modules/pi-lens/dist/clients/dispatch/dispatcher.js +52 -2
- package/node_modules/pi-lens/dist/clients/dispatch/integration.js +256 -88
- package/node_modules/pi-lens/dist/clients/dispatch/lazy.js +7 -4
- package/node_modules/pi-lens/dist/clients/dispatch/plan.js +5 -0
- package/node_modules/pi-lens/dist/clients/dispatch/runners/ast-grep-napi.js +234 -18
- package/node_modules/pi-lens/dist/clients/dispatch/runners/biome-check.js +187 -19
- package/node_modules/pi-lens/dist/clients/dispatch/runners/cpp-check.js +6 -3
- package/node_modules/pi-lens/dist/clients/dispatch/runners/credo.js +11 -9
- package/node_modules/pi-lens/dist/clients/dispatch/runners/cue-vet.js +398 -0
- package/node_modules/pi-lens/dist/clients/dispatch/runners/detekt.js +9 -6
- package/node_modules/pi-lens/dist/clients/dispatch/runners/elixir-check.js +11 -3
- package/node_modules/pi-lens/dist/clients/dispatch/runners/eslint.js +12 -7
- package/node_modules/pi-lens/dist/clients/dispatch/runners/go-vet.js +18 -0
- package/node_modules/pi-lens/dist/clients/dispatch/runners/hadolint.js +9 -7
- package/node_modules/pi-lens/dist/clients/dispatch/runners/helm-render.js +895 -0
- package/node_modules/pi-lens/dist/clients/dispatch/runners/htmlhint.js +8 -6
- package/node_modules/pi-lens/dist/clients/dispatch/runners/index.js +4 -0
- package/node_modules/pi-lens/dist/clients/dispatch/runners/javac.js +16 -3
- package/node_modules/pi-lens/dist/clients/dispatch/runners/lsp.js +60 -53
- package/node_modules/pi-lens/dist/clients/dispatch/runners/markdownlint.js +16 -2
- package/node_modules/pi-lens/dist/clients/dispatch/runners/mypy.js +25 -2
- package/node_modules/pi-lens/dist/clients/dispatch/runners/oxlint.js +20 -5
- package/node_modules/pi-lens/dist/clients/dispatch/runners/phpstan.js +44 -11
- package/node_modules/pi-lens/dist/clients/dispatch/runners/psscriptanalyzer.js +331 -55
- package/node_modules/pi-lens/dist/clients/dispatch/runners/pyright.js +38 -5
- package/node_modules/pi-lens/dist/clients/dispatch/runners/rust-clippy.js +97 -19
- package/node_modules/pi-lens/dist/clients/dispatch/runners/spellcheck.js +17 -8
- package/node_modules/pi-lens/dist/clients/dispatch/runners/sqlfluff.js +32 -4
- package/node_modules/pi-lens/dist/clients/dispatch/runners/stylelint.js +47 -3
- package/node_modules/pi-lens/dist/clients/dispatch/runners/swiftlint.js +14 -4
- package/node_modules/pi-lens/dist/clients/dispatch/runners/taplo.js +127 -28
- package/node_modules/pi-lens/dist/clients/dispatch/runners/tflint.js +12 -7
- package/node_modules/pi-lens/dist/clients/dispatch/runners/trivy-config.js +73 -12
- package/node_modules/pi-lens/dist/clients/dispatch/runners/utils/availability-policy.js +275 -13
- package/node_modules/pi-lens/dist/clients/dispatch/runners/utils/candidate-probe.js +21 -6
- package/node_modules/pi-lens/dist/clients/dispatch/runners/utils/lazy-installer.js +260 -27
- package/node_modules/pi-lens/dist/clients/dispatch/runners/utils/runner-helpers.js +734 -64
- package/node_modules/pi-lens/dist/clients/dispatch/runners/utils/spawn-outcome.js +86 -11
- package/node_modules/pi-lens/dist/clients/dispatch/runners/utils/tool-failure.js +188 -0
- package/node_modules/pi-lens/dist/clients/dispatch/runners/utils/toolchain-availability.js +9 -0
- package/node_modules/pi-lens/dist/clients/dispatch/runners/vale.js +21 -10
- package/node_modules/pi-lens/dist/clients/dispatch/runners/yamllint.js +18 -2
- package/node_modules/pi-lens/dist/clients/dispatch/runners/zig-check.js +4 -2
- package/node_modules/pi-lens/dist/clients/event-loop-monitor.js +28 -5
- package/node_modules/pi-lens/dist/clients/extension-log.js +22 -1
- package/node_modules/pi-lens/dist/clients/file-kinds.js +8 -2
- package/node_modules/pi-lens/dist/clients/finding-delivery-gate.js +316 -0
- package/node_modules/pi-lens/dist/clients/finding-identity.js +88 -0
- package/node_modules/pi-lens/dist/clients/formatters-lazy.js +3 -2
- package/node_modules/pi-lens/dist/clients/formatters.js +500 -115
- package/node_modules/pi-lens/dist/clients/generation-guard.js +216 -0
- package/node_modules/pi-lens/dist/clients/git-guard.js +31 -0
- package/node_modules/pi-lens/dist/clients/gitleaks-client.js +181 -8
- package/node_modules/pi-lens/dist/clients/govulncheck-client.js +109 -9
- package/node_modules/pi-lens/dist/clients/grammar-source.js +333 -10
- package/node_modules/pi-lens/dist/clients/host-ports.js +8 -0
- package/node_modules/pi-lens/dist/clients/installer/index.js +1114 -100
- package/node_modules/pi-lens/dist/clients/installer/managed-tool-refresh-session.js +58 -0
- package/node_modules/pi-lens/dist/clients/installer/managed-tool-refresh.js +715 -0
- package/node_modules/pi-lens/dist/clients/instance-reaper.js +643 -97
- package/node_modules/pi-lens/dist/clients/instance-registry.js +87 -17
- package/node_modules/pi-lens/dist/clients/jscpd-client.js +87 -8
- package/node_modules/pi-lens/dist/clients/knip-client.js +310 -10
- package/node_modules/pi-lens/dist/clients/language-policy.js +8 -2
- package/node_modules/pi-lens/dist/clients/language-profile.js +9 -2
- package/node_modules/pi-lens/dist/clients/latency-logger.js +440 -11
- package/node_modules/pi-lens/dist/clients/lazy-import.js +21 -0
- package/node_modules/pi-lens/dist/clients/ledger-bounds.js +21 -0
- package/node_modules/pi-lens/dist/clients/lens-flag-registry.js +8 -0
- package/node_modules/pi-lens/dist/clients/lsp/cascade-tier.js +128 -8
- package/node_modules/pi-lens/dist/clients/lsp/client.js +1660 -164
- package/node_modules/pi-lens/dist/clients/lsp/diagnostic-binding.js +83 -1
- package/node_modules/pi-lens/dist/clients/lsp/document-drift.js +389 -0
- package/node_modules/pi-lens/dist/clients/lsp/index.js +2423 -151
- package/node_modules/pi-lens/dist/clients/lsp/inferred-project.js +215 -0
- package/node_modules/pi-lens/dist/clients/lsp/jvm-runtime.js +146 -14
- package/node_modules/pi-lens/dist/clients/lsp/language.js +48 -4
- package/node_modules/pi-lens/dist/clients/lsp/server.js +277 -16
- package/node_modules/pi-lens/dist/clients/lsp/spawn-history.js +22 -0
- package/node_modules/pi-lens/dist/clients/lsp/sync-kind.js +43 -0
- package/node_modules/pi-lens/dist/clients/lsp/tsserver-sync.js +79 -3
- package/node_modules/pi-lens/dist/clients/lsp/wait-policy/strategies.js +43 -0
- package/node_modules/pi-lens/dist/clients/lsp/workspace-diagnostics-cache.js +422 -28
- package/node_modules/pi-lens/dist/clients/lsp/workspace-diagnostics-session.js +30 -0
- package/node_modules/pi-lens/dist/clients/lsp/workspace-sweep-hold.js +175 -0
- package/node_modules/pi-lens/dist/clients/lsp-lazy.js +3 -2
- package/node_modules/pi-lens/dist/clients/mcp/session.js +10 -2
- package/node_modules/pi-lens/dist/clients/module-report.js +22 -1
- package/node_modules/pi-lens/dist/clients/ndjson-logger.js +114 -23
- package/node_modules/pi-lens/dist/clients/opengrep-client.js +15 -1
- package/node_modules/pi-lens/dist/clients/package-manager.js +170 -14
- package/node_modules/pi-lens/dist/clients/path-attribution-telemetry.js +27 -0
- package/node_modules/pi-lens/dist/clients/path-utils.js +160 -0
- package/node_modules/pi-lens/dist/clients/pipeline.js +154 -33
- package/node_modules/pi-lens/dist/clients/post-autofix-notice.js +37 -0
- package/node_modules/pi-lens/dist/clients/project-diagnostics/cache.js +17 -3
- package/node_modules/pi-lens/dist/clients/project-diagnostics/extractors.js +89 -22
- package/node_modules/pi-lens/dist/clients/project-diagnostics/fresh-fetch.js +84 -14
- package/node_modules/pi-lens/dist/clients/project-diagnostics/runner-adapters/gitleaks.js +15 -3
- package/node_modules/pi-lens/dist/clients/project-diagnostics/runner-adapters/trivy.js +50 -2
- package/node_modules/pi-lens/dist/clients/project-diagnostics/scanner.js +23 -9
- package/node_modules/pi-lens/dist/clients/project-lens-config.js +3 -0
- package/node_modules/pi-lens/dist/clients/project-report.js +62 -27
- package/node_modules/pi-lens/dist/clients/project-snapshot.js +299 -0
- package/node_modules/pi-lens/dist/clients/quiet-window-config.js +47 -0
- package/node_modules/pi-lens/dist/clients/quiet-window.js +11 -25
- package/node_modules/pi-lens/dist/clients/read-guard-logger.js +8 -3
- package/node_modules/pi-lens/dist/clients/read-guard.js +253 -10
- package/node_modules/pi-lens/dist/clients/resource-sampler.js +49 -17
- package/node_modules/pi-lens/dist/clients/reverse-deps.js +50 -11
- package/node_modules/pi-lens/dist/clients/review-graph/builder.js +194 -31
- package/node_modules/pi-lens/dist/clients/review-graph/query.js +52 -4
- package/node_modules/pi-lens/dist/clients/review-graph/revision-drift.js +21 -0
- package/node_modules/pi-lens/dist/clients/review-graph/workspace-modules.js +6 -3
- package/node_modules/pi-lens/dist/clients/runtime-agent-end.js +96 -7
- package/node_modules/pi-lens/dist/clients/runtime-context.js +8 -1
- package/node_modules/pi-lens/dist/clients/runtime-coordinator.js +352 -45
- package/node_modules/pi-lens/dist/clients/runtime-session.js +373 -9
- package/node_modules/pi-lens/dist/clients/runtime-tool-call.js +217 -22
- package/node_modules/pi-lens/dist/clients/runtime-tool-result.js +212 -79
- package/node_modules/pi-lens/dist/clients/runtime-turn.js +620 -67
- package/node_modules/pi-lens/dist/clients/safe-spawn.js +220 -7
- package/node_modules/pi-lens/dist/clients/scratch-tree-policy.js +161 -0
- package/node_modules/pi-lens/dist/clients/search-read-registration.js +34 -6
- package/node_modules/pi-lens/dist/clients/security-scan-client.js +157 -24
- package/node_modules/pi-lens/dist/clients/session-event-guard.js +184 -0
- package/node_modules/pi-lens/dist/clients/sg-runner.js +116 -22
- package/node_modules/pi-lens/dist/clients/single-flight.js +158 -0
- package/node_modules/pi-lens/dist/clients/source-filter.js +6 -2
- package/node_modules/pi-lens/dist/clients/stale-marker.js +17 -0
- package/node_modules/pi-lens/dist/clients/startup-scan.js +5 -2
- package/node_modules/pi-lens/dist/clients/startup-timing.js +19 -1
- package/node_modules/pi-lens/dist/clients/test-runner-client.js +151 -16
- package/node_modules/pi-lens/dist/clients/tool-event.js +56 -5
- package/node_modules/pi-lens/dist/clients/tool-policy.js +125 -20
- package/node_modules/pi-lens/dist/clients/tree-sitter-cache.js +75 -1
- package/node_modules/pi-lens/dist/clients/tree-sitter-client.js +769 -64
- package/node_modules/pi-lens/dist/clients/tree-sitter-logger.js +1 -0
- package/node_modules/pi-lens/dist/clients/tree-sitter-shared.js +11 -0
- package/node_modules/pi-lens/dist/clients/tree-sitter-symbol-extractor.js +90 -0
- package/node_modules/pi-lens/dist/clients/trivy-client.js +19 -1
- package/node_modules/pi-lens/dist/clients/widget-state.js +336 -36
- package/node_modules/pi-lens/dist/clients/zizmor-config.js +214 -14
- package/node_modules/pi-lens/dist/index.js +61407 -48577
- package/node_modules/pi-lens/dist/tools/lens-diagnostics.js +476 -57
- package/node_modules/pi-lens/dist/tools/lsp-diagnostics.js +132 -43
- package/node_modules/pi-lens/dist/tools/lsp-navigation.js +46 -7
- package/node_modules/pi-lens/docs/agent-guide.md +6 -1
- package/node_modules/pi-lens/docs/ast-grep_rules_catalog.md +515 -506
- package/node_modules/pi-lens/docs/dispositions.md +21 -0
- package/node_modules/pi-lens/docs/features.md +19 -5
- package/node_modules/pi-lens/docs/globalconfig.md +3 -0
- package/node_modules/pi-lens/docs/language-coverage.md +71 -5
- package/node_modules/pi-lens/docs/mcp.md +2 -2
- package/node_modules/pi-lens/docs/servercapabilities.md +4 -1
- package/node_modules/pi-lens/docs/settings.md +19 -1
- package/node_modules/pi-lens/docs/usage.md +1 -0
- package/node_modules/pi-lens/package.json +27 -10
- package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/__snapshots__/no-reflect-get-js-snapshot.yml +23 -0
- package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/__snapshots__/no-reflect-get-snapshot.yml +23 -0
- package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/__snapshots__/ts-void-zero-snapshot.yml +23 -0
- package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/no-bare-object-param-test.yml +16 -0
- package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/no-chained-type-assertions-test.yml +15 -1
- package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/no-compile-call-test.yml +29 -1
- package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/no-dupe-class-members-test.yml +33 -0
- package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/no-inner-html-js-test.yml +7 -1
- package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/no-inner-html-test.yml +7 -1
- package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/no-known-value-widening-test.yml +9 -0
- package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/no-non-null-assertion-test.yml +216 -0
- package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/no-reflect-apply-js-test.yml +2 -0
- package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/no-reflect-apply-test.yml +2 -0
- package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/no-reflect-get-js-test.yml +2 -1
- package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/no-reflect-get-test.yml +2 -1
- package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/no-return-value-in-generator-test.yml +12 -0
- package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/no-runtime-typeof-test.yml +33 -0
- package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/no-server-bind-wildcard-test.yml +9 -0
- package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/no-shape-in-symbol-names-test.yml +13 -0
- package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/no-sql-in-code-js-test.yml +5 -1
- package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/no-sql-in-code-test.yml +5 -1
- package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/no-unknown-parameters-test.yml +12 -0
- package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/no-unknown-returns-test.yml +16 -0
- package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/no-unsafe-dictionary-any-test.yml +10 -0
- package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/no-unsafe-dictionary-unknown-test.yml +8 -0
- package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/redundant-unsafe-function-test.yml +35 -0
- package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/require-safety-comment-for-as-unknown-as-test.yml +177 -0
- package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/ts-void-zero-test.yml +1 -0
- package/node_modules/pi-lens/rules/ast-grep-rules/rules/no-await-expression-member-js.yml +13 -2
- package/node_modules/pi-lens/rules/ast-grep-rules/rules/no-await-expression-member.yml +13 -2
- package/node_modules/pi-lens/rules/ast-grep-rules/rules/no-bare-host-path-in-win32-branch.yml +2 -0
- package/node_modules/pi-lens/rules/ast-grep-rules/rules/no-bare-object-param.yml +60 -0
- package/node_modules/pi-lens/rules/ast-grep-rules/rules/no-chained-type-assertions.yml +57 -12
- package/node_modules/pi-lens/rules/ast-grep-rules/rules/no-compile-call.yml +63 -5
- package/node_modules/pi-lens/rules/ast-grep-rules/rules/no-dupe-class-members.yml +52 -8
- package/node_modules/pi-lens/rules/ast-grep-rules/rules/no-inner-html-js.yml +27 -2
- package/node_modules/pi-lens/rules/ast-grep-rules/rules/no-inner-html.yml +27 -2
- package/node_modules/pi-lens/rules/ast-grep-rules/rules/no-known-value-widening.yml +71 -0
- package/node_modules/pi-lens/rules/ast-grep-rules/rules/no-non-null-assertion.yml +316 -0
- package/node_modules/pi-lens/rules/ast-grep-rules/rules/no-raw-json-store-write.yml +7 -0
- package/node_modules/pi-lens/rules/ast-grep-rules/rules/no-reflect-apply-js.yml +22 -2
- package/node_modules/pi-lens/rules/ast-grep-rules/rules/no-reflect-apply.yml +23 -2
- package/node_modules/pi-lens/rules/ast-grep-rules/rules/no-reflect-get-js.yml +33 -5
- package/node_modules/pi-lens/rules/ast-grep-rules/rules/no-reflect-get.yml +34 -8
- package/node_modules/pi-lens/rules/ast-grep-rules/rules/no-return-value-in-generator.yml +22 -5
- package/node_modules/pi-lens/rules/ast-grep-rules/rules/no-runtime-typeof.yml +121 -0
- package/node_modules/pi-lens/rules/ast-grep-rules/rules/no-server-bind-wildcard.yml +23 -7
- package/node_modules/pi-lens/rules/ast-grep-rules/rules/no-shape-in-symbol-names.yml +68 -0
- package/node_modules/pi-lens/rules/ast-grep-rules/rules/no-sql-in-code-js.yml +41 -2
- package/node_modules/pi-lens/rules/ast-grep-rules/rules/no-sql-in-code.yml +41 -2
- package/node_modules/pi-lens/rules/ast-grep-rules/rules/no-unknown-laundering.yml +6 -1
- package/node_modules/pi-lens/rules/ast-grep-rules/rules/no-unknown-parameters.yml +67 -0
- package/node_modules/pi-lens/rules/ast-grep-rules/rules/no-unknown-returns.yml +106 -0
- package/node_modules/pi-lens/rules/ast-grep-rules/rules/no-unsafe-dictionary-any.yml +50 -0
- package/node_modules/pi-lens/rules/ast-grep-rules/rules/no-unsafe-dictionary-unknown.yml +56 -0
- package/node_modules/pi-lens/rules/ast-grep-rules/rules/no-win32-isabsolute-for-qualification.yml +2 -0
- package/node_modules/pi-lens/rules/ast-grep-rules/rules/redundant-unsafe-function.yml +32 -0
- package/node_modules/pi-lens/rules/ast-grep-rules/rules/require-safety-comment-for-as-unknown-as.yml +184 -0
- package/node_modules/pi-lens/rules/ast-grep-rules/rules/ts-void-zero.yml +5 -0
- package/node_modules/pi-lens/rules/ast-grep-rules/self-scan-baseline.json +5 -0
- package/node_modules/pi-lens/scripts/analyze-pi-lens-logs.mjs +53 -1
- package/node_modules/pi-lens/scripts/download-grammars.js +25 -0
- package/node_modules/pi-lens/scripts/grammars.lock.json +9 -0
- package/node_modules/pi-lens/scripts/install-selftest.mjs +99 -11
- package/node_modules/pi-lens/scripts/lib/host-provided-deps.mjs +75 -0
- package/node_modules/pi-lens/scripts/lib/warm-loader-cache.mjs +285 -0
- package/node_modules/pi-lens/scripts/warm-loader-cache.mjs +233 -0
- package/node_modules/pi-lens/skills/pi-lens-ast-grep/SKILL.md +2 -0
- package/node_modules/pi-lens/skills/pi-lens-write-ast-grep-rule/SKILL.md +80 -3
- package/node_modules/pi-lens/skills/pi-lens-write-ast-grep-rule/reference.md +41 -0
- package/node_modules/pi-lens/vendor/grammars/tree-sitter-cue.wasm +0 -0
- package/node_modules/pi-mcp-adapter/CHANGELOG.md +36 -0
- package/node_modules/pi-mcp-adapter/README.md +47 -5
- package/node_modules/pi-mcp-adapter/cli.js +163 -1
- package/node_modules/pi-mcp-adapter/commands.ts +128 -22
- package/node_modules/pi-mcp-adapter/config.ts +25 -7
- package/node_modules/pi-mcp-adapter/direct-tools.ts +5 -4
- package/node_modules/pi-mcp-adapter/index.ts +219 -32
- package/node_modules/pi-mcp-adapter/init.ts +36 -4
- package/node_modules/pi-mcp-adapter/lifecycle.ts +315 -24
- package/node_modules/pi-mcp-adapter/mcp-auth-flow.ts +39 -6
- package/node_modules/pi-mcp-adapter/mcp-bearer-store.ts +387 -0
- package/node_modules/pi-mcp-adapter/mcp-callback-server.ts +27 -3
- package/node_modules/pi-mcp-adapter/mcp-code.ts +4 -0
- package/node_modules/pi-mcp-adapter/mcp-panel.ts +42 -13
- package/node_modules/pi-mcp-adapter/metadata-cache.ts +32 -21
- package/node_modules/pi-mcp-adapter/package-mcp-loader.ts +168 -0
- package/node_modules/pi-mcp-adapter/package.json +3 -1
- package/node_modules/pi-mcp-adapter/proxy-modes.ts +5 -4
- package/node_modules/pi-mcp-adapter/request-headers-command.ts +31 -37
- package/node_modules/pi-mcp-adapter/search-ranking.ts +92 -22
- package/node_modules/pi-mcp-adapter/server-manager.ts +140 -2
- package/node_modules/pi-mcp-adapter/session-recovery.ts +7 -0
- package/node_modules/pi-mcp-adapter/tool-approval.ts +15 -2
- package/node_modules/pi-mcp-adapter/tool-result-renderer.ts +44 -4
- package/node_modules/pi-mcp-adapter/types.ts +2 -0
- package/node_modules/pi-mcp-adapter/ui-server.ts +18 -16
- package/node_modules/pi-mcp-adapter/utils.ts +70 -0
- package/node_modules/pi-web-access/CHANGELOG.md +37 -0
- package/node_modules/pi-web-access/README.md +32 -13
- package/node_modules/pi-web-access/anysearch.ts +4 -2
- package/node_modules/pi-web-access/brave.ts +16 -4
- package/node_modules/pi-web-access/chrome-cookies.ts +86 -15
- package/node_modules/pi-web-access/curator-page.ts +6 -3
- package/node_modules/pi-web-access/curator-server.ts +4 -1
- package/node_modules/pi-web-access/data-uri-sanitize.ts +406 -0
- package/node_modules/pi-web-access/exa.ts +18 -7
- package/node_modules/pi-web-access/extract.ts +40 -5
- package/node_modules/pi-web-access/firecrawl.ts +18 -2
- package/node_modules/pi-web-access/gemini-search.ts +16 -4
- package/node_modules/pi-web-access/github-extract.ts +65 -36
- package/node_modules/pi-web-access/index.ts +60 -61
- package/node_modules/pi-web-access/openai-search.ts +17 -6
- package/node_modules/pi-web-access/package.json +1 -1
- package/node_modules/pi-web-access/page-query.ts +4 -2
- package/node_modules/pi-web-access/parallel-mcp.ts +249 -0
- package/node_modules/pi-web-access/parallel.ts +2 -2
- package/node_modules/pi-web-access/pdf-extract.ts +18 -5
- package/node_modules/pi-web-access/query-rewrite.ts +51 -0
- package/node_modules/pi-web-access/serper.ts +211 -0
- package/node_modules/pi-web-access/ssrf-protection.ts +12 -2
- package/node_modules/pi-web-access/summary-model-scope.ts +12 -4
- package/node_modules/pi-web-access/summary-review.ts +44 -22
- package/node_modules/pi-web-access/tavily.ts +16 -4
- package/node_modules/pi-web-access/utils.ts +87 -0
- package/node_modules/pi-web-access/valyu.ts +199 -0
- package/package.json +14 -14
|
@@ -0,0 +1,121 @@
|
|
|
1
|
+
id: no-runtime-typeof
|
|
2
|
+
language: TypeScript
|
|
3
|
+
severity: hint
|
|
4
|
+
message: "Runtime 'typeof' check — decode/parse the value at its I/O boundary, then branch on the domain value"
|
|
5
|
+
note: |
|
|
6
|
+
Adapted from dmmulroy/anti-slop's `no-runtime-typeof`
|
|
7
|
+
(src/rules/no-runtime-typeof.ts, MIT). Upstream's own
|
|
8
|
+
`allowInTypeGuards` option only exempts a `typeof` sitting inside a
|
|
9
|
+
function whose return type is a type predicate (`x is T`) — the 2026-
|
|
10
|
+
08-19 audit found that option alone doesn't rescue the rule for this
|
|
11
|
+
codebase (73 predicate functions out of 404 client hits), so this
|
|
12
|
+
port adds two more exemptions, informed by where the audit found the
|
|
13
|
+
remaining hits actually concentrated: third-party JSON/LSP wire
|
|
14
|
+
payloads decoded inside functions already named for that job
|
|
15
|
+
(`trivy-client.ts`, `lsp/client.ts`, `git-guard.ts`).
|
|
16
|
+
|
|
17
|
+
Exemptions (all three must miss for a hit to fire):
|
|
18
|
+
1. `typeof` inside a function whose OWN return type is a type
|
|
19
|
+
predicate (`x is T`) — upstream's `allowInTypeGuards`.
|
|
20
|
+
2. `typeof` inside a function/method whose name starts with
|
|
21
|
+
`parse`, `decode`, `validate`, `is`, or `assert` — these are this
|
|
22
|
+
codebase's own naming convention for a boundary-parsing or
|
|
23
|
+
predicate function (`asRecord`, `errorMessage`), even when
|
|
24
|
+
TypeScript's `is`-predicate return-type syntax isn't used.
|
|
25
|
+
3. `.d.ts` files — declaration files have no runtime, so a `typeof`
|
|
26
|
+
there is a type query, not a check (the language keeps these
|
|
27
|
+
syntactically distinct in tree-sitter, but this glob is cheap
|
|
28
|
+
insurance).
|
|
29
|
+
|
|
30
|
+
These exemptions are structural, not semantic: they check the
|
|
31
|
+
ENCLOSING function's name/return-type, not what the `typeof` result
|
|
32
|
+
is actually used for, so a mis-named function (a real boundary
|
|
33
|
+
parser not named `parse*`, or a `checkFoo` predicate) still fires,
|
|
34
|
+
and a `parse*`-named function with an unrelated internal `typeof`
|
|
35
|
+
check is still exempted. `stopBy: end` searches to the nearest
|
|
36
|
+
enclosing function of that shape at ANY depth, which also exempts a
|
|
37
|
+
`typeof` inside a nested non-guard closure defined inside a guard —
|
|
38
|
+
a conservative (under-fires, not over-fires) choice.
|
|
39
|
+
|
|
40
|
+
Shipped at `hint`: the 2026-08-19 audit rejected outright adopting
|
|
41
|
+
this rule against pi-lens's own tree — it has no schema-decoding
|
|
42
|
+
library, and the concentration of hits is exactly where the rule
|
|
43
|
+
wants a schema layer (third-party JSON/LSP wire payloads), so
|
|
44
|
+
self-conformance would be an architecture decision, not a lint fix.
|
|
45
|
+
That verdict stands for pi-lens's own code; it doesn't mean the
|
|
46
|
+
pattern has no value for a repository that DOES have a decoder at its
|
|
47
|
+
boundaries. Self-scan note: do NOT try to make pi-lens's own tree
|
|
48
|
+
clean against this rule (#1718's baseline problem, likely never, per
|
|
49
|
+
the architecture-decision finding above); the adopting PR records the
|
|
50
|
+
2026-08-19 hit count so a rule that fires thousands of times against
|
|
51
|
+
its own product's source gets its pattern tightened before anyone
|
|
52
|
+
trusts the count on a real target repo.
|
|
53
|
+
|
|
54
|
+
2026-08-20 (refs #1727, #1777): CONSIDERED for promotion to `error`,
|
|
55
|
+
KEPT at `hint`. Four-corpus census, ast-grep CLI 0.45, with the three
|
|
56
|
+
exemptions above already applied:
|
|
57
|
+
|
|
58
|
+
| corpus | hits |
|
|
59
|
+
|---|---:|
|
|
60
|
+
| pi-lens `clients/` | 257 |
|
|
61
|
+
| pi-lens `tests/` | 232 |
|
|
62
|
+
| pi core `packages/` | 543 (431 outside test paths) |
|
|
63
|
+
| opencode `packages/` | 1122 (991) |
|
|
64
|
+
| oh-my-pi `packages/` | 4114 (3239) |
|
|
65
|
+
|
|
66
|
+
Verdict: the highest-volume rule in the whole catalog, and the volume is
|
|
67
|
+
not noise — it is the finding the note already records, that a codebase
|
|
68
|
+
without a decoding layer answers this rule with an architecture change.
|
|
69
|
+
The suppression the maintainer's own framing asks for ("suppress a
|
|
70
|
+
`typeof` whose checked binding comes from a source typed `unknown`")
|
|
71
|
+
needs the binding's declared type, which is type information ast-grep
|
|
72
|
+
does not have; the three exemptions here are the closest structural
|
|
73
|
+
approximation and they still leave 3,239 hits on one corpus. Promoting
|
|
74
|
+
at this volume would block agent turns across every one of these trees.
|
|
75
|
+
ignores:
|
|
76
|
+
- "**/*.d.ts"
|
|
77
|
+
rule:
|
|
78
|
+
kind: unary_expression
|
|
79
|
+
pattern: typeof $X
|
|
80
|
+
not:
|
|
81
|
+
any:
|
|
82
|
+
- inside:
|
|
83
|
+
stopBy: end
|
|
84
|
+
any:
|
|
85
|
+
- kind: function_declaration
|
|
86
|
+
- kind: function_expression
|
|
87
|
+
- kind: arrow_function
|
|
88
|
+
- kind: method_definition
|
|
89
|
+
has:
|
|
90
|
+
stopBy: neighbor
|
|
91
|
+
kind: type_annotation
|
|
92
|
+
has:
|
|
93
|
+
stopBy: neighbor
|
|
94
|
+
kind: type_predicate
|
|
95
|
+
- inside:
|
|
96
|
+
stopBy: end
|
|
97
|
+
kind: function_declaration
|
|
98
|
+
has:
|
|
99
|
+
stopBy: neighbor
|
|
100
|
+
kind: identifier
|
|
101
|
+
regex: '^(parse|decode|validate|is|assert)'
|
|
102
|
+
- inside:
|
|
103
|
+
stopBy: end
|
|
104
|
+
kind: function_expression
|
|
105
|
+
has:
|
|
106
|
+
stopBy: neighbor
|
|
107
|
+
kind: identifier
|
|
108
|
+
regex: '^(parse|decode|validate|is|assert)'
|
|
109
|
+
- inside:
|
|
110
|
+
stopBy: end
|
|
111
|
+
kind: method_definition
|
|
112
|
+
has:
|
|
113
|
+
stopBy: neighbor
|
|
114
|
+
kind: property_identifier
|
|
115
|
+
regex: '^(parse|decode|validate|is|assert)'
|
|
116
|
+
- inside:
|
|
117
|
+
stopBy: end
|
|
118
|
+
kind: variable_declarator
|
|
119
|
+
all:
|
|
120
|
+
- has: { stopBy: neighbor, kind: identifier, regex: '^(parse|decode|validate|is|assert)' }
|
|
121
|
+
- has: { stopBy: neighbor, kind: arrow_function }
|
|
@@ -9,14 +9,26 @@ note: |
|
|
|
9
9
|
network interface, including public ones. Production servers
|
|
10
10
|
should bind to a specific interface or use a reverse proxy.
|
|
11
11
|
|
|
12
|
-
Matches any `call` node whose text contains `host=` followed
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
12
|
+
Matches any `call` node whose text contains `host=` followed by
|
|
13
|
+
`0.0.0.0` (within a few characters). Note: `0.0.0.0` in `app.run()`
|
|
14
|
+
(Flask dev server) is also flagged — for development, prefer
|
|
15
|
+
`127.0.0.1`.
|
|
16
16
|
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
`
|
|
17
|
+
2026-08-20 (review round, refs #1806): a prior fix anchored this to
|
|
18
|
+
`.run(...)` / `.listen(...)` / `.serve(...)` call targets specifically,
|
|
19
|
+
to exclude a pydantic `Settings.model_construct(...)` test fixture
|
|
20
|
+
that happened to have a `host`-named field set to `"0.0.0.0"`. That
|
|
21
|
+
traded one false positive for a false-negative CLASS: a bare
|
|
22
|
+
`run(host='0.0.0.0')` (no receiver), `uvicorn.Config(app,
|
|
23
|
+
host='0.0.0.0')` (a different call name — the config object, not the
|
|
24
|
+
`.run()` invocation), and `app.run_server(...)` (a different method
|
|
25
|
+
name) all went invisible. For a BLOCKER-severity security rule, a
|
|
26
|
+
rare false positive is the acceptable trade, not a missed detection
|
|
27
|
+
class — reverted to the broad `kind: call` + regex match, and
|
|
28
|
+
excluded the SPECIFIC false-positive shape instead: a call to
|
|
29
|
+
`.model_construct(...)` / `.construct(...)` (pydantic's
|
|
30
|
+
validation-skipping constructors — the "this builds a config object,
|
|
31
|
+
it doesn't bind a socket" case the FP actually was).
|
|
20
32
|
|
|
21
33
|
The regex uses `.{0,5}` between `host` and `0.0.0.0` to
|
|
22
34
|
accept either `host='0.0.0.0'` (single quote) or
|
|
@@ -26,3 +38,7 @@ metadata:
|
|
|
26
38
|
rule:
|
|
27
39
|
kind: call
|
|
28
40
|
regex: 'host.{0,5}0\.0\.0\.0'
|
|
41
|
+
not:
|
|
42
|
+
any:
|
|
43
|
+
- pattern: $X.model_construct($$$ARGS)
|
|
44
|
+
- pattern: $X.construct($$$ARGS)
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
id: no-shape-in-symbol-names
|
|
2
|
+
language: TypeScript
|
|
3
|
+
severity: hint
|
|
4
|
+
message: "Symbol name contains 'shape' — name it for its domain role, not its structure"
|
|
5
|
+
note: |
|
|
6
|
+
Adapted from dmmulroy/anti-slop's `no-shape-in-symbol-names`
|
|
7
|
+
(src/rules/no-shape-in-symbol-names.ts, MIT). Upstream bans the
|
|
8
|
+
case-insensitive substring "shape" in every identifier, private
|
|
9
|
+
identifier, and JSX identifier: "shape" describes the STRUCTURE of a
|
|
10
|
+
value, not what it MEANS, and a name that only says "this has some
|
|
11
|
+
shape" (`PackageJsonShape`, `windowsShaped`) is filler a domain term
|
|
12
|
+
would replace (`PackageJsonManifest`, `usesWindowsSeparators`).
|
|
13
|
+
|
|
14
|
+
Explicitly NOT self-applied: AGENTS.md's own "Recurring defect shapes"
|
|
15
|
+
catalog uses "shape" as load-bearing review vocabulary, and pi-lens's
|
|
16
|
+
own code mirrors it — `ProbeFailureShape`, `windowsShaped`,
|
|
17
|
+
`basenameForShape`, 27 distinct identifiers / 291 occurrences in the
|
|
18
|
+
2026-08-19 audit. Banning the word in THIS repo would fight the
|
|
19
|
+
convention its own review process runs on. That is a reason not to
|
|
20
|
+
wire this rule into pi-lens's self-scan (#1718's decision to make),
|
|
21
|
+
not a reason to withhold it from the catalog — a repo without that
|
|
22
|
+
convention gets real signal from it. Self-scan note: do NOT try to
|
|
23
|
+
make pi-lens's own tree clean against this rule; the adopting PR
|
|
24
|
+
records the 2026-08-19 hit count instead.
|
|
25
|
+
|
|
26
|
+
Scope: `identifier`, `property_identifier`, `private_property_identifier`,
|
|
27
|
+
and `type_identifier` nodes whose text contains "shape"
|
|
28
|
+
case-insensitively, anywhere in the name (matches upstream's
|
|
29
|
+
substring semantics, so `reshape`/`Shapeless` are in scope too, not
|
|
30
|
+
just whole-word `shape`). `jsx_identifier` is dropped — this repo
|
|
31
|
+
ships no `.tsx`, so it has nothing to match (same call as
|
|
32
|
+
`no-unknown-laundering.yml`'s "no JS variant" note).
|
|
33
|
+
|
|
34
|
+
2026-08-20 (refs #1727, #1777): CONSIDERED for promotion to `error`,
|
|
35
|
+
KEPT at `hint`. Four-corpus census, ast-grep CLI 0.45:
|
|
36
|
+
|
|
37
|
+
| corpus | hits |
|
|
38
|
+
|---|---:|
|
|
39
|
+
| pi-lens `clients/` | 48 (13 distinct identifiers) |
|
|
40
|
+
| pi-lens `tests/` | 140 |
|
|
41
|
+
| pi core `packages/` | 5 (5 outside test paths, 1 file) |
|
|
42
|
+
| opencode `packages/` | 88 (76) |
|
|
43
|
+
| oh-my-pi `packages/` | 837 (608, 65 files) |
|
|
44
|
+
|
|
45
|
+
Verdict: structural scoping was applied and was not enough. Excluding
|
|
46
|
+
test paths — the mechanism this catalog now uses for
|
|
47
|
+
`require-safety-comment-for-as-unknown-as.yml` — removes pi-lens's 140
|
|
48
|
+
`tests/` hits and leaves all 48 `clients/` hits, because they are not a
|
|
49
|
+
test idiom. They are 13 production identifiers, several of them the
|
|
50
|
+
review vocabulary this repo runs on (`ProbeFailureShape`,
|
|
51
|
+
`basenameForShape`, `windowsShaped`, `checkManifestShape`,
|
|
52
|
+
`validateInputShape`) and one that is upstream's own headline example
|
|
53
|
+
(`PackageJsonShape`). The only ways to zero are an allowlist of pi-lens
|
|
54
|
+
identifiers baked into a rule that ships to other repositories — a
|
|
55
|
+
hand-maintained parallel list, which AGENTS.md forbids — or renaming 13
|
|
56
|
+
exported production symbols, which is a refactor with its own blast
|
|
57
|
+
radius and its own issue, not a severity change. Left at `hint` and
|
|
58
|
+
still NOT tagged for the self-scan.
|
|
59
|
+
rule:
|
|
60
|
+
any:
|
|
61
|
+
- kind: identifier
|
|
62
|
+
regex: "(?i)shape"
|
|
63
|
+
- kind: property_identifier
|
|
64
|
+
regex: "(?i)shape"
|
|
65
|
+
- kind: private_property_identifier
|
|
66
|
+
regex: "(?i)shape"
|
|
67
|
+
- kind: type_identifier
|
|
68
|
+
regex: "(?i)shape"
|
|
@@ -3,8 +3,9 @@ language: JavaScript
|
|
|
3
3
|
message: "Raw SQL string in code — use query builder or ORM"
|
|
4
4
|
severity: error
|
|
5
5
|
note: |
|
|
6
|
-
Raw SQL strings
|
|
7
|
-
Use a query builder (knex, drizzle)
|
|
6
|
+
Raw SQL strings built via concatenation or template substitution are
|
|
7
|
+
error-prone and open to injection. Use a query builder (knex, drizzle)
|
|
8
|
+
or ORM (prisma, typeorm), or pass the value as a bind parameter.
|
|
8
9
|
The `, $$$REST` suffix matches the optional parameters/options
|
|
9
10
|
argument common to ORM `query()`/`execute()` signatures. Without
|
|
10
11
|
it, only the 1-arg form (no params) matches.
|
|
@@ -12,6 +13,27 @@ note: |
|
|
|
12
13
|
because the SQL literal lives 2 levels below the call_expression
|
|
13
14
|
(inside `arguments`); the default `has` neighbor doesn't drill
|
|
14
15
|
that deep.
|
|
16
|
+
|
|
17
|
+
`$SQL` is constrained to a `binary_expression` (string concatenation,
|
|
18
|
+
e.g. `"SELECT ... " + id`) or a template string with at least one
|
|
19
|
+
`${...}` substitution — the two shapes that actually interpolate a
|
|
20
|
+
runtime value into the query text. A plain string literal (even one
|
|
21
|
+
containing a `?` placeholder passed alongside a params array — the
|
|
22
|
+
parameterized-query idiom) is NOT flagged: the query text itself is
|
|
23
|
+
static, so there's nothing to inject. Before this constraint, EVERY
|
|
24
|
+
`db.query("<literal SQL>")` call matched regardless of how the value
|
|
25
|
+
was passed, which is why the shipped rule produced 261 hits on a
|
|
26
|
+
correctly-parameterized DB layer (#1806 audit). Mirrors the Python
|
|
27
|
+
sibling `no-python-sql-string-concat`, which already restricted to
|
|
28
|
+
`binary_operator` concatenation.
|
|
29
|
+
|
|
30
|
+
2026-08-20 (review round, refs #1806, low-severity finding): a
|
|
31
|
+
`binary_expression` where BOTH sides are string literals
|
|
32
|
+
(`"SELECT * FROM " + "users"`) is compile-time-constant text, not
|
|
33
|
+
runtime interpolation — nothing to inject. Excluded via a `has:
|
|
34
|
+
field: left/right, kind: string` check on both operands. A
|
|
35
|
+
literal-plus-variable concatenation (the actual injection shape)
|
|
36
|
+
still flags.
|
|
15
37
|
rule:
|
|
16
38
|
all:
|
|
17
39
|
- any:
|
|
@@ -22,3 +44,20 @@ rule:
|
|
|
22
44
|
regex: >-
|
|
23
45
|
(?i)(SELECT|INSERT|UPDATE|DELETE|CREATE TABLE|DROP TABLE|ALTER
|
|
24
46
|
TABLE)
|
|
47
|
+
constraints:
|
|
48
|
+
SQL:
|
|
49
|
+
any:
|
|
50
|
+
- all:
|
|
51
|
+
- kind: binary_expression
|
|
52
|
+
- not:
|
|
53
|
+
all:
|
|
54
|
+
- has:
|
|
55
|
+
field: left
|
|
56
|
+
kind: string
|
|
57
|
+
- has:
|
|
58
|
+
field: right
|
|
59
|
+
kind: string
|
|
60
|
+
- all:
|
|
61
|
+
- kind: template_string
|
|
62
|
+
- has:
|
|
63
|
+
kind: template_substitution
|
|
@@ -3,8 +3,9 @@ language: TypeScript
|
|
|
3
3
|
message: "Raw SQL string in code — use query builder or ORM"
|
|
4
4
|
severity: error
|
|
5
5
|
note: |
|
|
6
|
-
Raw SQL strings
|
|
7
|
-
Use a query builder (knex, drizzle)
|
|
6
|
+
Raw SQL strings built via concatenation or template substitution are
|
|
7
|
+
error-prone and open to injection. Use a query builder (knex, drizzle)
|
|
8
|
+
or ORM (prisma, typeorm), or pass the value as a bind parameter.
|
|
8
9
|
The `, $$$REST` suffix matches the optional parameters/options
|
|
9
10
|
argument common to ORM `query()`/`execute()` signatures. Without
|
|
10
11
|
it, only the 1-arg form (no params) matches.
|
|
@@ -12,6 +13,27 @@ note: |
|
|
|
12
13
|
because the SQL literal lives 2 levels below the call_expression
|
|
13
14
|
(inside `arguments`); the default `has` neighbor doesn't drill
|
|
14
15
|
that deep.
|
|
16
|
+
|
|
17
|
+
`$SQL` is constrained to a `binary_expression` (string concatenation,
|
|
18
|
+
e.g. `"SELECT ... " + id`) or a template string with at least one
|
|
19
|
+
`${...}` substitution — the two shapes that actually interpolate a
|
|
20
|
+
runtime value into the query text. A plain string literal (even one
|
|
21
|
+
containing a `?` placeholder passed alongside a params array — the
|
|
22
|
+
parameterized-query idiom) is NOT flagged: the query text itself is
|
|
23
|
+
static, so there's nothing to inject. Before this constraint, EVERY
|
|
24
|
+
`db.query("<literal SQL>")` call matched regardless of how the value
|
|
25
|
+
was passed, which is why the shipped rule produced 261 hits on a
|
|
26
|
+
correctly-parameterized DB layer (#1806 audit). Mirrors the Python
|
|
27
|
+
sibling `no-python-sql-string-concat`, which already restricted to
|
|
28
|
+
`binary_operator` concatenation.
|
|
29
|
+
|
|
30
|
+
2026-08-20 (review round, refs #1806, low-severity finding): a
|
|
31
|
+
`binary_expression` where BOTH sides are string literals
|
|
32
|
+
(`"SELECT * FROM " + "users"`) is compile-time-constant text, not
|
|
33
|
+
runtime interpolation — nothing to inject. Excluded via a `has:
|
|
34
|
+
field: left/right, kind: string` check on both operands. A
|
|
35
|
+
literal-plus-variable concatenation (the actual injection shape)
|
|
36
|
+
still flags.
|
|
15
37
|
rule:
|
|
16
38
|
all:
|
|
17
39
|
- any:
|
|
@@ -22,3 +44,20 @@ rule:
|
|
|
22
44
|
regex: >-
|
|
23
45
|
(?i)(SELECT|INSERT|UPDATE|DELETE|CREATE TABLE|DROP TABLE|ALTER
|
|
24
46
|
TABLE)
|
|
47
|
+
constraints:
|
|
48
|
+
SQL:
|
|
49
|
+
any:
|
|
50
|
+
- all:
|
|
51
|
+
- kind: binary_expression
|
|
52
|
+
- not:
|
|
53
|
+
all:
|
|
54
|
+
- has:
|
|
55
|
+
field: left
|
|
56
|
+
kind: string
|
|
57
|
+
- has:
|
|
58
|
+
field: right
|
|
59
|
+
kind: string
|
|
60
|
+
- all:
|
|
61
|
+
- kind: template_string
|
|
62
|
+
- has:
|
|
63
|
+
kind: template_substitution
|
|
@@ -1,7 +1,9 @@
|
|
|
1
1
|
id: no-unknown-laundering
|
|
2
2
|
language: TypeScript
|
|
3
|
-
severity:
|
|
3
|
+
severity: error
|
|
4
4
|
message: "type alias to bare 'unknown' — give the alias real shape or inline 'unknown' at the one call site that needs it"
|
|
5
|
+
metadata:
|
|
6
|
+
category: pi-lens-self-scan
|
|
5
7
|
note: |
|
|
6
8
|
`type X = unknown` adds a name but zero type information — every
|
|
7
9
|
consumer of X still has to narrow from scratch, so the alias only
|
|
@@ -23,5 +25,8 @@ note: |
|
|
|
23
25
|
forces the caller to narrow — so it is not syntactically distinguishable
|
|
24
26
|
from a laundered one; only `type X = unknown` stayed a reliable
|
|
25
27
|
precision signal (zero hits in the same scan).
|
|
28
|
+
|
|
29
|
+
2026-08-20 (refs #1856): PROMOTED from `warning` to `error` after a
|
|
30
|
+
fresh scan confirmed zero hits in pi-lens's own tree.
|
|
26
31
|
rule:
|
|
27
32
|
pattern: "type $T = unknown"
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
id: no-unknown-parameters
|
|
2
|
+
language: TypeScript
|
|
3
|
+
severity: hint
|
|
4
|
+
message: "Parameter typed 'unknown' — decode it at the I/O boundary instead of leaving it unparsed"
|
|
5
|
+
note: |
|
|
6
|
+
Adapted from dmmulroy/anti-slop's `no-unknown-parameters`
|
|
7
|
+
(src/rules/no-unknown-parameters.ts, MIT). Upstream exempts a
|
|
8
|
+
parameter literally named `cause` (the standard `Error` cause-chain
|
|
9
|
+
field, which is `unknown` by the language's own `ErrorOptions` type)
|
|
10
|
+
— kept here for the same reason.
|
|
11
|
+
|
|
12
|
+
Shipped at `hint`, not `error`: AGENTS.md smell 3 records that this
|
|
13
|
+
exact arm was dropped from `no-unknown-laundering.yml` after an
|
|
14
|
+
FP-scan found 166 legitimate `unknown` parameters in pi-lens's own
|
|
15
|
+
tree (type-guard/validator functions like
|
|
16
|
+
`errorMessage(err: unknown)`). That finding is about THIS repo's own
|
|
17
|
+
code, not a reason to withhold the pattern from the shipped catalog —
|
|
18
|
+
other repositories may have real slop here — so it ships as a
|
|
19
|
+
discoverable hint instead. Self-scan note: do NOT try to make
|
|
20
|
+
pi-lens's own tree clean against this rule (#1718's baseline
|
|
21
|
+
problem); the adopting PR records the 2026-08-19 hit count instead.
|
|
22
|
+
|
|
23
|
+
Scope: a direct `unknown` annotation on a required or optional
|
|
24
|
+
parameter, matched structurally at the `predefined_type` leaf (same
|
|
25
|
+
shape as `no-bare-object-param.yml`). Rest/default-value parameters
|
|
26
|
+
(`...rest: unknown[]`, `x = y: unknown`) are out of scope — ast-grep
|
|
27
|
+
doesn't unwrap those parameter-pattern wrappers the way upstream's
|
|
28
|
+
AST-walk does. A union member (`unknown | null`) is not flagged for
|
|
29
|
+
the same "direct annotation only" reason `no-bare-object-param.yml`
|
|
30
|
+
gives.
|
|
31
|
+
|
|
32
|
+
2026-08-20 (refs #1727, #1777): CONSIDERED for promotion to `error`,
|
|
33
|
+
KEPT at `hint`. Four-corpus census, ast-grep CLI 0.45:
|
|
34
|
+
|
|
35
|
+
| corpus | hits |
|
|
36
|
+
|---|---:|
|
|
37
|
+
| pi-lens `clients/` | 149 |
|
|
38
|
+
| pi-lens `tests/` | 146 |
|
|
39
|
+
| pi core `packages/` | 381 (194 outside test paths) |
|
|
40
|
+
| opencode `packages/` | 678 (522) |
|
|
41
|
+
| oh-my-pi `packages/` | 2140 (1697) |
|
|
42
|
+
|
|
43
|
+
Verdict: structural narrowing was probed and does not reach zero. The
|
|
44
|
+
type-guard suppression (a parameter inside a function whose return type
|
|
45
|
+
is a `value is T` predicate) and a parser-name suppression together
|
|
46
|
+
clear the large predicate/validator block, but the residual is a second
|
|
47
|
+
legitimate class they cannot touch: opaque-payload SINKS that never
|
|
48
|
+
parse their argument at all — `setFileFact(path, id, value: unknown)`,
|
|
49
|
+
`bus(channel, payload: unknown)`, `emitLensEvent(name, payload:
|
|
50
|
+
unknown)`, `(err: unknown) => …` rejection handlers. `unknown` is the
|
|
51
|
+
CORRECT parameter type there, and it is syntactically identical to the
|
|
52
|
+
unparsed-boundary case the rule targets.
|
|
53
|
+
rule:
|
|
54
|
+
kind: predefined_type
|
|
55
|
+
regex: "^unknown$"
|
|
56
|
+
inside:
|
|
57
|
+
kind: type_annotation
|
|
58
|
+
inside:
|
|
59
|
+
all:
|
|
60
|
+
- any:
|
|
61
|
+
- kind: required_parameter
|
|
62
|
+
- kind: optional_parameter
|
|
63
|
+
- not:
|
|
64
|
+
has:
|
|
65
|
+
stopBy: neighbor
|
|
66
|
+
kind: identifier
|
|
67
|
+
regex: "^cause$"
|
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
id: no-unknown-returns
|
|
2
|
+
language: TypeScript
|
|
3
|
+
severity: error
|
|
4
|
+
message: "Function returns 'unknown' — parse the value at its boundary and return a named domain type"
|
|
5
|
+
metadata:
|
|
6
|
+
category: pi-lens-self-scan
|
|
7
|
+
note: |
|
|
8
|
+
Adapted from dmmulroy/anti-slop's `no-unknown-returns`
|
|
9
|
+
(src/rules/no-unknown-returns.ts, MIT). Upstream also resolves
|
|
10
|
+
`Promise<unknown>` and same-file type aliases that resolve to
|
|
11
|
+
`unknown`; both are dropped here — same-file alias/generic resolution
|
|
12
|
+
is out of ast-grep's reach (the `no-bare-object-param.yml` precedent).
|
|
13
|
+
|
|
14
|
+
Shipped at `hint`, not `error`: AGENTS.md smell 3 records that this
|
|
15
|
+
arm was dropped from `no-unknown-laundering.yml` after an FP-scan
|
|
16
|
+
found 192 legitimate `unknown` return types in pi-lens's own tree
|
|
17
|
+
(parsers, and a `ProxyHandler.get` trap whose signature TypeScript
|
|
18
|
+
itself requires). That's a finding about this repo's own code, not a
|
|
19
|
+
reason to withhold the pattern from the catalog, so it ships as a
|
|
20
|
+
discoverable hint. Self-scan note: do NOT try to make pi-lens's own
|
|
21
|
+
tree clean against this rule (#1718's baseline problem); the adopting
|
|
22
|
+
PR records the 2026-08-19 hit count instead.
|
|
23
|
+
|
|
24
|
+
Scope: a direct `unknown` return-type annotation, matched
|
|
25
|
+
structurally. Most function-like nodes wrap their return type in a
|
|
26
|
+
`type_annotation` node that is a DIRECT child of the function node
|
|
27
|
+
(function declaration/expression, arrow function, method signature/
|
|
28
|
+
definition, call/construct signature) — that is exactly the
|
|
29
|
+
return-type position; a parameter's `type_annotation` is nested one
|
|
30
|
+
level deeper, inside `required_parameter`/`optional_parameter`, so
|
|
31
|
+
the two never collide. `function_type` (`(x: T) => R`, used in
|
|
32
|
+
function-type aliases) was the one exception in
|
|
33
|
+
tree-sitter-typescript's grammar: its return type sits directly after
|
|
34
|
+
`=>` with no `type_annotation` wrapper at all, so it needed its own
|
|
35
|
+
branch. The #1824 scope correction removed that branch because callback
|
|
36
|
+
result types describe what callers consume, not an unparsed value crossing
|
|
37
|
+
a boundary. See the 2026-08-20 #1824 entry below for why that branch is
|
|
38
|
+
now gone.
|
|
39
|
+
|
|
40
|
+
2026-08-20 (refs #1727, #1777): CONSIDERED for promotion to `error`,
|
|
41
|
+
KEPT at `hint`. Four-corpus census, ast-grep CLI 0.45:
|
|
42
|
+
|
|
43
|
+
| corpus | hits |
|
|
44
|
+
|---|---:|
|
|
45
|
+
| pi-lens `clients/` | 19 |
|
|
46
|
+
| pi-lens `tests/` | 58 |
|
|
47
|
+
| pi core `packages/` | 17 (14 outside test paths) |
|
|
48
|
+
| opencode `packages/` | 111 (105) |
|
|
49
|
+
| oh-my-pi `packages/` | 288 (226) |
|
|
50
|
+
|
|
51
|
+
Verdict: the closest of the six to promotable, and still not there. A
|
|
52
|
+
probed narrowing — drop the `function_type` arm (a callback TYPE
|
|
53
|
+
declaring `=> unknown` says "the caller ignores my result", not "a
|
|
54
|
+
boundary went unparsed") plus a parser-name suppression — takes pi-lens
|
|
55
|
+
from 77 hits to 16, and `clients/` from 19 to 3. The residual 3 are
|
|
56
|
+
generic pass-through wrappers (`clients/extension-log.ts`'s console
|
|
57
|
+
capture and proxy wrapper) whose return value genuinely IS the wrapped
|
|
58
|
+
function's, so `unknown` is correct. Reaching zero needed a third
|
|
59
|
+
suppression shaped around those three sites specifically, which is
|
|
60
|
+
overfitting to one tree, so nothing was changed here. The
|
|
61
|
+
`function_type` scope question is worth its own issue on its own merits;
|
|
62
|
+
it is a scope correction, not a tier change, and this PR does not make
|
|
63
|
+
it.
|
|
64
|
+
|
|
65
|
+
2026-08-20 (#1824, refs #1727, #1815, review round 1 N4): dropped
|
|
66
|
+
the `function_type` arm named above. A TYPE-POSITION `unknown`
|
|
67
|
+
return is a legitimate contract ("the caller ignores my result"),
|
|
68
|
+
not a value-position return that skipped parsing at a boundary. This
|
|
69
|
+
is a scope correction, not a severity change. Same scan setup,
|
|
70
|
+
before → after: pi-lens full tree 79 → 23; pi-lens `clients/` +
|
|
71
|
+
`index.ts` 21 → 9 (see the adopting PR for the four-corpus
|
|
72
|
+
before/after on the same narrow scope). The value-position arm below
|
|
73
|
+
is unchanged and is what the rule now exclusively targets.
|
|
74
|
+
2026-08-20 (refs #1856): PROMOTED from `hint` to `error` after the
|
|
75
|
+
remaining value-position returns were given named domain types or made
|
|
76
|
+
generic so their pass-through contract stays exact. The pi-lens
|
|
77
|
+
self-scan is clean at promotion time.
|
|
78
|
+
Test paths stay excluded: mocks and interleaving controls intentionally
|
|
79
|
+
return opaque sentinel values, while this rule governs production
|
|
80
|
+
boundaries whose domain shape is knowable.
|
|
81
|
+
ignores:
|
|
82
|
+
- "**/*.test.ts"
|
|
83
|
+
- "**/*.test.tsx"
|
|
84
|
+
- "**/*.test.mts"
|
|
85
|
+
- "**/*.test.cts"
|
|
86
|
+
- "**/*.spec.ts"
|
|
87
|
+
- "**/*.spec.tsx"
|
|
88
|
+
- "**/tests/**"
|
|
89
|
+
- "**/test/**"
|
|
90
|
+
- "**/__tests__/**"
|
|
91
|
+
rule:
|
|
92
|
+
kind: predefined_type
|
|
93
|
+
regex: "^unknown$"
|
|
94
|
+
inside:
|
|
95
|
+
kind: type_annotation
|
|
96
|
+
inside:
|
|
97
|
+
any:
|
|
98
|
+
- kind: function_declaration
|
|
99
|
+
- kind: function_expression
|
|
100
|
+
- kind: generator_function_declaration
|
|
101
|
+
- kind: arrow_function
|
|
102
|
+
- kind: method_signature
|
|
103
|
+
- kind: method_definition
|
|
104
|
+
- kind: construct_signature
|
|
105
|
+
- kind: constructor_type
|
|
106
|
+
- kind: call_signature
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
id: no-unsafe-dictionary-any
|
|
2
|
+
language: TypeScript
|
|
3
|
+
severity: error
|
|
4
|
+
metadata:
|
|
5
|
+
category: pi-lens-self-scan
|
|
6
|
+
message: "Record<K, any> — the value type gives callers no contract; use Record<K, unknown> or a real value type"
|
|
7
|
+
note: |
|
|
8
|
+
Adapted from dmmulroy/anti-slop's `no-unsafe-dictionary-type`
|
|
9
|
+
(src/rules/no-unsafe-dictionary-type.ts, MIT), narrowed to the `any`
|
|
10
|
+
arm only. Upstream also flags `unknown`, bare `object`, `{}`, and
|
|
11
|
+
unions/aliases that resolve to one of those — this port drops all of
|
|
12
|
+
that (see the `no-unsafe-dictionary-unknown.yml` sibling for the
|
|
13
|
+
`unknown` arm, shipped separately at `hint`). `Record<K, any>` is the
|
|
14
|
+
one arm this repo's own FP scan (AGENTS.md smell 3) found ZERO
|
|
15
|
+
legitimate uses for: `any` as a dictionary's value type doesn't just
|
|
16
|
+
widen, it turns off checking for every property read off that
|
|
17
|
+
dictionary, which `unknown` does not do.
|
|
18
|
+
|
|
19
|
+
Scope: a direct `Record<$K, any>` type reference, matched
|
|
20
|
+
structurally — the same "direct annotation only" cut as
|
|
21
|
+
`no-bare-object-param.yml`. Upstream's alias-resolution and
|
|
22
|
+
type-literal-index-signature arms (`{ [key: string]: any }`,
|
|
23
|
+
an alias that resolves to `Record<string, any>`) are dropped for the
|
|
24
|
+
same reason: same-file symbol/generic resolution ast-grep doesn't do.
|
|
25
|
+
|
|
26
|
+
FP-scan (napi engine, clients/ + tests/, 2026-08-19): 4 hits, not the
|
|
27
|
+
2 the original audit measured — the audit's grep missed two test
|
|
28
|
+
files. `clients/cache/rule-cache.ts:81` and
|
|
29
|
+
`clients/tree-sitter-query-loader.ts:129` are genuine dictionary
|
|
30
|
+
value-type contracts (`post_filter_params?: Record<string, any>` on
|
|
31
|
+
loaded query metadata) and are fixed in the same PR to
|
|
32
|
+
`Record<string, unknown>` — every consumer already narrows manually
|
|
33
|
+
(`clients/tree-sitter-client.ts` takes `postFilterParams?: unknown`
|
|
34
|
+
or `any` as a local parameter type at the point it's actually
|
|
35
|
+
destructured, never relies on the interface field being `any`).
|
|
36
|
+
`tests/clients/call-graph.test.ts:736` and
|
|
37
|
+
`tests/tools/lens-diagnostics.test.ts:198` are a different shape:
|
|
38
|
+
ad-hoc mutation/access of a raw JSON fixture object
|
|
39
|
+
(`raw.edges[0].evidenceKind = "..."`, `props.mode.enum`) across
|
|
40
|
+
several unrelated nested paths, where `unknown` would require a cast
|
|
41
|
+
at every access and buys nothing — the same "test fixture shaping"
|
|
42
|
+
class already exempted for `require-safety-comment` and the empty-
|
|
43
|
+
object-spread hint. Excluded by path rather than fixed.
|
|
44
|
+
ignores:
|
|
45
|
+
- "**/tests/clients/call-graph.test.ts"
|
|
46
|
+
- "**/tests/tools/lens-diagnostics.test.ts"
|
|
47
|
+
rule:
|
|
48
|
+
pattern:
|
|
49
|
+
context: "type T = Record<$K, any>;"
|
|
50
|
+
selector: generic_type
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
id: no-unsafe-dictionary-unknown
|
|
2
|
+
language: TypeScript
|
|
3
|
+
severity: hint
|
|
4
|
+
message: "Record<K, unknown> — every read still needs a runtime narrow; prefer a real value type where the shape is known"
|
|
5
|
+
note: |
|
|
6
|
+
Adapted from dmmulroy/anti-slop's `no-unsafe-dictionary-type`
|
|
7
|
+
(src/rules/no-unsafe-dictionary-type.ts, MIT), narrowed to the
|
|
8
|
+
`unknown` arm — the sibling of `no-unsafe-dictionary-any.yml`, which
|
|
9
|
+
covers the `any` arm at `error`.
|
|
10
|
+
|
|
11
|
+
Shipped at `hint`, not `error` or `warning`: AGENTS.md smell 3
|
|
12
|
+
already records that `Record<string, unknown>` dictionaries are the
|
|
13
|
+
CORRECT, idiomatic contract at this repo's own validator/parser/
|
|
14
|
+
telemetry/metadata boundaries (9+ legitimate hits in the original
|
|
15
|
+
FP scan that got the wider `no-unknown-laundering` fan-out dropped
|
|
16
|
+
down to the alias-only arm). That finding doesn't generalize to every
|
|
17
|
+
repository this catalog ships to, so the pattern stays in the catalog
|
|
18
|
+
as a discoverable hint — "here's every open dictionary whose value
|
|
19
|
+
type forces the caller to narrow before use, go look and decide" —
|
|
20
|
+
rather than a rule that tells this repo's own idiom it's wrong.
|
|
21
|
+
|
|
22
|
+
Self-scan note: do NOT try to make pi-lens's own tree clean against
|
|
23
|
+
this rule (that is #1718's baseline problem, not this PR's). Recorded
|
|
24
|
+
in the adopting PR body per rule instead: 2026-08-19 hit count on
|
|
25
|
+
clients/ + tests/, napi engine.
|
|
26
|
+
|
|
27
|
+
Scope: same direct-annotation cut as the `any` arm — a `Record<$K,
|
|
28
|
+
unknown>` type reference, matched structurally. Alias resolution and
|
|
29
|
+
type-literal index signatures are out of scope for the same reason.
|
|
30
|
+
|
|
31
|
+
2026-08-20 (refs #1727, #1777): CONSIDERED for promotion to `error`,
|
|
32
|
+
KEPT at `hint`. Four-corpus census, ast-grep CLI 0.45:
|
|
33
|
+
|
|
34
|
+
| corpus | hits |
|
|
35
|
+
|---|---:|
|
|
36
|
+
| pi-lens `clients/` | 142 |
|
|
37
|
+
| pi-lens `tests/` | 247 |
|
|
38
|
+
| pi core `packages/` | 299 (162 outside test paths) |
|
|
39
|
+
| opencode `packages/` | 533 (392) |
|
|
40
|
+
| oh-my-pi `packages/` | 2994 (1727) |
|
|
41
|
+
|
|
42
|
+
Verdict: promoting this rule would contradict AGENTS.md's own written
|
|
43
|
+
guidance in the same repository. Smell 3 records `Record<string,
|
|
44
|
+
unknown>` as the CORRECT contract at this codebase's validator, parser,
|
|
45
|
+
telemetry, and metadata boundaries. The suppression that would rescue it
|
|
46
|
+
— "suppress when the enclosing scope narrows the value before use" —
|
|
47
|
+
needs data flow from the dictionary's declaration to each read, which
|
|
48
|
+
ast-grep's structural matcher does not do; a syntactic stand-in would be
|
|
49
|
+
the vacuous guard this repo's review process screens for. The `any` arm
|
|
50
|
+
(`no-unsafe-dictionary-any.yml`) stays the error-tier member of the
|
|
51
|
+
pair, and it is clean on pi-lens: `any` turns checking OFF for every
|
|
52
|
+
property read, which is the discriminator `unknown` does not share.
|
|
53
|
+
rule:
|
|
54
|
+
pattern:
|
|
55
|
+
context: "type T = Record<$K, unknown>;"
|
|
56
|
+
selector: generic_type
|
package/node_modules/pi-lens/rules/ast-grep-rules/rules/no-win32-isabsolute-for-qualification.yml
CHANGED
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
id: no-win32-isabsolute-for-qualification
|
|
2
2
|
language: TypeScript
|
|
3
3
|
severity: warning
|
|
4
|
+
metadata:
|
|
5
|
+
category: pi-lens-self-scan
|
|
4
6
|
message: "Use isFullyQualified for path qualification instead of win32.isAbsolute"
|
|
5
7
|
note: |
|
|
6
8
|
Qualification must follow the input path's shape. Use clients/path-utils.ts
|