@herbertgao/pi-extensions 2026.8.5 → 2026.8.7
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 +5 -5
- 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 +272 -22
- package/node_modules/@herbertgao/pi-cc-extensions/extensions/feature/context.ts +74 -5
- package/node_modules/@herbertgao/pi-cc-extensions/extensions/renderer/compact-mode.ts +94 -77
- package/node_modules/@herbertgao/pi-cc-extensions/extensions/renderer/markdown-enhance.ts +48 -6
- package/node_modules/@herbertgao/pi-cc-extensions/extensions/renderer/message-display.ts +1 -1
- package/node_modules/@herbertgao/pi-cc-extensions/extensions/renderer/mouse/hover.ts +14 -0
- package/node_modules/@herbertgao/pi-cc-extensions/extensions/renderer/mouse/interaction.ts +55 -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 +16 -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 +22 -15
- 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 +34 -10
- package/node_modules/@herbertgao/pi-subagents/src/usage.ts +129 -1
- package/node_modules/@herbertgao/pi-subagents/src/worktree.ts +29 -5
- package/node_modules/@juicesharp/rpiv-ask-user-question/README.md +3 -0
- package/node_modules/@juicesharp/rpiv-ask-user-question/ask-user-question.ts +46 -10
- 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 +8 -1
- package/node_modules/@juicesharp/rpiv-ask-user-question/docs/localization.md +3 -1
- package/node_modules/@juicesharp/rpiv-ask-user-question/locales/en.json +2 -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 +3 -1
- package/node_modules/@juicesharp/rpiv-ask-user-question/state/questionnaire-session.ts +30 -7
- package/node_modules/@juicesharp/rpiv-ask-user-question/state/state.ts +14 -6
- package/node_modules/@juicesharp/rpiv-ask-user-question/view/dialog-builder.ts +30 -4
- package/node_modules/@juicesharp/rpiv-ask-user-question/view/tab-content-strategy.ts +26 -5
- package/node_modules/@narumitw/pi-btw/README.md +119 -103
- 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 +13 -9
- package/node_modules/@narumitw/pi-btw/src/btw.ts +40 -42
- 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 +78 -15
- package/node_modules/@narumitw/pi-btw/src/settings.ts +22 -2
- package/node_modules/@narumitw/pi-btw/src/transcript-pager.ts +136 -45
- package/node_modules/pi-lens/CHANGELOG.md +1004 -0
- package/node_modules/pi-lens/README.md +11 -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 +427 -0
- package/node_modules/pi-lens/dist/clients/agent-nudge.js +79 -16
- 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 +285 -8
- package/node_modules/pi-lens/dist/clients/biome-client.js +176 -37
- package/node_modules/pi-lens/dist/clients/blocker-freshness.js +428 -0
- package/node_modules/pi-lens/dist/clients/blocker-past-eof.js +119 -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 +192 -0
- package/node_modules/pi-lens/dist/clients/bus-events-logger.js +62 -6
- package/node_modules/pi-lens/dist/clients/bus-publish.js +11 -3
- package/node_modules/pi-lens/dist/clients/cascade-budget.js +196 -0
- package/node_modules/pi-lens/dist/clients/cascade-format.js +76 -2
- 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/console-guard-install.js +16 -4
- package/node_modules/pi-lens/dist/clients/dead-code-client.js +249 -52
- 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 +62 -13
- package/node_modules/pi-lens/dist/clients/dependency-checker.js +43 -9
- package/node_modules/pi-lens/dist/clients/diagnostic-dispositions.js +153 -37
- package/node_modules/pi-lens/dist/clients/diagnostic-line-freshness.js +298 -0
- package/node_modules/pi-lens/dist/clients/diagnostics-publish.js +10 -3
- package/node_modules/pi-lens/dist/clients/dispatch/dispatcher.js +165 -11
- package/node_modules/pi-lens/dist/clients/dispatch/integration.js +325 -72
- 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/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/helm-render.js +895 -0
- 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 +81 -41
- package/node_modules/pi-lens/dist/clients/dispatch/runners/markdownlint.js +16 -0
- package/node_modules/pi-lens/dist/clients/dispatch/runners/mypy.js +23 -0
- 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 +14 -0
- package/node_modules/pi-lens/dist/clients/dispatch/runners/sqlfluff.js +20 -0
- package/node_modules/pi-lens/dist/clients/dispatch/runners/stylelint.js +22 -0
- package/node_modules/pi-lens/dist/clients/dispatch/runners/swiftlint.js +10 -0
- package/node_modules/pi-lens/dist/clients/dispatch/runners/taplo.js +18 -6
- 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 +488 -0
- package/node_modules/pi-lens/dist/clients/dispatch/runners/utils/candidate-probe.js +84 -0
- 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 +943 -93
- 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 +72 -0
- package/node_modules/pi-lens/dist/clients/dispatch/runners/utils/toolchain-availability.js +106 -0
- package/node_modules/pi-lens/dist/clients/dispatch/runners/vale.js +9 -0
- package/node_modules/pi-lens/dist/clients/dispatch/runners/yamllint.js +18 -1
- package/node_modules/pi-lens/dist/clients/dispatch/runners/zig-check.js +4 -2
- package/node_modules/pi-lens/dist/clients/disposition-publish.js +10 -3
- package/node_modules/pi-lens/dist/clients/eval-timestamp.js +17 -0
- package/node_modules/pi-lens/dist/clients/event-loop-monitor.js +28 -5
- package/node_modules/pi-lens/dist/clients/extension-log.js +317 -3
- package/node_modules/pi-lens/dist/clients/file-kinds.js +8 -2
- package/node_modules/pi-lens/dist/clients/finding-delivery-gate.js +294 -0
- package/node_modules/pi-lens/dist/clients/finding-identity.js +88 -0
- package/node_modules/pi-lens/dist/clients/fix-worklog.js +5 -1
- package/node_modules/pi-lens/dist/clients/format-events-publish.js +39 -8
- 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 +49 -21
- package/node_modules/pi-lens/dist/clients/gitleaks-client.js +181 -8
- package/node_modules/pi-lens/dist/clients/go-client.js +21 -39
- package/node_modules/pi-lens/dist/clients/govulncheck-client.js +219 -10
- package/node_modules/pi-lens/dist/clients/grammar-source.js +333 -10
- package/node_modules/pi-lens/dist/clients/host-ports.js +9 -1
- package/node_modules/pi-lens/dist/clients/installer/index.js +1119 -101
- 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 +86 -15
- package/node_modules/pi-lens/dist/clients/knip-client.js +361 -24
- package/node_modules/pi-lens/dist/clients/language-policy.js +8 -2
- package/node_modules/pi-lens/dist/clients/language-profile.js +2 -0
- package/node_modules/pi-lens/dist/clients/latency-logger.js +487 -9
- 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-events.js +56 -25
- package/node_modules/pi-lens/dist/clients/lens-flag-registry.js +16 -0
- package/node_modules/pi-lens/dist/clients/live-bus-emitter.js +45 -2
- package/node_modules/pi-lens/dist/clients/lsp/aggregation.js +30 -4
- package/node_modules/pi-lens/dist/clients/lsp/cascade-tier.js +160 -20
- package/node_modules/pi-lens/dist/clients/lsp/client.js +1666 -148
- package/node_modules/pi-lens/dist/clients/lsp/diagnostic-binding.js +111 -0
- package/node_modules/pi-lens/dist/clients/lsp/document-drift.js +389 -0
- package/node_modules/pi-lens/dist/clients/lsp/index.js +2496 -171
- 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 +517 -69
- 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 +172 -0
- package/node_modules/pi-lens/dist/clients/lsp/wait-policy/classification.js +21 -5
- package/node_modules/pi-lens/dist/clients/lsp/wait-policy/strategies.js +61 -3
- 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/analyze.js +4 -0
- package/node_modules/pi-lens/dist/clients/mcp/session.js +39 -18
- package/node_modules/pi-lens/dist/clients/model-provider.js +53 -0
- package/node_modules/pi-lens/dist/clients/module-report.js +8 -0
- 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 +178 -30
- 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 +85 -15
- 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/runner-findings.js +23 -2
- 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 +5 -0
- package/node_modules/pi-lens/dist/clients/project-lens-config.js +3 -0
- 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 +1 -1
- package/node_modules/pi-lens/dist/clients/read-guard.js +184 -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/query.js +76 -4
- package/node_modules/pi-lens/dist/clients/run-duration.js +55 -0
- package/node_modules/pi-lens/dist/clients/runtime-agent-end.js +248 -13
- package/node_modules/pi-lens/dist/clients/runtime-context.js +112 -12
- package/node_modules/pi-lens/dist/clients/runtime-coordinator.js +472 -61
- package/node_modules/pi-lens/dist/clients/runtime-session.js +359 -13
- package/node_modules/pi-lens/dist/clients/runtime-tool-call.js +217 -22
- package/node_modules/pi-lens/dist/clients/runtime-tool-result.js +269 -22
- package/node_modules/pi-lens/dist/clients/runtime-turn.js +948 -87
- package/node_modules/pi-lens/dist/clients/rust-client.js +21 -37
- 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 +224 -8
- package/node_modules/pi-lens/dist/clients/sg-runner.js +249 -37
- package/node_modules/pi-lens/dist/clients/single-flight.js +158 -0
- package/node_modules/pi-lens/dist/clients/smells-rollup.js +18 -11
- package/node_modules/pi-lens/dist/clients/stale-marker.js +17 -0
- package/node_modules/pi-lens/dist/clients/startup-timing.js +26 -2
- package/node_modules/pi-lens/dist/clients/test-runner-client.js +574 -32
- package/node_modules/pi-lens/dist/clients/tool-event.js +56 -5
- package/node_modules/pi-lens/dist/clients/tool-policy.js +127 -20
- package/node_modules/pi-lens/dist/clients/tool-set-policy.js +76 -0
- 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-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/warm-attach.js +17 -0
- package/node_modules/pi-lens/dist/clients/widget-state.js +336 -36
- package/node_modules/pi-lens/dist/clients/word-index.js +305 -33
- package/node_modules/pi-lens/dist/clients/zizmor-config.js +214 -14
- package/node_modules/pi-lens/dist/index.js +64677 -49484
- package/node_modules/pi-lens/dist/mcp/server.js +8 -2
- package/node_modules/pi-lens/dist/tools/activate-tools.js +17 -5
- package/node_modules/pi-lens/dist/tools/ast-grep-replace.js +9 -4
- package/node_modules/pi-lens/dist/tools/lens-diagnostic-mark.js +5 -2
- package/node_modules/pi-lens/dist/tools/lens-diagnostics.js +469 -56
- package/node_modules/pi-lens/dist/tools/lsp-diagnostics.js +190 -46
- package/node_modules/pi-lens/dist/tools/lsp-navigation.js +46 -7
- package/node_modules/pi-lens/dist/tools/symbol-search.js +1 -1
- package/node_modules/pi-lens/docs/agent-guide.md +44 -14
- package/node_modules/pi-lens/docs/ast-grep_rules_catalog.md +518 -501
- package/node_modules/pi-lens/docs/dispositions.md +21 -0
- package/node_modules/pi-lens/docs/features.md +33 -6
- package/node_modules/pi-lens/docs/globalconfig.md +14 -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 +25 -1
- package/node_modules/pi-lens/docs/usage.md +24 -5
- package/node_modules/pi-lens/docs/word-index.md +35 -0
- package/node_modules/pi-lens/package.json +10 -6
- 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 +22 -0
- 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-conditional-empty-object-spread-js-test.yml +9 -0
- package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/no-conditional-empty-object-spread-test.yml +9 -0
- 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 +9 -0
- package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/no-reflect-apply-test.yml +9 -0
- package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/no-reflect-get-js-test.yml +9 -0
- package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/no-reflect-get-test.yml +9 -0
- 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-laundering-test.yml +11 -0
- 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 +66 -0
- 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-conditional-empty-object-spread-js.yml +21 -0
- package/node_modules/pi-lens/rules/ast-grep-rules/rules/no-conditional-empty-object-spread.yml +29 -0
- 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 +29 -0
- package/node_modules/pi-lens/rules/ast-grep-rules/rules/no-reflect-apply.yml +30 -0
- package/node_modules/pi-lens/rules/ast-grep-rules/rules/no-reflect-get-js.yml +41 -0
- package/node_modules/pi-lens/rules/ast-grep-rules/rules/no-reflect-get.yml +42 -0
- 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 +32 -0
- 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 +132 -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/skills/pi-lens-ast-grep/SKILL.md +12 -11
- package/node_modules/pi-lens/skills/pi-lens-lsp-navigation/SKILL.md +22 -22
- package/node_modules/pi-lens/skills/pi-lens-write-ast-grep-rule/SKILL.md +87 -116
- package/node_modules/pi-lens/skills/pi-lens-write-ast-grep-rule/reference.md +170 -0
- package/node_modules/pi-lens/skills/pi-lens-write-tree-sitter-rule/SKILL.md +3 -1
- package/node_modules/pi-lens/vendor/grammars/tree-sitter-cue.wasm +0 -0
- package/node_modules/pi-mcp-adapter/CHANGELOG.md +49 -0
- package/node_modules/pi-mcp-adapter/README.md +51 -6
- package/node_modules/pi-mcp-adapter/agent-dir.ts +12 -4
- package/node_modules/pi-mcp-adapter/cli.js +188 -5
- package/node_modules/pi-mcp-adapter/commands.ts +128 -22
- package/node_modules/pi-mcp-adapter/config.ts +28 -10
- package/node_modules/pi-mcp-adapter/direct-tools.ts +23 -19
- 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/mcp-setup-panel.ts +2 -1
- package/node_modules/pi-mcp-adapter/metadata-cache.ts +46 -25
- package/node_modules/pi-mcp-adapter/package-mcp-loader.ts +168 -0
- package/node_modules/pi-mcp-adapter/package.json +4 -1
- package/node_modules/pi-mcp-adapter/proxy-modes.ts +5 -4
- package/node_modules/pi-mcp-adapter/request-headers-command.ts +330 -0
- package/node_modules/pi-mcp-adapter/search-ranking.ts +92 -22
- package/node_modules/pi-mcp-adapter/server-manager.ts +145 -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-metadata.ts +38 -18
- package/node_modules/pi-mcp-adapter/tool-result-renderer.ts +44 -4
- package/node_modules/pi-mcp-adapter/types.ts +95 -10
- 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 +38 -14
- package/node_modules/pi-web-access/anysearch.ts +4 -2
- package/node_modules/pi-web-access/auth-fetch.ts +148 -0
- package/node_modules/pi-web-access/brave.ts +16 -4
- package/node_modules/pi-web-access/chrome-cookies.ts +110 -23
- package/node_modules/pi-web-access/curator-page.ts +8 -3
- package/node_modules/pi-web-access/curator-server.ts +5 -1
- package/node_modules/pi-web-access/exa.ts +18 -7
- package/node_modules/pi-web-access/extract.ts +134 -37
- package/node_modules/pi-web-access/fetch-params.ts +17 -3
- package/node_modules/pi-web-access/firecrawl.ts +172 -12
- package/node_modules/pi-web-access/gemini-search.ts +33 -7
- package/node_modules/pi-web-access/index.ts +160 -104
- package/node_modules/pi-web-access/package.json +2 -2
- 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/query-rewrite.ts +51 -0
- package/node_modules/pi-web-access/serper.ts +211 -0
- package/node_modules/pi-web-access/summary-model-scope.ts +12 -4
- package/node_modules/pi-web-access/summary-review.ts +51 -23
- 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/node_modules/pi-web-access/youtube-extract.ts +2 -2
- package/package.json +13 -13
|
@@ -9,12 +9,18 @@
|
|
|
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";
|
|
15
16
|
import { findNearestMarkerRoot } from "./path-utils.js";
|
|
16
17
|
import { safeSpawnAsync } from "./safe-spawn.js";
|
|
17
|
-
import { createAvailabilityChecker, getManagedToolEnvironment, resolveAvailableOrInstall, } from "./dispatch/runners/utils/runner-helpers.js";
|
|
18
|
+
import { createAvailabilityChecker, findManagedNodeToolBinary, getManagedToolEnvironment, resolveAvailableOrInstall, } from "./dispatch/runners/utils/runner-helpers.js";
|
|
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";
|
|
18
24
|
const EMPTY_RESULT = {
|
|
19
25
|
success: false,
|
|
20
26
|
issues: [],
|
|
@@ -56,13 +62,118 @@ export function readOverridePinnedPackageNames(targetDir) {
|
|
|
56
62
|
collectKeys(pkg.pnpm?.overrides);
|
|
57
63
|
return names;
|
|
58
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;
|
|
59
164
|
// --- Client ---
|
|
60
165
|
export class KnipClient {
|
|
61
166
|
knipAvailability = createAvailabilityChecker("knip", ".cmd", ["--version"], {
|
|
62
167
|
environment: (cwd) => getManagedToolEnvironment("knip", cwd),
|
|
63
168
|
unclassifiedFailureOutcome: "missing",
|
|
169
|
+
fastPath: () => findManagedNodeToolBinary("knip"),
|
|
64
170
|
});
|
|
65
|
-
|
|
171
|
+
/**
|
|
172
|
+
* Client-side memo. Only a DURABLE verdict is latched — a transient probe
|
|
173
|
+
* failure expires, so an installed knip becomes available again without a
|
|
174
|
+
* host restart (#1467).
|
|
175
|
+
*/
|
|
176
|
+
availabilityLatch = createAvailabilityLatch();
|
|
66
177
|
knipCommand = "knip";
|
|
67
178
|
ensureInFlight = null;
|
|
68
179
|
log;
|
|
@@ -80,11 +191,22 @@ export class KnipClient {
|
|
|
80
191
|
* in-flight promise; completing clears the slot.
|
|
81
192
|
*/
|
|
82
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();
|
|
83
201
|
constructor(verbose = false) {
|
|
84
202
|
this.log = verbose
|
|
85
203
|
? createSubsystemLogger("knip")
|
|
86
204
|
: () => { };
|
|
87
205
|
}
|
|
206
|
+
/** Re-arm content-keyed reuse at the session boundary. */
|
|
207
|
+
resetSessionState() {
|
|
208
|
+
this.completedByProject.clear();
|
|
209
|
+
}
|
|
88
210
|
/**
|
|
89
211
|
* Find the nearest directory with a project/knip config marker.
|
|
90
212
|
*
|
|
@@ -104,12 +226,17 @@ export class KnipClient {
|
|
|
104
226
|
return findNearestMarkerRoot(startDir, ["package.json", "knip.json", "knip.ts", "knip.config.js", "knip.config.ts"], { boundaries: [".git", ".hg", ".svn"], homeDir: homeDirOverride });
|
|
105
227
|
}
|
|
106
228
|
/**
|
|
107
|
-
* Check if knip CLI is available, auto-install if not
|
|
229
|
+
* Check if knip CLI is available, auto-install if not.
|
|
230
|
+
*
|
|
231
|
+
* The memo returns `null` when the last verdict was transient and its
|
|
232
|
+
* cooldown has expired, which re-enters the probe. That is the difference
|
|
233
|
+
* between "knip is missing" (a fact worth caching) and "the probe timed out"
|
|
234
|
+
* (a moment worth retrying).
|
|
108
235
|
*/
|
|
109
236
|
async ensureAvailable() {
|
|
110
|
-
|
|
111
|
-
if (
|
|
112
|
-
return
|
|
237
|
+
const memo = this.availabilityLatch.read();
|
|
238
|
+
if (memo !== null)
|
|
239
|
+
return memo;
|
|
113
240
|
if (this.ensureInFlight)
|
|
114
241
|
return this.ensureInFlight;
|
|
115
242
|
this.ensureInFlight = this.doEnsureAvailable();
|
|
@@ -121,11 +248,39 @@ export class KnipClient {
|
|
|
121
248
|
}
|
|
122
249
|
}
|
|
123
250
|
async doEnsureAvailable() {
|
|
124
|
-
const
|
|
125
|
-
|
|
126
|
-
if (resolved)
|
|
251
|
+
const cwd = process.cwd();
|
|
252
|
+
const resolved = await resolveAvailableOrInstall(this.knipAvailability, "knip", cwd);
|
|
253
|
+
if (resolved !== null) {
|
|
127
254
|
this.knipCommand = resolved;
|
|
128
|
-
|
|
255
|
+
this.availabilityLatch.noteAvailable();
|
|
256
|
+
return true;
|
|
257
|
+
}
|
|
258
|
+
const verdict = this.knipAvailability.getVerdict(cwd);
|
|
259
|
+
this.availabilityLatch.noteUnavailable(verdict.outcome ?? "missing", verdict.cause ?? "not-found");
|
|
260
|
+
return false;
|
|
261
|
+
}
|
|
262
|
+
/**
|
|
263
|
+
* The single place a knip-unavailable result is worded. A transient probe
|
|
264
|
+
* failure must never be reported as "install knip" — knip is on disk.
|
|
265
|
+
*/
|
|
266
|
+
unavailableResult() {
|
|
267
|
+
const verdict = this.knipAvailability.getVerdict(process.cwd());
|
|
268
|
+
const transient = verdict.outcome === "transient";
|
|
269
|
+
const retryAfterMs = verdict.retryAtMs
|
|
270
|
+
? Math.max(0, verdict.retryAtMs - Date.now())
|
|
271
|
+
: undefined;
|
|
272
|
+
return {
|
|
273
|
+
...EMPTY_RESULT,
|
|
274
|
+
failureKind: transient ? "unavailable-transient" : "unavailable-missing",
|
|
275
|
+
summary: describeUnavailability({
|
|
276
|
+
tool: "Knip",
|
|
277
|
+
installHint: "npm install -D knip",
|
|
278
|
+
outcome: verdict.outcome,
|
|
279
|
+
cause: verdict.cause,
|
|
280
|
+
elapsedMs: verdict.elapsedMs,
|
|
281
|
+
retryAfterMs,
|
|
282
|
+
}),
|
|
283
|
+
};
|
|
129
284
|
}
|
|
130
285
|
/**
|
|
131
286
|
* Run knip analysis on the project.
|
|
@@ -137,8 +292,13 @@ export class KnipClient {
|
|
|
137
292
|
*
|
|
138
293
|
* Re-entrancy safe: concurrent calls resolving to the same project
|
|
139
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.
|
|
140
300
|
*/
|
|
141
|
-
async analyze(cwd, _ignore) {
|
|
301
|
+
async analyze(cwd, _ignore, options = {}) {
|
|
142
302
|
const targetDir = this.resolveProjectRoot(cwd || process.cwd());
|
|
143
303
|
if (!targetDir) {
|
|
144
304
|
// No package.json / knip config anywhere up the tree. Running knip
|
|
@@ -151,33 +311,97 @@ export class KnipClient {
|
|
|
151
311
|
summary: "No project root found; knip skipped",
|
|
152
312
|
};
|
|
153
313
|
}
|
|
154
|
-
if (!(await this.ensureAvailable())) {
|
|
155
|
-
return {
|
|
156
|
-
...EMPTY_RESULT,
|
|
157
|
-
summary: "Knip not available. Install with: npm install -D knip",
|
|
158
|
-
};
|
|
159
|
-
}
|
|
160
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())) {
|
|
328
|
+
return this.unavailableResult();
|
|
329
|
+
}
|
|
161
330
|
const existing = this.inFlight.get(key);
|
|
162
331
|
if (existing) {
|
|
163
332
|
this.log(`Analysis already in flight for ${key}; sharing result`);
|
|
164
333
|
return existing;
|
|
165
334
|
}
|
|
166
|
-
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(() => {
|
|
167
348
|
this.inFlight.delete(key);
|
|
168
349
|
});
|
|
169
350
|
this.inFlight.set(key, promise);
|
|
170
351
|
return promise;
|
|
171
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
|
+
}
|
|
172
379
|
async runAnalyze(targetDir) {
|
|
173
380
|
// Cache dir is routed through pi-lens's project-data-dir convention (NOT
|
|
174
381
|
// knip's own default `./node_modules/.cache/knip`) so it lives alongside
|
|
175
382
|
// every other project cache (see cache-manager.ts, call-graph.ts) and is
|
|
176
383
|
// covered by the existing `.pi-lens/` gitignore entry.
|
|
177
384
|
//
|
|
178
|
-
//
|
|
179
|
-
//
|
|
180
|
-
//
|
|
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.
|
|
181
405
|
const cacheLocation = path.join(getProjectDataDir(targetDir), "cache", "knip");
|
|
182
406
|
// knip (verified against 6.26.0) silently fails to persist the cache when
|
|
183
407
|
// `--cache-location` points at a directory that doesn't exist yet: its
|
|
@@ -193,6 +417,7 @@ export class KnipClient {
|
|
|
193
417
|
catch (err) {
|
|
194
418
|
this.log(`Failed to pre-create knip cache dir ${cacheLocation}: ${err}`);
|
|
195
419
|
}
|
|
420
|
+
this.pruneStaleGlobCache(cacheLocation);
|
|
196
421
|
const args = [
|
|
197
422
|
"--reporter=json",
|
|
198
423
|
"--include",
|
|
@@ -205,7 +430,14 @@ export class KnipClient {
|
|
|
205
430
|
"--cache-location",
|
|
206
431
|
cacheLocation,
|
|
207
432
|
];
|
|
208
|
-
|
|
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, {
|
|
209
441
|
timeout: ANALYSIS_TIMEOUT_MS,
|
|
210
442
|
cwd: targetDir,
|
|
211
443
|
env: await getManagedToolEnvironment("knip", targetDir),
|
|
@@ -217,13 +449,55 @@ export class KnipClient {
|
|
|
217
449
|
summary: `Error: ${result.error.message}`,
|
|
218
450
|
};
|
|
219
451
|
}
|
|
220
|
-
//
|
|
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.
|
|
221
461
|
const output = result.stdout || "";
|
|
222
|
-
this.log(`Knip output length: ${output.length}`);
|
|
462
|
+
this.log(`Knip output length: ${output.length}, exit status: ${result.status}`);
|
|
223
463
|
if (output.length < 500) {
|
|
224
464
|
this.log(`Knip output sample: ${output}`);
|
|
225
465
|
}
|
|
226
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.
|
|
227
501
|
return {
|
|
228
502
|
...EMPTY_RESULT,
|
|
229
503
|
success: true,
|
|
@@ -232,6 +506,69 @@ export class KnipClient {
|
|
|
232
506
|
}
|
|
233
507
|
return this.dropOverridePinnedDeps(this.parseOutput(output), targetDir);
|
|
234
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
|
+
}
|
|
235
572
|
/**
|
|
236
573
|
* Drop `dependency`/`devDependency` issues for a package that's also
|
|
237
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,
|