@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
|
@@ -9,6 +9,7 @@
|
|
|
9
9
|
* Docs: https://knip.dev/
|
|
10
10
|
*/
|
|
11
11
|
import { createSubsystemLogger } from "./extension-log.js";
|
|
12
|
+
import { incrementDegradationCount } from "./degradation-ledger.js";
|
|
12
13
|
import * as fs from "node:fs";
|
|
13
14
|
import * as path from "node:path";
|
|
14
15
|
import { getProjectDataDir } from "./file-utils.js";
|
|
@@ -16,6 +17,10 @@ import { findNearestMarkerRoot } from "./path-utils.js";
|
|
|
16
17
|
import { safeSpawnAsync } from "./safe-spawn.js";
|
|
17
18
|
import { createAvailabilityChecker, findManagedNodeToolBinary, getManagedToolEnvironment, resolveAvailableOrInstall, } from "./dispatch/runners/utils/runner-helpers.js";
|
|
18
19
|
import { createAvailabilityLatch, describeUnavailability, } from "./dispatch/runners/utils/availability-policy.js";
|
|
20
|
+
import { spawnFailedWithNoOutput } from "./dispatch/runners/utils/spawn-outcome.js";
|
|
21
|
+
import { formatToolFailure } from "./dispatch/runners/utils/tool-failure.js";
|
|
22
|
+
import { findLocalBinUpwards } from "./package-manager.js";
|
|
23
|
+
import { logSessionStart } from "./sessionstart-logger.js";
|
|
19
24
|
const EMPTY_RESULT = {
|
|
20
25
|
success: false,
|
|
21
26
|
issues: [],
|
|
@@ -57,6 +62,105 @@ export function readOverridePinnedPackageNames(targetDir) {
|
|
|
57
62
|
collectKeys(pkg.pnpm?.overrides);
|
|
58
63
|
return names;
|
|
59
64
|
}
|
|
65
|
+
/**
|
|
66
|
+
* knip's own config-file names, in knip's discovery order (knip 6
|
|
67
|
+
* `configFilesLookup`). Used for REPORTING which config a run resolved — the
|
|
68
|
+
* runner never passes `--config`, so knip still does its own discovery from the
|
|
69
|
+
* spawn cwd. Reading the same list here keeps the recorded answer honest
|
|
70
|
+
* instead of guessing "knip.json or nothing".
|
|
71
|
+
*/
|
|
72
|
+
const KNIP_CONFIG_FILENAMES = [
|
|
73
|
+
"knip.json",
|
|
74
|
+
"knip.jsonc",
|
|
75
|
+
"knip.ts",
|
|
76
|
+
"knip.js",
|
|
77
|
+
"knip.config.ts",
|
|
78
|
+
"knip.config.js",
|
|
79
|
+
".knip.json",
|
|
80
|
+
".knip.jsonc",
|
|
81
|
+
".knip.ts",
|
|
82
|
+
".knip.js",
|
|
83
|
+
];
|
|
84
|
+
/**
|
|
85
|
+
* The knip config this project ships, relative to `targetDir`, or null when the
|
|
86
|
+
* project ships none (knip then runs on its built-in defaults).
|
|
87
|
+
*
|
|
88
|
+
* `package.json` is reported last and only when it carries a `knip` field —
|
|
89
|
+
* knip reads that field as a config source, and a project that configures knip
|
|
90
|
+
* there is just as configured as one with a `knip.json`.
|
|
91
|
+
*/
|
|
92
|
+
export function resolveProjectKnipConfig(targetDir) {
|
|
93
|
+
for (const name of KNIP_CONFIG_FILENAMES) {
|
|
94
|
+
if (fs.existsSync(path.join(targetDir, name)))
|
|
95
|
+
return name;
|
|
96
|
+
}
|
|
97
|
+
try {
|
|
98
|
+
const pkg = JSON.parse(fs.readFileSync(path.join(targetDir, "package.json"), "utf-8"));
|
|
99
|
+
if (pkg && typeof pkg === "object" && pkg.knip !== undefined) {
|
|
100
|
+
return "package.json#knip";
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
catch {
|
|
104
|
+
// No/malformed package.json — "no project config" is the honest answer.
|
|
105
|
+
}
|
|
106
|
+
return null;
|
|
107
|
+
}
|
|
108
|
+
/**
|
|
109
|
+
* The knip the PROJECT itself would run: its own `node_modules/.bin/knip`,
|
|
110
|
+
* walking up so a workspace package finds the monorepo's hoisted copy. Null
|
|
111
|
+
* when the project installs no knip and pi-lens's managed shim is all there is.
|
|
112
|
+
*
|
|
113
|
+
* A project that installs knip pins the version its config is written against,
|
|
114
|
+
* and that version is what the project's `npx knip` / `npm run knip` runs.
|
|
115
|
+
* Preferring pi-lens's managed shim instead makes the lens report a DIFFERENT
|
|
116
|
+
* tool's verdict under the project's config (#1721): a managed knip 6.4.1
|
|
117
|
+
* flagged 62 unused type exports on a tree that knip 6.32.2 leaves clean, and
|
|
118
|
+
* every one of those flags is destructive advice.
|
|
119
|
+
*
|
|
120
|
+
* The walk is the shared `findLocalBinUpwards`, the same one behind jscpd's
|
|
121
|
+
* (`clients/jscpd-client.ts:269`) and madge's
|
|
122
|
+
* (`clients/dependency-checker.ts:420`) resolution, rather than a fourth copy.
|
|
123
|
+
* It stops at the filesystem half deliberately: the global-bin step those two
|
|
124
|
+
* add spawns a probe per package manager, and this runs on every analyze().
|
|
125
|
+
*/
|
|
126
|
+
export function resolveProjectKnipBinary(targetDir) {
|
|
127
|
+
return findLocalBinUpwards("knip", targetDir) ?? null;
|
|
128
|
+
}
|
|
129
|
+
/**
|
|
130
|
+
* Classify a resolved shim for the toolchain record: inside the project tree,
|
|
131
|
+
* elsewhere on the user's machine, or pi-lens's own managed/PATH fallback.
|
|
132
|
+
*/
|
|
133
|
+
export function classifyKnipBinary(binary, targetDir) {
|
|
134
|
+
if (binary === null)
|
|
135
|
+
return "managed-or-path";
|
|
136
|
+
const relative = path.relative(path.resolve(targetDir), path.resolve(binary));
|
|
137
|
+
return relative === "" || relative.startsWith("..") || path.isAbsolute(relative)
|
|
138
|
+
? "global"
|
|
139
|
+
: "project";
|
|
140
|
+
}
|
|
141
|
+
/**
|
|
142
|
+
* The version of the knip package behind a resolved shim, read from disk (no
|
|
143
|
+
* spawn — a `--version` probe per project root would add a process to a hot
|
|
144
|
+
* path for a telemetry field). Returns null for a bare PATH command, whose
|
|
145
|
+
* package location is unknown.
|
|
146
|
+
*/
|
|
147
|
+
function readKnipShimVersion(binary) {
|
|
148
|
+
if (!path.isAbsolute(binary))
|
|
149
|
+
return null;
|
|
150
|
+
const binDir = path.dirname(binary);
|
|
151
|
+
if (path.basename(binDir) !== ".bin")
|
|
152
|
+
return null;
|
|
153
|
+
try {
|
|
154
|
+
const pkg = JSON.parse(fs.readFileSync(path.join(path.dirname(binDir), "knip", "package.json"), "utf-8"));
|
|
155
|
+
const version = pkg.version;
|
|
156
|
+
return typeof version === "string" ? version : null;
|
|
157
|
+
}
|
|
158
|
+
catch {
|
|
159
|
+
return null;
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
/** Distinct toolchain records kept per client instance (bounded telemetry). */
|
|
163
|
+
const MAX_RECORDED_TOOLCHAINS = 32;
|
|
60
164
|
// --- Client ---
|
|
61
165
|
export class KnipClient {
|
|
62
166
|
knipAvailability = createAvailabilityChecker("knip", ".cmd", ["--version"], {
|
|
@@ -87,11 +191,22 @@ export class KnipClient {
|
|
|
87
191
|
* in-flight promise; completing clears the slot.
|
|
88
192
|
*/
|
|
89
193
|
inFlight = new Map();
|
|
194
|
+
/** Last successful result per project and runtime content generation. */
|
|
195
|
+
completedByProject = new Map();
|
|
196
|
+
/**
|
|
197
|
+
* (project root, binary, config) triples already recorded, so the toolchain
|
|
198
|
+
* row is written once per distinct resolution instead of once per run.
|
|
199
|
+
*/
|
|
200
|
+
recordedToolchains = new Set();
|
|
90
201
|
constructor(verbose = false) {
|
|
91
202
|
this.log = verbose
|
|
92
203
|
? createSubsystemLogger("knip")
|
|
93
204
|
: () => { };
|
|
94
205
|
}
|
|
206
|
+
/** Re-arm content-keyed reuse at the session boundary. */
|
|
207
|
+
resetSessionState() {
|
|
208
|
+
this.completedByProject.clear();
|
|
209
|
+
}
|
|
95
210
|
/**
|
|
96
211
|
* Find the nearest directory with a project/knip config marker.
|
|
97
212
|
*
|
|
@@ -177,8 +292,13 @@ export class KnipClient {
|
|
|
177
292
|
*
|
|
178
293
|
* Re-entrancy safe: concurrent calls resolving to the same project
|
|
179
294
|
* root share a single knip process via `inFlight`.
|
|
295
|
+
*
|
|
296
|
+
* Successful memo hits validate package.json and the resolved Knip config
|
|
297
|
+
* with bounded metadata checks. The two statSync calls replace a 10-23
|
|
298
|
+
* second project scan. Source-only external edits remain undetected until
|
|
299
|
+
* pi observes a write or the session resets.
|
|
180
300
|
*/
|
|
181
|
-
async analyze(cwd, _ignore) {
|
|
301
|
+
async analyze(cwd, _ignore, options = {}) {
|
|
182
302
|
const targetDir = this.resolveProjectRoot(cwd || process.cwd());
|
|
183
303
|
if (!targetDir) {
|
|
184
304
|
// No package.json / knip config anywhere up the tree. Running knip
|
|
@@ -191,30 +311,97 @@ export class KnipClient {
|
|
|
191
311
|
summary: "No project root found; knip skipped",
|
|
192
312
|
};
|
|
193
313
|
}
|
|
194
|
-
|
|
314
|
+
const key = path.resolve(targetDir);
|
|
315
|
+
const completed = this.completedByProject.get(key);
|
|
316
|
+
if (options.projectSeq !== undefined &&
|
|
317
|
+
completed?.projectSeq === options.projectSeq &&
|
|
318
|
+
this.matchesMemoSignal(targetDir, completed.signal)) {
|
|
319
|
+
this.log(`Analysis cache hit for ${key} at projectSeq ${options.projectSeq}`);
|
|
320
|
+
return { ...completed.result, execution: "cache" };
|
|
321
|
+
}
|
|
322
|
+
// A project that ships its own knip needs no managed install and no
|
|
323
|
+
// managed probe — the shim is already on disk, and gating on
|
|
324
|
+
// `ensureAvailable()` would tell such a project to "npm install -D knip"
|
|
325
|
+
// whenever the MANAGED copy is missing (#1721).
|
|
326
|
+
if (resolveProjectKnipBinary(targetDir) === null &&
|
|
327
|
+
!(await this.ensureAvailable())) {
|
|
195
328
|
return this.unavailableResult();
|
|
196
329
|
}
|
|
197
|
-
const key = path.resolve(targetDir);
|
|
198
330
|
const existing = this.inFlight.get(key);
|
|
199
331
|
if (existing) {
|
|
200
332
|
this.log(`Analysis already in flight for ${key}; sharing result`);
|
|
201
333
|
return existing;
|
|
202
334
|
}
|
|
203
|
-
const promise = this.runAnalyze(key)
|
|
335
|
+
const promise = this.runAnalyze(key)
|
|
336
|
+
.then((result) => {
|
|
337
|
+
const executed = { ...result, execution: "executed" };
|
|
338
|
+
if (result.success && options.projectSeq !== undefined) {
|
|
339
|
+
this.completedByProject.set(key, {
|
|
340
|
+
projectSeq: options.projectSeq,
|
|
341
|
+
result: executed,
|
|
342
|
+
signal: this.readMemoSignal(key),
|
|
343
|
+
});
|
|
344
|
+
}
|
|
345
|
+
return executed;
|
|
346
|
+
})
|
|
347
|
+
.finally(() => {
|
|
204
348
|
this.inFlight.delete(key);
|
|
205
349
|
});
|
|
206
350
|
this.inFlight.set(key, promise);
|
|
207
351
|
return promise;
|
|
208
352
|
}
|
|
353
|
+
readMemoFileSignal(filePath) {
|
|
354
|
+
try {
|
|
355
|
+
const stat = fs.statSync(filePath);
|
|
356
|
+
return { path: filePath, mtimeMs: stat.mtimeMs, size: stat.size };
|
|
357
|
+
}
|
|
358
|
+
catch {
|
|
359
|
+
return null;
|
|
360
|
+
}
|
|
361
|
+
}
|
|
362
|
+
readMemoSignal(targetDir) {
|
|
363
|
+
const config = resolveProjectKnipConfig(targetDir);
|
|
364
|
+
return {
|
|
365
|
+
packageJson: this.readMemoFileSignal(path.join(targetDir, "package.json")),
|
|
366
|
+
config: config && config !== "package.json#knip"
|
|
367
|
+
? this.readMemoFileSignal(path.join(targetDir, config))
|
|
368
|
+
: null,
|
|
369
|
+
};
|
|
370
|
+
}
|
|
371
|
+
matchesMemoSignal(targetDir, signal) {
|
|
372
|
+
const current = {
|
|
373
|
+
packageJson: this.readMemoFileSignal(path.join(targetDir, "package.json")),
|
|
374
|
+
config: signal.config ? this.readMemoFileSignal(signal.config.path) : null,
|
|
375
|
+
};
|
|
376
|
+
return (JSON.stringify(current.packageJson) === JSON.stringify(signal.packageJson) &&
|
|
377
|
+
JSON.stringify(current.config) === JSON.stringify(signal.config));
|
|
378
|
+
}
|
|
209
379
|
async runAnalyze(targetDir) {
|
|
210
380
|
// Cache dir is routed through pi-lens's project-data-dir convention (NOT
|
|
211
381
|
// knip's own default `./node_modules/.cache/knip`) so it lives alongside
|
|
212
382
|
// every other project cache (see cache-manager.ts, call-graph.ts) and is
|
|
213
383
|
// covered by the existing `.pi-lens/` gitignore entry.
|
|
214
384
|
//
|
|
215
|
-
//
|
|
216
|
-
//
|
|
217
|
-
//
|
|
385
|
+
// Documented cache-invalidation gaps (both live in knip's own cache, not
|
|
386
|
+
// in pi-lens):
|
|
387
|
+
//
|
|
388
|
+
// 1. `.gitignore` (per knip's docs): a cached run does NOT pick up
|
|
389
|
+
// newly-added `.gitignore` files automatically — the cache must be
|
|
390
|
+
// deleted to detect them. Not auto-handled here; documented tradeoff.
|
|
391
|
+
// 2. Consumer-side imports (#1630): knip's glob cache records the mtime of
|
|
392
|
+
// every directory that CONTRIBUTED a matched path, and revalidates
|
|
393
|
+
// against those. A directory that matched nothing at cache time is not
|
|
394
|
+
// recorded, so a file later added to it is invisible to the cached
|
|
395
|
+
// glob. A new test that imports an export therefore never reaches the
|
|
396
|
+
// graph, and knip keeps reporting that export as unused — a stale
|
|
397
|
+
// verdict pi-lens then renders as fresh. Fixed upstream in knip 6.28.0
|
|
398
|
+
// (glob cache now tracks every directory it reads), but the managed
|
|
399
|
+
// install floats and older versions are common in the field, so
|
|
400
|
+
// `pruneStaleGlobCache()` below drops the glob cache on every run
|
|
401
|
+
// regardless of version. Measured on this repo with knip 6.4.1:
|
|
402
|
+
// uncached 3.3s, fully cached 1.3s, glob-cache-dropped 1.4s. The glob
|
|
403
|
+
// cache is worth ~0.1s of the ~2.0s the cache saves, so dropping it
|
|
404
|
+
// buys correctness for almost nothing.
|
|
218
405
|
const cacheLocation = path.join(getProjectDataDir(targetDir), "cache", "knip");
|
|
219
406
|
// knip (verified against 6.26.0) silently fails to persist the cache when
|
|
220
407
|
// `--cache-location` points at a directory that doesn't exist yet: its
|
|
@@ -230,6 +417,7 @@ export class KnipClient {
|
|
|
230
417
|
catch (err) {
|
|
231
418
|
this.log(`Failed to pre-create knip cache dir ${cacheLocation}: ${err}`);
|
|
232
419
|
}
|
|
420
|
+
this.pruneStaleGlobCache(cacheLocation);
|
|
233
421
|
const args = [
|
|
234
422
|
"--reporter=json",
|
|
235
423
|
"--include",
|
|
@@ -242,7 +430,14 @@ export class KnipClient {
|
|
|
242
430
|
"--cache-location",
|
|
243
431
|
cacheLocation,
|
|
244
432
|
];
|
|
245
|
-
|
|
433
|
+
// Project toolchain first. #1199 already put `<targetDir>/node_modules/.bin`
|
|
434
|
+
// at the front of the child PATH for exactly this preference, but the spawn
|
|
435
|
+
// command is an ABSOLUTE managed path, so PATH order never got a say
|
|
436
|
+
// (#1721). Resolving the command here is what makes that intent real.
|
|
437
|
+
const projectBinary = resolveProjectKnipBinary(targetDir);
|
|
438
|
+
const command = projectBinary ?? this.knipCommand;
|
|
439
|
+
this.recordToolchain(targetDir, command, classifyKnipBinary(projectBinary, targetDir));
|
|
440
|
+
const result = await safeSpawnAsync(command, args, {
|
|
246
441
|
timeout: ANALYSIS_TIMEOUT_MS,
|
|
247
442
|
cwd: targetDir,
|
|
248
443
|
env: await getManagedToolEnvironment("knip", targetDir),
|
|
@@ -254,13 +449,55 @@ export class KnipClient {
|
|
|
254
449
|
summary: `Error: ${result.error.message}`,
|
|
255
450
|
};
|
|
256
451
|
}
|
|
257
|
-
//
|
|
452
|
+
// Empirical exit-code table (knip 6.4.1, verified live for #1736): 0 =
|
|
453
|
+
// clean run, JSON stdout `{"issues":[]}`; 1 = clean run WITH findings,
|
|
454
|
+
// JSON stdout `{"issues":[...]}`; 2 = config/load error, empty or
|
|
455
|
+
// non-JSON stdout with the error on stderr. A genuinely clean run's
|
|
456
|
+
// stdout is therefore NEVER empty — knip always prints at least
|
|
457
|
+
// `{"issues":[]}` on exit 0. Empty stdout only ever shows up paired
|
|
458
|
+
// with a NONZERO exit (a broken shim, a crash, or knip's own load
|
|
459
|
+
// error), so `status !== 0 && !output.trim()` is unambiguous evidence
|
|
460
|
+
// of a failed run, never a clean one.
|
|
258
461
|
const output = result.stdout || "";
|
|
259
|
-
this.log(`Knip output length: ${output.length}`);
|
|
462
|
+
this.log(`Knip output length: ${output.length}, exit status: ${result.status}`);
|
|
260
463
|
if (output.length < 500) {
|
|
261
464
|
this.log(`Knip output sample: ${output}`);
|
|
262
465
|
}
|
|
263
466
|
if (!output.trim()) {
|
|
467
|
+
// Reuses the SAME discriminator every dispatch/runners linter uses
|
|
468
|
+
// (`spawnFailedWithNoOutput`, `clients/dispatch/runners/utils/
|
|
469
|
+
// spawn-outcome.ts`) rather than a parallel hand-rolled check — a
|
|
470
|
+
// nonzero exit with nothing to parse is never a clean run, here or
|
|
471
|
+
// there.
|
|
472
|
+
if (spawnFailedWithNoOutput(result, output)) {
|
|
473
|
+
// #1816: one shared wording, one truncation, signal named. The
|
|
474
|
+
// binary-source discriminator (#1721's whole point — WHICH knip
|
|
475
|
+
// ran) survives as a named field rather than as prose.
|
|
476
|
+
const reason = formatToolFailure({
|
|
477
|
+
tool: "knip",
|
|
478
|
+
status: result.status,
|
|
479
|
+
signal: result.signal,
|
|
480
|
+
stderr: result.stderr,
|
|
481
|
+
fields: {
|
|
482
|
+
command,
|
|
483
|
+
source: classifyKnipBinary(projectBinary, targetDir),
|
|
484
|
+
},
|
|
485
|
+
});
|
|
486
|
+
this.log(reason);
|
|
487
|
+
incrementDegradationCount({
|
|
488
|
+
kind: "runner-empty-result",
|
|
489
|
+
subject: "knip",
|
|
490
|
+
reason,
|
|
491
|
+
});
|
|
492
|
+
return {
|
|
493
|
+
...EMPTY_RESULT,
|
|
494
|
+
summary: `Knip exited ${result.status} with no output; run skipped`,
|
|
495
|
+
};
|
|
496
|
+
}
|
|
497
|
+
// status === 0 with empty stdout has never been observed against a
|
|
498
|
+
// real knip binary (a genuine clean run still prints
|
|
499
|
+
// `{"issues":[]}`), but a defensive fallback is cheap insurance
|
|
500
|
+
// against a future knip release that changes this.
|
|
264
501
|
return {
|
|
265
502
|
...EMPTY_RESULT,
|
|
266
503
|
success: true,
|
|
@@ -269,6 +506,69 @@ export class KnipClient {
|
|
|
269
506
|
}
|
|
270
507
|
return this.dropOverridePinnedDeps(this.parseOutput(output), targetDir);
|
|
271
508
|
}
|
|
509
|
+
/**
|
|
510
|
+
* Record WHICH knip a run used and WHICH config it ran under (#1721).
|
|
511
|
+
*
|
|
512
|
+
* The dogfood failure this fixes was invisible from the outside: the lens
|
|
513
|
+
* reported 62 unused type exports and the project's own `npx knip` reported
|
|
514
|
+
* none, with nothing in any log to say the two ran different binaries. This
|
|
515
|
+
* row is that missing evidence — it names the shim, its version, the config
|
|
516
|
+
* knip will discover, and whether the shim came from the project or from
|
|
517
|
+
* pi-lens.
|
|
518
|
+
*
|
|
519
|
+
* Bounded twice over: one row per distinct (project root, binary, config)
|
|
520
|
+
* triple, and at most `MAX_RECORDED_TOOLCHAINS` distinct triples per client.
|
|
521
|
+
* Steady-state cost is therefore one line per project per session, not one
|
|
522
|
+
* per turn_end.
|
|
523
|
+
*/
|
|
524
|
+
recordToolchain(targetDir, command, source) {
|
|
525
|
+
const config = resolveProjectKnipConfig(targetDir);
|
|
526
|
+
const key = `${targetDir} ${command} ${config ?? ""}`;
|
|
527
|
+
if (this.recordedToolchains.has(key))
|
|
528
|
+
return;
|
|
529
|
+
if (this.recordedToolchains.size >= MAX_RECORDED_TOOLCHAINS)
|
|
530
|
+
return;
|
|
531
|
+
this.recordedToolchains.add(key);
|
|
532
|
+
const version = readKnipShimVersion(command);
|
|
533
|
+
logSessionStart(`knip toolchain ${targetDir}: binary=${command}` +
|
|
534
|
+
`${version ? ` version=${version}` : ""}` +
|
|
535
|
+
` source=${source}` +
|
|
536
|
+
` config=${config ?? "none (knip defaults)"}`);
|
|
537
|
+
}
|
|
538
|
+
/**
|
|
539
|
+
* Delete knip's glob cache (`glob-<version>.cache`) before every run (#1630).
|
|
540
|
+
*
|
|
541
|
+
* knip revalidates a cached glob against the mtimes of the directories that
|
|
542
|
+
* contributed a matched path. Directories that matched nothing are never
|
|
543
|
+
* recorded, so files later added to them stay invisible and knip keeps
|
|
544
|
+
* reporting an export as unused after a new consumer imports it. Removing
|
|
545
|
+
* this one file forces a fresh file walk while the module and plugin caches —
|
|
546
|
+
* which carry nearly all of the cache's speed — survive.
|
|
547
|
+
*
|
|
548
|
+
* Failures are logged and ignored: a glob cache we could not delete degrades
|
|
549
|
+
* to the pre-#1630 behavior, which is stale but not fatal.
|
|
550
|
+
*/
|
|
551
|
+
pruneStaleGlobCache(cacheLocation) {
|
|
552
|
+
let entries;
|
|
553
|
+
try {
|
|
554
|
+
entries = fs.readdirSync(cacheLocation);
|
|
555
|
+
}
|
|
556
|
+
catch (err) {
|
|
557
|
+
this.log(`Failed to read knip cache dir ${cacheLocation}: ${err}`);
|
|
558
|
+
return;
|
|
559
|
+
}
|
|
560
|
+
for (const entry of entries) {
|
|
561
|
+
if (!entry.startsWith("glob-") || !entry.endsWith(".cache"))
|
|
562
|
+
continue;
|
|
563
|
+
try {
|
|
564
|
+
fs.rmSync(path.join(cacheLocation, entry), { force: true });
|
|
565
|
+
this.log(`Pruned knip glob cache ${entry}`);
|
|
566
|
+
}
|
|
567
|
+
catch (err) {
|
|
568
|
+
this.log(`Failed to prune knip glob cache ${entry}: ${err}`);
|
|
569
|
+
}
|
|
570
|
+
}
|
|
571
|
+
}
|
|
272
572
|
/**
|
|
273
573
|
* Drop `dependency`/`devDependency` issues for a package that's also
|
|
274
574
|
* referenced as an npm `overrides` (or Yarn `resolutions` / pnpm
|
|
@@ -61,6 +61,7 @@ export const LANGUAGE_POLICY = {
|
|
|
61
61
|
gleam: { lspCapable: true },
|
|
62
62
|
ocaml: { lspCapable: true },
|
|
63
63
|
clojure: { lspCapable: true },
|
|
64
|
+
cue: { lspCapable: true },
|
|
64
65
|
terraform: { lspCapable: true },
|
|
65
66
|
terragrunt: { lspCapable: false },
|
|
66
67
|
nix: { lspCapable: true },
|
|
@@ -119,7 +120,7 @@ const PRIMARY_DISPATCH_GROUPS = {
|
|
|
119
120
|
},
|
|
120
121
|
yaml: {
|
|
121
122
|
mode: "all",
|
|
122
|
-
runnerIds: ["lsp", "yamllint", "trivy-config", "helm-lint"],
|
|
123
|
+
runnerIds: ["lsp", "yamllint", "trivy-config", "helm-lint", "helm-render"],
|
|
123
124
|
filterKinds: ["yaml"],
|
|
124
125
|
},
|
|
125
126
|
sql: {
|
|
@@ -183,7 +184,9 @@ const PRIMARY_DISPATCH_GROUPS = {
|
|
|
183
184
|
haskell: { mode: "fallback", runnerIds: ["lsp"], filterKinds: ["haskell"] },
|
|
184
185
|
"helm-template": {
|
|
185
186
|
mode: "all",
|
|
186
|
-
|
|
187
|
+
// helm-render is opt-in (`helm.renderValidation.enabled`) and skips itself
|
|
188
|
+
// when the switch is absent, so it costs nothing when unconfigured (#1283).
|
|
189
|
+
runnerIds: ["helm-lint", "helm-render"],
|
|
187
190
|
filterKinds: ["helm-template"],
|
|
188
191
|
},
|
|
189
192
|
elixir: {
|
|
@@ -198,6 +201,9 @@ const PRIMARY_DISPATCH_GROUPS = {
|
|
|
198
201
|
},
|
|
199
202
|
ocaml: { mode: "fallback", runnerIds: ["lsp"], filterKinds: ["ocaml"] },
|
|
200
203
|
clojure: { mode: "fallback", runnerIds: ["lsp"], filterKinds: ["clojure"] },
|
|
204
|
+
// #1522: cuelsp reports syntax/parse errors only; cue-vet covers the
|
|
205
|
+
// evaluation-error class the language server deliberately doesn't publish.
|
|
206
|
+
cue: { mode: "all", runnerIds: ["lsp", "cue-vet"], filterKinds: ["cue"] },
|
|
201
207
|
terraform: {
|
|
202
208
|
mode: "all",
|
|
203
209
|
runnerIds: ["lsp", "tflint", "trivy-config"],
|
|
@@ -35,6 +35,7 @@ const PROJECT_MARKERS_BY_KIND = {
|
|
|
35
35
|
swift: ["Package.swift"],
|
|
36
36
|
dart: ["pubspec.yaml"],
|
|
37
37
|
elixir: ["mix.exs"],
|
|
38
|
+
cue: ["cue.mod"],
|
|
38
39
|
gleam: ["gleam.toml"],
|
|
39
40
|
terraform: [".terraform.lock.hcl"],
|
|
40
41
|
terragrunt: TERRAGRUNT_FILENAMES,
|
|
@@ -80,6 +81,7 @@ const ROOT_MARKERS_BY_KIND = {
|
|
|
80
81
|
swift: ["Package.swift"],
|
|
81
82
|
dart: ["pubspec.yaml"],
|
|
82
83
|
elixir: ["mix.exs"],
|
|
84
|
+
cue: ["cue.mod", ".git"],
|
|
83
85
|
gleam: ["gleam.toml"],
|
|
84
86
|
terraform: [".terraform.lock.hcl"],
|
|
85
87
|
terragrunt: TERRAGRUNT_FILENAMES,
|
|
@@ -283,11 +285,16 @@ export async function collectSourceFilesForWarmup(rootDir, maxFiles = MAX_WARMUP
|
|
|
283
285
|
stack.push(fullPath);
|
|
284
286
|
}
|
|
285
287
|
else if (entry.isFile()) {
|
|
286
|
-
|
|
287
|
-
|
|
288
|
+
// #1974: cheap extension gate before the ignore matcher — isIgnored is
|
|
289
|
+
// O(ancestorDirs x patterns) with a per-call minimatch regex compile
|
|
290
|
+
// (0.68-0.93ms/file, measured), so pay it only for files that already
|
|
291
|
+
// pass the extension check. A large ignored-but-not-dir-prunable pile
|
|
292
|
+
// (e.g. wal/*.log) otherwise pays the full isIgnored cost per file.
|
|
288
293
|
const ext = path.extname(entry.name).toLowerCase();
|
|
289
294
|
if (!WARMUP_SOURCE_EXTS.has(ext))
|
|
290
295
|
continue;
|
|
296
|
+
if (ignoreMatcher.isIgnored(fullPath, false))
|
|
297
|
+
continue;
|
|
291
298
|
matchedSeen += 1;
|
|
292
299
|
const bucket = WARMUP_CODE_EXTS.has(ext) ? codeOut : nonCodeOut;
|
|
293
300
|
// Per-category hard cap — language detection only needs
|