@herbertgao/pi-extensions 2026.9.0 → 2026.9.1
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/node_modules/@czottmann/pi-automode/CHANGELOG.md +13 -1
- package/node_modules/@czottmann/pi-automode/README.md +20 -0
- package/node_modules/@czottmann/pi-automode/docs/GLOSSARY.md +1 -1
- package/node_modules/@czottmann/pi-automode/docs/automode-classifier-flow.md +2 -1
- package/node_modules/@czottmann/pi-automode/docs/defaults.md +3 -2
- package/node_modules/@czottmann/pi-automode/extensions/auto-mode/classifier.ts +38 -2
- package/node_modules/@czottmann/pi-automode/extensions/auto-mode/constants.ts +5 -3
- package/node_modules/@czottmann/pi-automode/extensions/auto-mode/extension.ts +11 -3
- package/node_modules/@czottmann/pi-automode/package.json +1 -1
- package/node_modules/@pi-plugins/fast-mode/README.md +5 -3
- package/node_modules/@pi-plugins/fast-mode/dist/index.d.mts.map +1 -1
- package/node_modules/@pi-plugins/fast-mode/dist/index.mjs +20 -55
- package/node_modules/@pi-plugins/fast-mode/dist/index.mjs.map +1 -1
- package/node_modules/@pi-plugins/fast-mode/package.json +1 -1
- package/node_modules/pi-lens/CHANGELOG.md +988 -0
- package/node_modules/pi-lens/README.md +3 -0
- package/node_modules/pi-lens/config/biome/core.jsonc +11 -2
- package/node_modules/pi-lens/config/dependency-cruiser-eager-allowlist.json +13 -1
- package/node_modules/pi-lens/dist/clients/actionable-warnings-logger.js +2 -2
- package/node_modules/pi-lens/dist/clients/actionable-warnings.js +927 -80
- package/node_modules/pi-lens/dist/clients/agent-behavior-client.js +13 -4
- package/node_modules/pi-lens/dist/clients/ast-grep-client.js +123 -3
- package/node_modules/pi-lens/dist/clients/ast-grep-rule-manager.js +60 -5
- package/node_modules/pi-lens/dist/clients/ast-grep-tool-logger.js +2 -2
- package/node_modules/pi-lens/dist/clients/bash-file-access.js +1 -3
- package/node_modules/pi-lens/dist/clients/biome-client.js +9 -2
- package/node_modules/pi-lens/dist/clients/blocker-freshness.js +14 -0
- package/node_modules/pi-lens/dist/clients/bootstrap.js +509 -73
- package/node_modules/pi-lens/dist/clients/bounded-cache.js +152 -12
- package/node_modules/pi-lens/dist/clients/bounded-telemetry.js +59 -4
- package/node_modules/pi-lens/dist/clients/bundled-resource-health.js +113 -0
- package/node_modules/pi-lens/dist/clients/bus-events-logger.js +2 -2
- package/node_modules/pi-lens/dist/clients/cache/rule-cache.js +31 -4
- package/node_modules/pi-lens/dist/clients/cache-manager.js +105 -6
- package/node_modules/pi-lens/dist/clients/cache-observability.js +44 -18
- package/node_modules/pi-lens/dist/clients/cargo-manifest.js +422 -0
- package/node_modules/pi-lens/dist/clients/cascade-logger.js +2 -2
- package/node_modules/pi-lens/dist/clients/code-quality-warnings.js +13 -3
- package/node_modules/pi-lens/dist/clients/complexity-client.js +16 -5
- package/node_modules/pi-lens/dist/clients/config-core/deny.js +221 -0
- package/node_modules/pi-lens/dist/clients/config-core/index.js +47 -0
- package/node_modules/pi-lens/dist/clients/config-core/merge.js +357 -0
- package/node_modules/pi-lens/dist/clients/config-core/normalize.js +340 -0
- package/node_modules/pi-lens/dist/clients/config-core/process-spec.js +248 -0
- package/node_modules/pi-lens/dist/clients/config-core/provenance.js +171 -0
- package/node_modules/pi-lens/dist/clients/config-core/records.js +218 -0
- package/node_modules/pi-lens/dist/clients/config-core/resolve.js +125 -0
- package/node_modules/pi-lens/dist/clients/config-core/safe-object.js +78 -0
- package/node_modules/pi-lens/dist/clients/config-core/schema.js +167 -0
- package/node_modules/pi-lens/dist/clients/config-diagnostic-codes.js +281 -0
- package/node_modules/pi-lens/dist/clients/config-locations.js +160 -0
- package/node_modules/pi-lens/dist/clients/config-resolve.js +789 -0
- package/node_modules/pi-lens/dist/clients/config-schema.js +197 -0
- package/node_modules/pi-lens/dist/clients/config-warn.js +407 -0
- package/node_modules/pi-lens/dist/clients/dead-code-client.js +19 -14
- package/node_modules/pi-lens/dist/clients/dead-code-logger.js +2 -2
- package/node_modules/pi-lens/dist/clients/deadline-utils.js +178 -0
- package/node_modules/pi-lens/dist/clients/debug-handles.js +2 -2
- package/node_modules/pi-lens/dist/clients/debug-heap.js +3 -3
- package/node_modules/pi-lens/dist/clients/deferred-lsp-work.js +106 -0
- package/node_modules/pi-lens/dist/clients/degradation-ledger.js +113 -7
- package/node_modules/pi-lens/dist/clients/dependency-checker.js +8 -19
- package/node_modules/pi-lens/dist/clients/diagnostic-line-freshness.js +12 -9
- package/node_modules/pi-lens/dist/clients/diagnostic-logger.js +14 -4
- package/node_modules/pi-lens/dist/clients/dispatch/dispatcher.js +162 -18
- package/node_modules/pi-lens/dist/clients/dispatch/fact-store.js +97 -0
- package/node_modules/pi-lens/dist/clients/dispatch/integration.js +9 -7
- package/node_modules/pi-lens/dist/clients/dispatch/runners/actionlint.js +0 -1
- package/node_modules/pi-lens/dist/clients/dispatch/runners/ast-grep-napi.js +380 -26
- package/node_modules/pi-lens/dist/clients/dispatch/runners/biome-check.js +0 -1
- package/node_modules/pi-lens/dist/clients/dispatch/runners/cpp-check.js +0 -1
- package/node_modules/pi-lens/dist/clients/dispatch/runners/credo.js +0 -1
- package/node_modules/pi-lens/dist/clients/dispatch/runners/cue-vet.js +0 -1
- package/node_modules/pi-lens/dist/clients/dispatch/runners/dart-analyze.js +0 -1
- package/node_modules/pi-lens/dist/clients/dispatch/runners/detekt.js +0 -1
- package/node_modules/pi-lens/dist/clients/dispatch/runners/dotnet-build.js +0 -1
- package/node_modules/pi-lens/dist/clients/dispatch/runners/elixir-check.js +0 -1
- package/node_modules/pi-lens/dist/clients/dispatch/runners/eslint.js +0 -1
- package/node_modules/pi-lens/dist/clients/dispatch/runners/fact-rules.js +0 -1
- package/node_modules/pi-lens/dist/clients/dispatch/runners/fish-indent.js +0 -1
- package/node_modules/pi-lens/dist/clients/dispatch/runners/gleam-check.js +0 -1
- package/node_modules/pi-lens/dist/clients/dispatch/runners/go-vet.js +1 -3
- package/node_modules/pi-lens/dist/clients/dispatch/runners/golangci-lint.js +0 -1
- package/node_modules/pi-lens/dist/clients/dispatch/runners/hadolint.js +0 -1
- package/node_modules/pi-lens/dist/clients/dispatch/runners/helm-lint.js +0 -1
- package/node_modules/pi-lens/dist/clients/dispatch/runners/helm-render.js +0 -1
- package/node_modules/pi-lens/dist/clients/dispatch/runners/htmlhint.js +0 -1
- package/node_modules/pi-lens/dist/clients/dispatch/runners/javac.js +0 -1
- package/node_modules/pi-lens/dist/clients/dispatch/runners/ktlint.js +0 -1
- package/node_modules/pi-lens/dist/clients/dispatch/runners/lsp.js +0 -1
- package/node_modules/pi-lens/dist/clients/dispatch/runners/markdownlint.js +0 -1
- package/node_modules/pi-lens/dist/clients/dispatch/runners/mypy.js +0 -1
- package/node_modules/pi-lens/dist/clients/dispatch/runners/oxlint.js +13 -18
- package/node_modules/pi-lens/dist/clients/dispatch/runners/php-lint.js +0 -1
- package/node_modules/pi-lens/dist/clients/dispatch/runners/phpstan.js +0 -1
- package/node_modules/pi-lens/dist/clients/dispatch/runners/prisma-validate.js +0 -1
- package/node_modules/pi-lens/dist/clients/dispatch/runners/psscriptanalyzer.js +0 -1
- package/node_modules/pi-lens/dist/clients/dispatch/runners/pyright.js +7 -4
- package/node_modules/pi-lens/dist/clients/dispatch/runners/rubocop.js +0 -1
- package/node_modules/pi-lens/dist/clients/dispatch/runners/ruff.js +0 -1
- package/node_modules/pi-lens/dist/clients/dispatch/runners/rust-clippy.js +1 -3
- package/node_modules/pi-lens/dist/clients/dispatch/runners/shellcheck.js +0 -1
- package/node_modules/pi-lens/dist/clients/dispatch/runners/shfmt.js +0 -1
- package/node_modules/pi-lens/dist/clients/dispatch/runners/spellcheck.js +0 -1
- package/node_modules/pi-lens/dist/clients/dispatch/runners/spotbugs.js +0 -1
- package/node_modules/pi-lens/dist/clients/dispatch/runners/sqlfluff.js +0 -1
- package/node_modules/pi-lens/dist/clients/dispatch/runners/stylelint.js +0 -1
- package/node_modules/pi-lens/dist/clients/dispatch/runners/swiftlint.js +0 -1
- package/node_modules/pi-lens/dist/clients/dispatch/runners/taplo.js +0 -1
- package/node_modules/pi-lens/dist/clients/dispatch/runners/terragrunt.js +0 -1
- package/node_modules/pi-lens/dist/clients/dispatch/runners/tflint.js +0 -1
- package/node_modules/pi-lens/dist/clients/dispatch/runners/tree-sitter.js +0 -1
- package/node_modules/pi-lens/dist/clients/dispatch/runners/trivy-config.js +0 -1
- package/node_modules/pi-lens/dist/clients/dispatch/runners/utils/availability-policy.js +3 -0
- package/node_modules/pi-lens/dist/clients/dispatch/runners/utils/diagnostic-parsers.js +3 -4
- package/node_modules/pi-lens/dist/clients/dispatch/runners/utils/runner-helpers.js +194 -80
- package/node_modules/pi-lens/dist/clients/dispatch/runners/utils/toolchain-availability.js +84 -15
- package/node_modules/pi-lens/dist/clients/dispatch/runners/vale.js +0 -1
- package/node_modules/pi-lens/dist/clients/dispatch/runners/yamllint.js +0 -1
- package/node_modules/pi-lens/dist/clients/dispatch/runners/zig-check.js +0 -1
- package/node_modules/pi-lens/dist/clients/disposition-logger.js +3 -3
- package/node_modules/pi-lens/dist/clients/effective-config.js +403 -0
- package/node_modules/pi-lens/dist/clients/error-class.js +23 -0
- package/node_modules/pi-lens/dist/clients/event-loop-hold.js +274 -0
- package/node_modules/pi-lens/dist/clients/extension-log.js +2 -2
- package/node_modules/pi-lens/dist/clients/feature-hints.js +2 -1
- package/node_modules/pi-lens/dist/clients/file-time.js +6 -1
- package/node_modules/pi-lens/dist/clients/file-utils.js +112 -9
- package/node_modules/pi-lens/dist/clients/finding-delivery-gate.js +50 -13
- package/node_modules/pi-lens/dist/clients/format-service.js +6 -1
- package/node_modules/pi-lens/dist/clients/formatters.js +276 -102
- package/node_modules/pi-lens/dist/clients/freshness-cadence.js +17 -0
- package/node_modules/pi-lens/dist/clients/generated-artifacts.js +114 -19
- package/node_modules/pi-lens/dist/clients/generation-guard.js +4 -9
- package/node_modules/pi-lens/dist/clients/git-guard.js +1 -1
- package/node_modules/pi-lens/dist/clients/go-client.js +39 -0
- package/node_modules/pi-lens/dist/clients/gradle-ktfmt-style.js +252 -0
- package/node_modules/pi-lens/dist/clients/hashline-anchor.js +424 -0
- package/node_modules/pi-lens/dist/clients/hook-budgets.js +76 -0
- package/node_modules/pi-lens/dist/clients/host-edit-normalize.js +5 -2
- package/node_modules/pi-lens/dist/clients/host-ports.js +1 -1
- package/node_modules/pi-lens/dist/clients/installer/index.js +71 -52
- package/node_modules/pi-lens/dist/clients/instance-reaper.js +104 -230
- package/node_modules/pi-lens/dist/clients/instance-registry.js +6 -3
- package/node_modules/pi-lens/dist/clients/language-registry.js +595 -0
- package/node_modules/pi-lens/dist/clients/latency-logger.js +160 -2
- package/node_modules/pi-lens/dist/clients/ledger-bounds.js +13 -0
- package/node_modules/pi-lens/dist/clients/lens-config.js +141 -30
- package/node_modules/pi-lens/dist/clients/lens-engine.js +30 -37
- package/node_modules/pi-lens/dist/clients/lens-flag-registry.js +59 -6
- package/node_modules/pi-lens/dist/clients/log-cleanup.js +2 -2
- package/node_modules/pi-lens/dist/clients/lsp/aggregation.js +3 -1
- package/node_modules/pi-lens/dist/clients/lsp/client.js +168 -30
- package/node_modules/pi-lens/dist/clients/lsp/config.js +483 -158
- package/node_modules/pi-lens/dist/clients/lsp/diagnostic-binding.js +1 -1
- package/node_modules/pi-lens/dist/clients/lsp/edits.js +15 -2
- package/node_modules/pi-lens/dist/clients/lsp/index.js +676 -71
- package/node_modules/pi-lens/dist/clients/lsp/language.js +18 -169
- package/node_modules/pi-lens/dist/clients/lsp/launch.js +2 -1
- package/node_modules/pi-lens/dist/clients/lsp/pending-aux-coverage.js +5 -16
- package/node_modules/pi-lens/dist/clients/lsp/server.js +284 -147
- package/node_modules/pi-lens/dist/clients/lsp/session-roots.js +116 -23
- package/node_modules/pi-lens/dist/clients/lsp/spawn-history.js +2 -7
- package/node_modules/pi-lens/dist/clients/lsp/tsserver-sync.js +9 -2
- package/node_modules/pi-lens/dist/clients/lsp/workspace-diagnostics-cache.js +1 -1
- package/node_modules/pi-lens/dist/clients/lsp-mutation.js +163 -21
- package/node_modules/pi-lens/dist/clients/map-with-concurrency.js +36 -0
- package/node_modules/pi-lens/dist/clients/mcp/analyze.js +33 -4
- package/node_modules/pi-lens/dist/clients/mcp/session.js +5 -16
- package/node_modules/pi-lens/dist/clients/memory-sampler.js +8 -3
- package/node_modules/pi-lens/dist/clients/middle-man-analysis.js +2 -4
- package/node_modules/pi-lens/dist/clients/module-report.js +20 -45
- package/node_modules/pi-lens/dist/clients/mutating-tool.js +651 -0
- package/node_modules/pi-lens/dist/clients/mutation-attribution.js +368 -0
- package/node_modules/pi-lens/dist/clients/mutation-bridge.js +240 -0
- package/node_modules/pi-lens/dist/clients/ndjson-logger.js +247 -20
- package/node_modules/pi-lens/dist/clients/observed-mutation-sources.js +101 -0
- package/node_modules/pi-lens/dist/clients/observed-mutation.js +1215 -0
- package/node_modules/pi-lens/dist/clients/opaque-mutation-scan.js +68 -22
- package/node_modules/pi-lens/dist/clients/opengrep-config.js +4 -0
- package/node_modules/pi-lens/dist/clients/package-manager.js +195 -26
- package/node_modules/pi-lens/dist/clients/partial-edit-apply.js +359 -80
- package/node_modules/pi-lens/dist/clients/path-attribution-telemetry.js +23 -7
- package/node_modules/pi-lens/dist/clients/path-keyed-map.js +21 -2
- package/node_modules/pi-lens/dist/clients/path-utils.js +428 -13
- package/node_modules/pi-lens/dist/clients/persist-debounce.js +8 -1
- package/node_modules/pi-lens/dist/clients/php-cs-fixer-config.js +114 -0
- package/node_modules/pi-lens/dist/clients/pipeline.js +77 -16
- package/node_modules/pi-lens/dist/clients/probe-home-state.js +228 -0
- package/node_modules/pi-lens/dist/clients/process-bridge.js +66 -0
- package/node_modules/pi-lens/dist/clients/process-snapshot.js +68 -0
- package/node_modules/pi-lens/dist/clients/project-diagnostics/fresh-fetch.js +4 -3
- package/node_modules/pi-lens/dist/clients/project-diagnostics/runner-adapters/runner-findings.js +27 -3
- package/node_modules/pi-lens/dist/clients/project-diagnostics/scanner.js +51 -20
- package/node_modules/pi-lens/dist/clients/project-lens-config.js +393 -122
- package/node_modules/pi-lens/dist/clients/project-snapshot.js +52 -24
- package/node_modules/pi-lens/dist/clients/python-environment.js +217 -0
- package/node_modules/pi-lens/dist/clients/python-provenance.js +639 -0
- package/node_modules/pi-lens/dist/clients/quiet-window.js +6 -1
- package/node_modules/pi-lens/dist/clients/read-bridge.js +13 -21
- package/node_modules/pi-lens/dist/clients/read-expansion.js +9 -46
- package/node_modules/pi-lens/dist/clients/read-guard-logger.js +15 -4
- package/node_modules/pi-lens/dist/clients/read-guard-tool-lines.js +364 -212
- package/node_modules/pi-lens/dist/clients/read-guard.js +21 -0
- package/node_modules/pi-lens/dist/clients/resource-sampler.js +195 -96
- package/node_modules/pi-lens/dist/clients/review-graph/builder.js +152 -109
- package/node_modules/pi-lens/dist/clients/review-graph/service.js +55 -3
- package/node_modules/pi-lens/dist/clients/review-graph/shared-extraction-ir.js +7 -15
- package/node_modules/pi-lens/dist/clients/review-graph/workspace-modules.js +10 -74
- package/node_modules/pi-lens/dist/clients/review-graph-logger.js +9 -3
- package/node_modules/pi-lens/dist/clients/runtime-agent-end.js +18 -2
- package/node_modules/pi-lens/dist/clients/runtime-context.js +49 -16
- package/node_modules/pi-lens/dist/clients/runtime-coordinator.js +25 -6
- package/node_modules/pi-lens/dist/clients/runtime-session.js +139 -22
- package/node_modules/pi-lens/dist/clients/runtime-tool-call.js +168 -35
- package/node_modules/pi-lens/dist/clients/runtime-tool-result.js +797 -243
- package/node_modules/pi-lens/dist/clients/runtime-turn.js +1028 -53
- package/node_modules/pi-lens/dist/clients/rust-client.js +31 -0
- package/node_modules/pi-lens/dist/clients/safe-spawn.js +33 -10
- package/node_modules/pi-lens/dist/clients/sanitize.js +7 -1
- package/node_modules/pi-lens/dist/clients/scratch-tree-policy.js +1 -3
- package/node_modules/pi-lens/dist/clients/security-scan-client.js +3 -0
- package/node_modules/pi-lens/dist/clients/session-lifecycle.js +1 -1
- package/node_modules/pi-lens/dist/clients/session-start-observability.js +79 -0
- package/node_modules/pi-lens/dist/clients/sessionstart-logger.js +12 -3
- package/node_modules/pi-lens/dist/clients/sgconfig.js +6 -1
- package/node_modules/pi-lens/dist/clients/skills-resolver.js +105 -0
- package/node_modules/pi-lens/dist/clients/smells-rollup.js +2 -2
- package/node_modules/pi-lens/dist/clients/string-utils.js +13 -0
- package/node_modules/pi-lens/dist/clients/subagent-mode.js +17 -4
- package/node_modules/pi-lens/dist/clients/test-runner-client.js +176 -39
- package/node_modules/pi-lens/dist/clients/test-runner-delivery.js +239 -0
- package/node_modules/pi-lens/dist/clients/tool-definition.js +41 -1
- package/node_modules/pi-lens/dist/clients/tool-policy.js +91 -21
- package/node_modules/pi-lens/dist/clients/tree-sitter-cache.js +40 -40
- package/node_modules/pi-lens/dist/clients/tree-sitter-client.js +86 -48
- package/node_modules/pi-lens/dist/clients/tree-sitter-logger.js +2 -2
- package/node_modules/pi-lens/dist/clients/tree-sitter-query-loader.js +81 -1
- package/node_modules/pi-lens/dist/clients/tree-sitter-shared.js +51 -46
- package/node_modules/pi-lens/dist/clients/tree-sitter-symbol-extractor.js +28 -0
- package/node_modules/pi-lens/dist/clients/typos-config.js +5 -0
- package/node_modules/pi-lens/dist/clients/user-notify.js +6 -2
- package/node_modules/pi-lens/dist/clients/widget-state.js +191 -26
- package/node_modules/pi-lens/dist/clients/word-index-logger.js +2 -2
- package/node_modules/pi-lens/dist/clients/word-index-store.js +20 -5
- package/node_modules/pi-lens/dist/clients/word-index.js +243 -31
- package/node_modules/pi-lens/dist/clients/workspace-topology.js +8 -1
- package/node_modules/pi-lens/dist/clients/zizmor-config.js +3 -0
- package/node_modules/pi-lens/dist/index.js +64335 -54300
- package/node_modules/pi-lens/dist/mcp/analyze-cli.js +3 -1
- package/node_modules/pi-lens/dist/mcp/server.js +127 -5
- package/node_modules/pi-lens/dist/scripts/lib/process-scan.mjs +583 -0
- package/node_modules/pi-lens/dist/scripts/lib/skills-predicate.mjs +129 -0
- package/node_modules/pi-lens/dist/tools/effective-config.js +89 -0
- package/node_modules/pi-lens/dist/tools/lens-diagnostics.js +95 -24
- package/node_modules/pi-lens/dist/tools/lsp-diagnostics.js +67 -80
- package/node_modules/pi-lens/dist/tools/lsp-navigation.js +37 -16
- package/node_modules/pi-lens/dist/tools/shared.js +0 -1
- package/node_modules/pi-lens/docs/agent-guide.md +64 -1
- package/node_modules/pi-lens/docs/configuration.md +222 -0
- package/node_modules/pi-lens/docs/dependencies.md +3 -3
- package/node_modules/pi-lens/docs/features.md +44 -5
- package/node_modules/pi-lens/docs/language-coverage.md +2 -2
- package/node_modules/pi-lens/docs/pi-lens-fixer.md +25 -0
- package/node_modules/pi-lens/docs/pi-lens-investigator.md +25 -0
- package/node_modules/pi-lens/docs/pi-lens-reviewer.md +27 -0
- package/node_modules/pi-lens/docs/pi-lens-subagent.md +38 -0
- package/node_modules/pi-lens/docs/pi-lens-warden.md +55 -0
- package/node_modules/pi-lens/docs/public-api-stability.md +359 -0
- package/node_modules/pi-lens/docs/release-qa-baseline.md +182 -0
- package/node_modules/pi-lens/docs/subagent-compat.md +110 -30
- package/node_modules/pi-lens/docs/tree-sitter_rules_catalog.md +2 -2
- package/node_modules/pi-lens/package.json +15 -23
- package/node_modules/pi-lens/rules/tree-sitter-queries/python/python-cross-language-method.yml +3 -3
- package/node_modules/pi-lens/rules/tree-sitter-queries/python/python-hallucinated-import.yml +2 -2
- package/node_modules/pi-lens/rules/tree-sitter-queries/python/python-sql-injection.yml +12 -2
- package/node_modules/pi-lens/scripts/analyze-pi-lens-logs.mjs +192 -1
- package/node_modules/pi-lens/scripts/install-selftest.mjs +58 -2
- package/node_modules/pi-lens/scripts/lib/skills-predicate.mjs +129 -0
- package/node_modules/pi-lens/scripts/rpc-load-check.mjs +3 -1
- package/node_modules/pi-web-access/CHANGELOG.md +28 -0
- package/node_modules/pi-web-access/README.md +62 -15
- package/node_modules/pi-web-access/curator-page.ts +3 -1
- package/node_modules/pi-web-access/curator-server.ts +5 -1
- package/node_modules/pi-web-access/gemini-search.ts +8 -4
- package/node_modules/pi-web-access/github-extract.ts +242 -1
- package/node_modules/pi-web-access/index.ts +118 -64
- package/node_modules/pi-web-access/mistral-search.ts +281 -0
- package/node_modules/pi-web-access/package.json +2 -2
- package/node_modules/pi-web-access/perplexity.ts +14 -1
- package/node_modules/pi-web-access/utils.ts +23 -6
- package/node_modules/pi-web-access/xai-search.ts +96 -33
- package/package.json +5 -5
|
@@ -23,39 +23,7 @@ import { isBlocking, reconcileScanDiagnostics, } from "../clients/widget-state.j
|
|
|
23
23
|
import { baseName, compactRenderResult } from "./render-compact.js";
|
|
24
24
|
import { makeProgressReporter, scanningSummaryLine } from "./scan-progress.js";
|
|
25
25
|
import { isWarmAttached, tryWarmAttachedDiagnostics, } from "../clients/warm-attach.js";
|
|
26
|
-
|
|
27
|
-
".ts": [".ts", ".tsx", ".mts", ".cts"],
|
|
28
|
-
".tsx": [".ts", ".tsx", ".mts", ".cts"],
|
|
29
|
-
".js": [".js", ".jsx", ".mjs", ".cjs"],
|
|
30
|
-
".py": [".py", ".pyi"],
|
|
31
|
-
".rs": [".rs"],
|
|
32
|
-
".go": [".go"],
|
|
33
|
-
".rb": [".rb", ".rake", ".gemspec"],
|
|
34
|
-
".java": [".java"],
|
|
35
|
-
".kt": [".kt", ".kts"],
|
|
36
|
-
".swift": [".swift"],
|
|
37
|
-
".cs": [".cs"],
|
|
38
|
-
".cpp": [".cpp", ".cc", ".cxx", ".hpp", ".hxx"],
|
|
39
|
-
".c": [".c", ".h"],
|
|
40
|
-
".zig": [".zig", ".zon"],
|
|
41
|
-
".hs": [".hs", ".lhs"],
|
|
42
|
-
".ex": [".ex", ".exs"],
|
|
43
|
-
".gleam": [".gleam"],
|
|
44
|
-
".tf": [".tf", ".tfvars"],
|
|
45
|
-
".nix": [".nix"],
|
|
46
|
-
".sh": [".sh", ".bash", ".zsh"],
|
|
47
|
-
".php": [".php"],
|
|
48
|
-
".lua": [".lua"],
|
|
49
|
-
".dart": [".dart"],
|
|
50
|
-
".vue": [".vue"],
|
|
51
|
-
".svelte": [".svelte"],
|
|
52
|
-
".css": [".css", ".scss", ".less"],
|
|
53
|
-
".html": [".html", ".htm"],
|
|
54
|
-
".json": [".json", ".jsonc"],
|
|
55
|
-
".yaml": [".yaml", ".yml"],
|
|
56
|
-
".toml": [".toml"],
|
|
57
|
-
".prisma": [".prisma"],
|
|
58
|
-
};
|
|
26
|
+
import { extensionsForLanguage, SCAN_LANGUAGE_PRIORITY, } from "../clients/language-registry.js";
|
|
59
27
|
const MAX_FILES = 100;
|
|
60
28
|
const MAX_BATCH_FILES = 100;
|
|
61
29
|
const MAX_DIAGNOSTICS = 200;
|
|
@@ -192,9 +160,10 @@ function projectIgnorePredicate(root) {
|
|
|
192
160
|
* This walk was fully synchronous with NO yielding of any kind, bounded only by
|
|
193
161
|
* `maxFiles` *kept* — an ignored-heavy or cloud-backed (OneDrive/network) tree
|
|
194
162
|
* could traverse unboundedly many entries, and a single stalled `readdirSync`
|
|
195
|
-
* held the loop for the whole stall. It is also called once PER
|
|
196
|
-
* `runDirectoryDiagnostics`'s `
|
|
197
|
-
*
|
|
163
|
+
* held the loop for the whole stall. It is also called once PER FAMILY in
|
|
164
|
+
* `runDirectoryDiagnostics`'s `SCAN_LANGUAGE_PRIORITY` loop (#2434, grouped by
|
|
165
|
+
* family since #2458 fix-round F1), so a directory-mode `lsp_diagnostics`
|
|
166
|
+
* could pay that cost several times over.
|
|
198
167
|
*
|
|
199
168
|
* The traversal is deliberately still **depth-first with immediate descent**
|
|
200
169
|
* (not the shared stack-based `walkTreeStackAsync`): the `maxFiles` cap makes
|
|
@@ -456,13 +425,17 @@ async function collectDiagnosticsForFile(absPath, lspService, waitMs, serverScop
|
|
|
456
425
|
// `touchFile` is the authoritative collection boundary for every scope: it
|
|
457
426
|
// preserves per-touch timeout, content-binding, and silent-clean confirmation
|
|
458
427
|
// metadata while returning diagnostics from only the requested clients. The
|
|
459
|
-
//
|
|
460
|
-
//
|
|
428
|
+
// getDiagnostics fallback below remains for the two states a REAL service
|
|
429
|
+
// still reaches: the file read threw (no content to touch with), or the
|
|
430
|
+
// touch resolved no clients and returned `undefined` (clients/lsp/index.ts
|
|
431
|
+
// `touchFile`'s `no_clients`/`destroyed` returns). #2598 deleted the third
|
|
432
|
+
// reason — "an older/mock service without touchFile" — because the real
|
|
433
|
+
// `LSPService` has always defined the method unconditionally, so that arm
|
|
434
|
+
// was reachable only from a partial test double (AGENTS.md shape 7).
|
|
461
435
|
// #1179: the result is an explicit wrapper so side-channel fields survive
|
|
462
436
|
// array copies; confirmation was added when Marksman's lower-level clean verdict
|
|
463
437
|
// proved that a successful empty collection also needs explicit provenance.
|
|
464
438
|
let touched;
|
|
465
|
-
let usedTouch = false;
|
|
466
439
|
try {
|
|
467
440
|
content = fs.readFileSync(absPath, "utf-8");
|
|
468
441
|
if (isWarmAttached()) {
|
|
@@ -501,35 +474,25 @@ async function collectDiagnosticsForFile(absPath, lspService, waitMs, serverScop
|
|
|
501
474
|
};
|
|
502
475
|
}
|
|
503
476
|
}
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
clientScope: serverScope,
|
|
513
|
-
});
|
|
514
|
-
timedOut = touched?.inconclusive === true;
|
|
515
|
-
}
|
|
516
|
-
else {
|
|
517
|
-
await lspService.openFile(absPath, content, {
|
|
518
|
-
preserveDiagnostics: false,
|
|
519
|
-
});
|
|
520
|
-
}
|
|
477
|
+
touched = await lspService.touchFile(absPath, content, {
|
|
478
|
+
diagnostics: "document",
|
|
479
|
+
collectDiagnostics: true,
|
|
480
|
+
maxClientWaitMs: waitMs,
|
|
481
|
+
source: "lsp_diagnostics",
|
|
482
|
+
clientScope: serverScope,
|
|
483
|
+
});
|
|
484
|
+
timedOut = touched?.inconclusive === true;
|
|
521
485
|
}
|
|
522
486
|
catch {
|
|
523
487
|
// Non-fatal: getDiagnostics may still have stale/health information.
|
|
524
488
|
}
|
|
525
489
|
// Only fall through to the unscoped getDiagnostics() read when the touch
|
|
526
|
-
//
|
|
527
|
-
//
|
|
528
|
-
//
|
|
529
|
-
//
|
|
530
|
-
//
|
|
531
|
-
|
|
532
|
-
const diagnostics = usedTouch && touched !== undefined
|
|
490
|
+
// produced nothing to read — it threw, the file read threw before it ran, or
|
|
491
|
+
// it resolved no clients at all. When touched IS defined it's already the
|
|
492
|
+
// answer — reusing it is what makes serverScope:"primary" actually skip
|
|
493
|
+
// auxiliary scanners and drops the common case back to a single LSP round
|
|
494
|
+
// trip instead of two.
|
|
495
|
+
const diagnostics = touched !== undefined
|
|
533
496
|
? touched.diags
|
|
534
497
|
: await lspService.getDiagnostics(absPath, waitMs !== undefined ? "document" : "full");
|
|
535
498
|
// #586: honor each auxiliary profile's native inline-suppression comment
|
|
@@ -546,25 +509,25 @@ async function collectDiagnosticsForFile(absPath, lspService, waitMs, serverScop
|
|
|
546
509
|
fileRole: detectFileRole(absPath, content),
|
|
547
510
|
})
|
|
548
511
|
: diagnostics;
|
|
549
|
-
// #1095: surface the touch's content binding (only
|
|
550
|
-
// one; the
|
|
512
|
+
// #1095: surface the touch's content binding (only a touch that resolved
|
|
513
|
+
// clients carries one; the getDiagnostics fallback leaves it undefined →
|
|
551
514
|
// "unknown", no demotion).
|
|
552
|
-
const binding =
|
|
515
|
+
const binding = touched?.binding;
|
|
553
516
|
// #1470: `"partial"` counts here. `confirmedByTouch` feeds
|
|
554
517
|
// `canTrustTouchConfirmation`, which asks about the PRIMARY's own verdict —
|
|
555
518
|
// and a partial touch is one whose primary confirmed while an auxiliary was
|
|
556
519
|
// cut off. Excluding it would render "Primary LSP: unconfirmed" for a primary
|
|
557
520
|
// that did confirm. The coverage gap is carried separately, below.
|
|
558
|
-
const confirmedByTouch =
|
|
521
|
+
const confirmedByTouch = touchCompletedConfirmationPolicy(touched);
|
|
559
522
|
return {
|
|
560
523
|
diagnostics: filtered,
|
|
561
524
|
timedOut,
|
|
562
525
|
skipReason: touched?.skipReason,
|
|
563
526
|
confirmedByTouch,
|
|
564
|
-
// #1470: only a touch
|
|
565
|
-
//
|
|
566
|
-
//
|
|
567
|
-
unconfirmedServerIds:
|
|
527
|
+
// #1470: only a touch that resolved clients contributes a coverage gap;
|
|
528
|
+
// the getDiagnostics fallback never reports one, which is honest — that
|
|
529
|
+
// path claims no confirmation at all.
|
|
530
|
+
unconfirmedServerIds: touchCoverageGap(touched),
|
|
568
531
|
content,
|
|
569
532
|
binding,
|
|
570
533
|
};
|
|
@@ -1350,18 +1313,42 @@ async function runBatchFileDiagnostics(absPaths, severity, lspService, options)
|
|
|
1350
1313
|
},
|
|
1351
1314
|
};
|
|
1352
1315
|
}
|
|
1316
|
+
/**
|
|
1317
|
+
* The scan-language DECISION `runDirectoryDiagnostics` makes, pulled out as
|
|
1318
|
+
* its own function so `tests/tools/lsp-diagnostics-scan-family.test.ts` can
|
|
1319
|
+
* pin it against the golden `LANG_EXTENSIONS` table for every 1- and
|
|
1320
|
+
* 2-extension combination in that table's universe without spinning up one
|
|
1321
|
+
* real directory (and the full LSP-mocked tool) per combination — `hasMatch`
|
|
1322
|
+
* is the only I/O-shaped seam, so the caller decides whether it is backed by
|
|
1323
|
+
* a real `collectFiles` walk (production) or an in-memory extension-set probe
|
|
1324
|
+
* (tests).
|
|
1325
|
+
*
|
|
1326
|
+
* Walks `SCAN_LANGUAGE_PRIORITY`'s FAMILIES in order and unions each member
|
|
1327
|
+
* id's {@link extensionsForLanguage} into ONE `hasMatch` call — the first
|
|
1328
|
+
* family with any match wins the whole directory for this pass. Grouping by
|
|
1329
|
+
* family (not trying each id alone) is what makes a directory mixing BOTH
|
|
1330
|
+
* extensions of a registry-split pair (`.ts`+`.tsx`, `.css`+`.scss`, ...)
|
|
1331
|
+
* behavior-preserving vs the pre-#2434 bundled-key table: a flat per-id loop
|
|
1332
|
+
* stopped at the first id with ANY match, silently losing the sibling half of
|
|
1333
|
+
* a split pair present in the same directory (#2458 fix-round F1).
|
|
1334
|
+
*/
|
|
1335
|
+
export async function resolveDirectoryScanExtensions(hasMatch) {
|
|
1336
|
+
for (const family of SCAN_LANGUAGE_PRIORITY) {
|
|
1337
|
+
const exts = family.flatMap((languageId) => extensionsForLanguage(languageId));
|
|
1338
|
+
if (await hasMatch(exts)) {
|
|
1339
|
+
return exts;
|
|
1340
|
+
}
|
|
1341
|
+
}
|
|
1342
|
+
return undefined;
|
|
1343
|
+
}
|
|
1353
1344
|
async function runDirectoryDiagnostics(absPath, severity, lspService, options) {
|
|
1354
|
-
let extension;
|
|
1355
1345
|
let collectedFiles = [];
|
|
1356
1346
|
const isIgnored = projectIgnorePredicate(absPath);
|
|
1357
|
-
|
|
1358
|
-
collectedFiles = await collectFiles(absPath, exts, MAX_FILES + 1, isIgnored);
|
|
1359
|
-
|
|
1360
|
-
|
|
1361
|
-
|
|
1362
|
-
}
|
|
1363
|
-
}
|
|
1364
|
-
if (!extension || collectedFiles.length === 0) {
|
|
1347
|
+
await resolveDirectoryScanExtensions(async (exts) => {
|
|
1348
|
+
collectedFiles = await collectFiles(absPath, [...exts], MAX_FILES + 1, isIgnored);
|
|
1349
|
+
return collectedFiles.length > 0;
|
|
1350
|
+
});
|
|
1351
|
+
if (collectedFiles.length === 0) {
|
|
1365
1352
|
return {
|
|
1366
1353
|
content: [
|
|
1367
1354
|
{
|
|
@@ -10,6 +10,8 @@ import { Type } from "../clients/deps/typebox.js";
|
|
|
10
10
|
import { logLatency } from "../clients/latency-logger.js";
|
|
11
11
|
import { newLspMutationCorrelationId, recordLspMutationOutcome, } from "../clients/lsp-mutation.js";
|
|
12
12
|
import { uriToPath } from "../clients/path-utils.js";
|
|
13
|
+
import { escapeRegExp } from "../clients/string-utils.js";
|
|
14
|
+
import { isRecordableProjectPath } from "../clients/file-utils.js";
|
|
13
15
|
import { compactRenderResult } from "./render-compact.js";
|
|
14
16
|
import { applyWorkspaceEdit, summarizeWorkspaceEdit, } from "../clients/lsp/edits.js";
|
|
15
17
|
import { getLSPService, } from "../clients/lsp/index.js";
|
|
@@ -106,9 +108,6 @@ function emptyReasonForOperation(operation) {
|
|
|
106
108
|
return "no-call-hierarchy-results";
|
|
107
109
|
return "no-results";
|
|
108
110
|
}
|
|
109
|
-
function escapeRegExp(value) {
|
|
110
|
-
return value.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
111
|
-
}
|
|
112
111
|
function parseSymbolSelector(symbol) {
|
|
113
112
|
const trimmed = symbol.trim();
|
|
114
113
|
const match = /^([^#]*)(?:#(-?\d+))?$/.exec(trimmed);
|
|
@@ -530,16 +529,16 @@ async function openFileBestEffort(lspService, filePath, waitForDiagnostics = fal
|
|
|
530
529
|
if (!fileContent)
|
|
531
530
|
return;
|
|
532
531
|
try {
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
}
|
|
532
|
+
// #2598: `touchFile` is defined unconditionally on the real `LSPService`
|
|
533
|
+
// (clients/lsp/index.ts), so the former `typeof … === "function"` hedge
|
|
534
|
+
// and its `openFile` arm were reachable only from a partial test double
|
|
535
|
+
// (AGENTS.md shape 7). Nothing here reads the result — a touch that
|
|
536
|
+
// resolves no clients is already the no-op this helper wants.
|
|
537
|
+
await lspService.touchFile(filePath, fileContent, {
|
|
538
|
+
diagnostics: waitForDiagnostics ? "document" : "none",
|
|
539
|
+
source: "lsp_navigation",
|
|
540
|
+
clientScope: waitForDiagnostics ? "all" : "primary",
|
|
541
|
+
});
|
|
543
542
|
}
|
|
544
543
|
catch {
|
|
545
544
|
/* LSP server may not be ready yet — proceed anyway */
|
|
@@ -729,7 +728,7 @@ getFlag, mutationDeps) {
|
|
|
729
728
|
},
|
|
730
729
|
],
|
|
731
730
|
details: {
|
|
732
|
-
...
|
|
731
|
+
...payload.details,
|
|
733
732
|
failureKind: meta.failureKind,
|
|
734
733
|
},
|
|
735
734
|
};
|
|
@@ -779,15 +778,37 @@ getFlag, mutationDeps) {
|
|
|
779
778
|
if (requestedApply &&
|
|
780
779
|
["rename", "rename_file", "executeCommand"].includes(operation)) {
|
|
781
780
|
const cwd = ctx.cwd || ".";
|
|
781
|
+
// Name the specific LSP operation in the receipt rather than a
|
|
782
|
+
// generic "lsp-edit" tag, so a rename's change-log entry reads
|
|
783
|
+
// differently from an executeCommand-solicited edit (#2450).
|
|
784
|
+
const mutationSource = operation === "executeCommand" ? "lsp-execute-command" : "lsp-rename";
|
|
782
785
|
mutationContext = {
|
|
783
786
|
cwd,
|
|
784
787
|
correlationId: newLspMutationCorrelationId(_toolCallId),
|
|
785
|
-
tool:
|
|
786
|
-
source:
|
|
788
|
+
tool: `lsp_navigation:${operation}`,
|
|
789
|
+
source: mutationSource,
|
|
787
790
|
...mutationDeps,
|
|
788
791
|
readGuard: getFlag("no-read-guard", cwd)
|
|
789
792
|
? undefined
|
|
790
793
|
: mutationDeps?.readGuard,
|
|
794
|
+
// #2450 review round 2 (F4)/round 3 (F2, F4): the SAME gate
|
|
795
|
+
// `registerMutationBridge` applies internally in `index.ts`, so
|
|
796
|
+
// this directly-threaded path and the bridge fallback
|
|
797
|
+
// (`clients/lsp-mutation.ts`, reached when `mutationDeps` is
|
|
798
|
+
// absent/partial — e.g. the MCP server) agree on which files
|
|
799
|
+
// count as project source, rather than the direct path
|
|
800
|
+
// recording an ignored/vendor write the fallback would drop.
|
|
801
|
+
// `no-read-guard` is intentionally NOT checked here (round 3
|
|
802
|
+
// F2): it gates only the read-guard stamp above, the same
|
|
803
|
+
// canonical split `clients/runtime-tool-result.ts` applies
|
|
804
|
+
// (`:1120`, `:1485`) — bookkeeping (turn-state / receipts)
|
|
805
|
+
// still runs under `--no-read-guard`. Judge against the
|
|
806
|
+
// project root, not the request `cwd` (round 3 F4): a
|
|
807
|
+
// sub-package `cwd` must not read a sibling-package rename as
|
|
808
|
+
// external.
|
|
809
|
+
isRecordable: (filePath) => {
|
|
810
|
+
return isRecordableProjectPath(filePath, mutationDeps?.runtime?.projectRoot ?? cwd);
|
|
811
|
+
},
|
|
791
812
|
};
|
|
792
813
|
}
|
|
793
814
|
const isCallHierarchyTraversal = operation === "incomingCalls" || operation === "outgoingCalls";
|
|
@@ -45,10 +45,20 @@ On every write/edit, and at session/turn boundaries, pi-lens runs — without yo
|
|
|
45
45
|
| **Structural rules** | ast-grep (NAPI engine) + tree-sitter rules flag correctness/security smells. |
|
|
46
46
|
| **Opengrep security scan** | Always-on: per-edit via an auxiliary LSP, plus a cached project-wide CLI scan for `mode=full`. |
|
|
47
47
|
| **Other scanners** | Config-/presence-gated: gitleaks (secrets), trivy (CVEs/IaC/license), govulncheck (Go), knip/jscpd/madge (JS/TS dead-code/dupes/cycles), vulture (Python), zizmor (GH Actions), typos. |
|
|
48
|
-
| **Test-runner-on-write** | Related/affected tests are run asynchronously for the next turn's findings (edit-scoped, not a full-suite run). |
|
|
48
|
+
| **Test-runner-on-write** | Related/affected tests are run asynchronously for the next turn's findings (edit-scoped, not a full-suite run). Integration/e2e tests are never auto-fired — see below. |
|
|
49
49
|
| **Read-guard** | Tracks that you read a file before editing it; blocks/warns zero-read or stale-range edits. |
|
|
50
50
|
| **Context injection** | Injects session-start guidance and turn-end findings into your context (see §2). |
|
|
51
51
|
|
|
52
|
+
**Test-runner-on-write scope.** A built-in exclusion list keeps integration/e2e
|
|
53
|
+
suites out of the auto-fired batch — `**/integration/**`, `**/e2e/**`,
|
|
54
|
+
`**/*.integration.*`, `**/*.e2e.*` — since those commonly spawn external
|
|
55
|
+
processes (another CLI, a browser, a live provider) that don't belong on an
|
|
56
|
+
unattended per-edit turn. This is a fixed, built-in list; there is no
|
|
57
|
+
per-project config knob for it. If a runner itself fails to complete (a
|
|
58
|
+
timeout, or a missing provider/binary — not a failing assertion), pi-lens
|
|
59
|
+
delivers it as an advisory ("could not complete last turn"), not as a
|
|
60
|
+
"fix before continuing" blocker — you didn't introduce anything to fix.
|
|
61
|
+
|
|
52
62
|
You don't invoke these. They happen. Your job is to **read the results** and **respond**.
|
|
53
63
|
|
|
54
64
|
---
|
|
@@ -185,9 +195,62 @@ pi-lens writes to files **outside your own tool calls** (`docs/features.md`
|
|
|
185
195
|
- **`write` then `edit` on the same file, same turn:** the write's autofix
|
|
186
196
|
demotes to deferred too, so the file's mutation history stays coherent. This
|
|
187
197
|
resets at the next turn.
|
|
198
|
+
- **Any other tool that edits a file:** pi-lens recognizes it by the SHAPE of
|
|
199
|
+
its arguments rather than its name (`clients/mutating-tool.ts`), so a host or
|
|
200
|
+
extension tool called `replace` or `insert` gets the same chain `edit` gets:
|
|
201
|
+
a turn-state entry, a change-log receipt attributed to that tool, and a
|
|
202
|
+
*deferred* auto-fix. Its lines are resolved when the anchor is unambiguous
|
|
203
|
+
(roughly two-thirds of anchors in practice — `clients/hashline-anchor.ts`);
|
|
204
|
+
otherwise the mutation is recorded whole-file with lines unknown, and the
|
|
205
|
+
read-before-edit guard takes its no-line-info arm rather than guessing.
|
|
206
|
+
Deferred is the default for every edit-shaped tool pi-lens cannot place,
|
|
207
|
+
because formatting between the steps of a multi-call rewrite fights the tool
|
|
208
|
+
that is still writing.
|
|
209
|
+
- **A tool whose shape is unrecognized too:** pi-lens watches instead of
|
|
210
|
+
guessing (`clients/observed-mutation.ts`). A call that names a file gets a
|
|
211
|
+
bounded pre/post snapshot of THAT PATH — the file itself, or a directory's own
|
|
212
|
+
entries — and nothing else, so a write landing on a neighbouring file is never
|
|
213
|
+
attributed to it. Anything that changed is replayed through the same chain,
|
|
214
|
+
and the tool is then remembered as mutating: for this session on the first
|
|
215
|
+
sighting, persisted under the project's data directory on the second, so a
|
|
216
|
+
later session classifies it by name with no snapshot at all. Three quiet
|
|
217
|
+
observations in a row withdraw a session attribution again, and a withdrawn
|
|
218
|
+
tool can be learned back from a later real edit. An observation pi-lens could
|
|
219
|
+
not finish — a directory with more entries than it watches — counts as
|
|
220
|
+
neither, so a wide codemod is never written off on a look it never took. A
|
|
221
|
+
call that names
|
|
222
|
+
no file is caught at `agent_settled` by an incremental content check over the
|
|
223
|
+
files pi-lens has already read, written, diagnosed or opened on a language
|
|
224
|
+
server — a rotating window per turn, reading only what actually moved; a file
|
|
225
|
+
it has never seen has no baseline, so that last-resort net does not cover it,
|
|
226
|
+
and a file it cannot verify is reported as such rather than reformatted on a
|
|
227
|
+
timestamp alone.
|
|
188
228
|
- The conservative actionable-warnings autofix (LSP quickfixes, hard-capped)
|
|
189
229
|
is unchanged: it always runs at `agent_end`.
|
|
190
230
|
|
|
231
|
+
**Extension authors: record your own writes.** If your extension writes files
|
|
232
|
+
outside pi-lens's tool events — its own registered tool, a spawned rewriter —
|
|
233
|
+
tell pi-lens through the in-process mutation bridge, the write-side sibling of
|
|
234
|
+
the read bridge:
|
|
235
|
+
|
|
236
|
+
```js
|
|
237
|
+
const bridge = globalThis[Symbol.for("pi-lens:mutation-bridge")];
|
|
238
|
+
if (bridge?.version === 1) {
|
|
239
|
+
bridge.recordMutation({
|
|
240
|
+
filePath, // absolute path
|
|
241
|
+
kind: "edit", // "write" replaces the whole file; "edit" is partial
|
|
242
|
+
editRanges: [[12, 18]], // optional, 1-based inclusive
|
|
243
|
+
consumer: "my-extension",
|
|
244
|
+
});
|
|
245
|
+
}
|
|
246
|
+
```
|
|
247
|
+
|
|
248
|
+
Check `version` before calling; a version you do not recognize is unsupported.
|
|
249
|
+
Calling when pi-lens is absent or the guard is disabled is safe — the bridge is
|
|
250
|
+
missing or drops the call. `recordMutation` returns `true` when pi-lens took the
|
|
251
|
+
record and `false` when it dropped it, so you can count your own drops. pi-lens's
|
|
252
|
+
own `ast_grep_replace apply:true` records through this same bridge.
|
|
253
|
+
|
|
191
254
|
Consequences for you:
|
|
192
255
|
|
|
193
256
|
- Your exact written bytes may be reformatted/fixed. **This is expected pipeline
|
|
@@ -0,0 +1,222 @@
|
|
|
1
|
+
# Configuring pi-lens
|
|
2
|
+
|
|
3
|
+
There are **two** pi-lens config files:
|
|
4
|
+
|
|
5
|
+
| File | Scope | Notes |
|
|
6
|
+
| --- | --- | --- |
|
|
7
|
+
| `.pi-lens.json` | the project | Committed or not, your call. Nearest one wins **per field** — a package can override one setting without restating the repo root's. |
|
|
8
|
+
| `~/.pi-lens/config.json` | the machine | Your defaults across every project. `PI_LENS_CONFIG_PATH` relocates it. |
|
|
9
|
+
|
|
10
|
+
Both files have the same shape, with one exception noted below the example:
|
|
11
|
+
everything LSP-related lives under an `lsp` namespace inside them.
|
|
12
|
+
|
|
13
|
+
```jsonc
|
|
14
|
+
{
|
|
15
|
+
"$schema": "https://raw.githubusercontent.com/apmantza/pi-lens/master/docs/schema/pi-lens-config-v1.json",
|
|
16
|
+
"ignore": ["dist/**"],
|
|
17
|
+
"maxProjectFiles": 8000,
|
|
18
|
+
"rules": { "high-complexity": { "threshold": 25 } },
|
|
19
|
+
"lsp": {
|
|
20
|
+
"disabledServers": ["typos"],
|
|
21
|
+
"warmFiles": ["src/main.rs"],
|
|
22
|
+
"servers": {
|
|
23
|
+
"my-server": {
|
|
24
|
+
"name": "My Custom LSP",
|
|
25
|
+
"extensions": [".myext"],
|
|
26
|
+
"command": "my-lsp-server",
|
|
27
|
+
"args": ["--stdio"]
|
|
28
|
+
}
|
|
29
|
+
},
|
|
30
|
+
"serverOverrides": {
|
|
31
|
+
"rust": {
|
|
32
|
+
"initializationOptions": { "check": { "command": "clippy" } }
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
**Some settings are global-only.** A handful of switches — `lsp.enabled`
|
|
40
|
+
(`--no-lsp`), `tests.enabled`, `delta.enabled` and the other session-wide
|
|
41
|
+
toggles — are decided once for the machine, not per project, so writing one in a
|
|
42
|
+
`.pi-lens.json` does nothing. It is not ignored quietly: the project loader says
|
|
43
|
+
so, naming the key. `docs/settings.md` lists which flags are which.
|
|
44
|
+
|
|
45
|
+
## Which file wins
|
|
46
|
+
|
|
47
|
+
One order, lowest precedence first. A later tier replaces an earlier tier's
|
|
48
|
+
value **for that field only** — objects are merged field-wise, never replaced
|
|
49
|
+
whole, so setting one key never silently drops the rest of a section.
|
|
50
|
+
|
|
51
|
+
1. **global** — `~/.pi-lens/config.json`.
|
|
52
|
+
2. **project root** — the outermost `.pi-lens.json` at or above your working
|
|
53
|
+
directory.
|
|
54
|
+
3. **nested-project** — every `.pi-lens.json` between that root and your working
|
|
55
|
+
directory, outermost first. The nearest file wins, per field.
|
|
56
|
+
|
|
57
|
+
Those three are the tiers the config **files** resolve through, and they are the
|
|
58
|
+
only ones this resolution populates. Four more tiers are reserved in the
|
|
59
|
+
precedence table — `builtin` below them, and `env`, `cli`, `host` above — and
|
|
60
|
+
nothing writes into them yet; #2427 (env/CLI) and #2416 (host and project trust)
|
|
61
|
+
are what fill them in.
|
|
62
|
+
|
|
63
|
+
Until they do, environment variables and CLI flags are read by their own
|
|
64
|
+
accessors rather than through this resolution, and their effective precedence
|
|
65
|
+
for a pi-lens toggle is:
|
|
66
|
+
|
|
67
|
+
1. a `PI_LENS_*` environment variable set to `1` — checked first, and it wins
|
|
68
|
+
outright;
|
|
69
|
+
2. the matching `--lens-*` / `--no-*` CLI flag;
|
|
70
|
+
3. the nearest project `.pi-lens.json`, then the outer ones (project-scoped
|
|
71
|
+
settings only);
|
|
72
|
+
4. `~/.pi-lens/config.json`;
|
|
73
|
+
5. the built-in default.
|
|
74
|
+
|
|
75
|
+
Subsystem-specific env overrides follow the same shape: a
|
|
76
|
+
`PI_LENS_REVIEW_GRAPH_MAX_FILES` beats a `.pi-lens.json`'s
|
|
77
|
+
`reviewGraph.maxFiles`. `docs/environment-variables.md` and `docs/settings.md`
|
|
78
|
+
are the per-setting references.
|
|
79
|
+
|
|
80
|
+
### One exception: `lsp.disabledServers` is a denial, not a value
|
|
81
|
+
|
|
82
|
+
Ordinary settings are last-tier-wins. A **denial** is not, because the tier
|
|
83
|
+
that made it is usually the one you control and the tier that would override it
|
|
84
|
+
is usually one that arrived with somebody else's checkout.
|
|
85
|
+
|
|
86
|
+
`lsp.disabledServers` resolves as the **union of every tier's entries**. A
|
|
87
|
+
project `.pi-lens.json` can add to it and can never subtract from it, so a
|
|
88
|
+
repository cannot re-enable a server you turned off in
|
|
89
|
+
`~/.pi-lens/config.json`. There is no vocabulary for un-denying an entry: if
|
|
90
|
+
you change your mind, edit the file that denied. The provenance reports, per
|
|
91
|
+
denied server, the tier that contributed it.
|
|
92
|
+
|
|
93
|
+
```console
|
|
94
|
+
$ # which servers run for this file, and why
|
|
95
|
+
$ pilens_effective_config file=src/main.rs
|
|
96
|
+
✗ typos — disabled-by-config (global ~/.pi-lens/config.json → /lsp/disabledServers/0)
|
|
97
|
+
```
|
|
98
|
+
|
|
99
|
+
The union spans **both spellings**: a document's deprecated root keys
|
|
100
|
+
(`servers`, `serverOverrides`, `disabledServers`, `warmFiles`) are read
|
|
101
|
+
into the `lsp` namespace before any tier is merged, so one setting is resolved
|
|
102
|
+
once no matter which spelling each file uses. Migrating does not change the
|
|
103
|
+
answer, staying un-migrated is not a way around the denial, and a half-migrated
|
|
104
|
+
pair of files merges rather than one clobbering the other.
|
|
105
|
+
|
|
106
|
+
Two rules make the rest of the table unambiguous:
|
|
107
|
+
|
|
108
|
+
- **The search stops at `$HOME`.** pi-lens never reads a config file in your
|
|
109
|
+
home directory or above it. A stray `pi-lens.json` in `$HOME` (or at `C:\`)
|
|
110
|
+
is not adopted by every project on the machine. The machine-global file is
|
|
111
|
+
read by its own path, so it is unaffected.
|
|
112
|
+
- **The canonical spelling wins.** Where a legacy file or a legacy key means the
|
|
113
|
+
same thing as the canonical one, the canonical one is used — otherwise the
|
|
114
|
+
migration below could never be completed.
|
|
115
|
+
|
|
116
|
+
## Legacy locations (still read; being removed)
|
|
117
|
+
|
|
118
|
+
These are read for their deprecation window and then **removed**. Each one you
|
|
119
|
+
still have produces one warning per setting, naming exactly where to move it —
|
|
120
|
+
carrying the stable code `PILENS_CFG_0003` (a deprecated file) or
|
|
121
|
+
`PILENS_CFG_0002` (a deprecated key), so you can match or suppress on the code
|
|
122
|
+
rather than on the prose.
|
|
123
|
+
|
|
124
|
+
| Legacy | Move it to | Code |
|
|
125
|
+
| --- | --- | --- |
|
|
126
|
+
| `.pi-lens/lsp.json` | `.pi-lens.json` → `lsp.*` | `PILENS_CFG_0003` |
|
|
127
|
+
| `pi-lsp.json` | `.pi-lens.json` → `lsp.*` | `PILENS_CFG_0003` |
|
|
128
|
+
| `pi-lens.json` (undotted) | `.pi-lens.json` | `PILENS_CFG_0003` |
|
|
129
|
+
| `~/.pi-lens/lsp.json` | `~/.pi-lens/config.json` → `lsp.*` | `PILENS_CFG_0003` |
|
|
130
|
+
| `servers` at the file root | `lsp.servers` | `PILENS_CFG_0002` |
|
|
131
|
+
| `serverOverrides` at the file root | `lsp.serverOverrides` | `PILENS_CFG_0002` |
|
|
132
|
+
| `disabledServers` at the file root | `lsp.disabledServers` | `PILENS_CFG_0002` |
|
|
133
|
+
| `warmFiles` at the file root | `lsp.warmFiles` | `PILENS_CFG_0002` |
|
|
134
|
+
|
|
135
|
+
**Deprecated since 4.1.4. Read for the last time before 5.0.0.** The window is
|
|
136
|
+
declared as data in `clients/config-diagnostic-codes.ts`
|
|
137
|
+
(`DEPRECATED_CONFIG_SURFACES`) and enforced by test, so the schedule above and
|
|
138
|
+
the code cannot drift apart. `docs/public-api-stability.md` describes the policy
|
|
139
|
+
these dates instantiate.
|
|
140
|
+
|
|
141
|
+
A `.pi-lens.json` that mixes both spellings is fine while you migrate: the
|
|
142
|
+
canonical key wins, and the keys you have not moved yet keep working.
|
|
143
|
+
|
|
144
|
+
Only keys pi-lens actually recognizes get "move it to …" advice. A key in a
|
|
145
|
+
legacy file that is not a pi-lens setting at all — a typo, or a leftover from
|
|
146
|
+
another tool — cannot be migrated anywhere, so it gets the ordinary
|
|
147
|
+
unrecognized-key notice (`PILENS_CFG_0001`) and is counted in ONE whole-file
|
|
148
|
+
`PILENS_CFG_0003` notice for the file rather than being told to move.
|
|
149
|
+
|
|
150
|
+
## When a config is ignored
|
|
151
|
+
|
|
152
|
+
A file that cannot be read or parsed is **ignored, never partially applied** —
|
|
153
|
+
pi-lens runs on defaults for it and says so once, with the code
|
|
154
|
+
`PILENS_CFG_0001`. A field whose value does not match its declared type is
|
|
155
|
+
dropped on its own (`PILENS_CFG_0005`), and an unrecognized field is dropped
|
|
156
|
+
with a message naming the key (`PILENS_CFG_0004`). If resolving a file fails
|
|
157
|
+
internally the whole file is ignored and said so under its own code
|
|
158
|
+
(`PILENS_CFG_0008`), so "one field went missing" and "none of this file is in
|
|
159
|
+
effect" are never the same code. Nothing about your config is ever ignored
|
|
160
|
+
silently.
|
|
161
|
+
|
|
162
|
+
The number of notices one file can produce is bounded PER NOTICE LIST, because
|
|
163
|
+
the number of keys in a file is not. There are two lists, split by who composes
|
|
164
|
+
them rather than by what they say — both are about values that were rejected:
|
|
165
|
+
|
|
166
|
+
- what **resolving** the file produced — the per-field rejections
|
|
167
|
+
(`PILENS_CFG_0004`, `PILENS_CFG_0005`, `PILENS_CFG_0006`) together with the
|
|
168
|
+
deprecation notices (`PILENS_CFG_0002`, `PILENS_CFG_0003`), which share this
|
|
169
|
+
list;
|
|
170
|
+
- what the **loader** reading the file produced on its own — unknown top-level
|
|
171
|
+
keys and settings it refused (`PILENS_CFG_0001`).
|
|
172
|
+
|
|
173
|
+
Each list is bounded at 20 records: up to 19 notices plus, when the bound bit,
|
|
174
|
+
a single `PILENS_CFG_0007` summary giving the count that was suppressed, so a
|
|
175
|
+
truncated list always says that it is truncated. That summary is about the
|
|
176
|
+
LIST, not about the file: a config whose every setting was applied can still
|
|
177
|
+
overflow the bound, so it is worded and recorded as a summary rather than as an
|
|
178
|
+
ignored config.
|
|
179
|
+
|
|
180
|
+
One notice is never suppressed by that bound: `PILENS_CFG_0008`, which says the
|
|
181
|
+
whole file is out of effect. It is not one more rejected key competing for a
|
|
182
|
+
slot — it is what tells you the rejections above it are no longer the whole
|
|
183
|
+
story — so it is kept however full the list already was.
|
|
184
|
+
|
|
185
|
+
## Asking what is actually in effect
|
|
186
|
+
|
|
187
|
+
You never have to reconstruct the table above by hand. `pilens_effective_config`
|
|
188
|
+
(MCP) and `effective_config` (pi) return the resolved configuration with the
|
|
189
|
+
provenance of **every** leaf — the tier, the file, the key, and the trust
|
|
190
|
+
decision that applied — plus, for a file you name, its language, every LSP
|
|
191
|
+
server with the reason it was selected or denied, and the runners that would
|
|
192
|
+
dispatch. That is the answer to "why is this running" and to "why is this *not*
|
|
193
|
+
running", without reading a log.
|
|
194
|
+
|
|
195
|
+
Naming a `file` resolves the configuration **at that file's own directory**,
|
|
196
|
+
which is where the runtime decides from — so a nested `repo/sub/.pi-lens.json`
|
|
197
|
+
layer contributes to the answer, appears in the reported document list, and is
|
|
198
|
+
named as the file behind any decision it made. The walk runs upward and is
|
|
199
|
+
**confined to `cwd`**: a `file` that resolves outside `cwd` — including a
|
|
200
|
+
sibling package in the same monorepo — is rejected rather than answered from
|
|
201
|
+
its own unrelated tree, because the per-file answer is only ever correct when
|
|
202
|
+
it is a superset of the workspace's own; the rejection names the `cwd` it was
|
|
203
|
+
measured against and the remedy is to re-query with `cwd` set to that file's
|
|
204
|
+
own workspace. A confined `file` always passes back through the workspace's
|
|
205
|
+
own documents on its way up, so they are always included too.
|
|
206
|
+
|
|
207
|
+
It reports **sources, never values**. Environment values never appear, a custom
|
|
208
|
+
server's command line is cut to the binary itself, and every path is rewritten
|
|
209
|
+
`~`-relative. There is no un-redacted mode: the un-redacted data is the config
|
|
210
|
+
file you already have.
|
|
211
|
+
|
|
212
|
+
`pilens_health` embeds the same provenance as **counts per tier** — how many
|
|
213
|
+
settings each source decided, and which `PILENS_CFG_*` notices the resolution
|
|
214
|
+
produced — so a session's config posture is visible without the detail.
|
|
215
|
+
|
|
216
|
+
## See also
|
|
217
|
+
|
|
218
|
+
- `docs/globalconfig.md` — every key of `~/.pi-lens/config.json`, in detail.
|
|
219
|
+
- `docs/settings.md` — the CLI flags and what they map to.
|
|
220
|
+
- `docs/environment-variables.md` — the `PI_LENS_*` tier.
|
|
221
|
+
- `docs/public-api-stability.md` — what `x-stability`, the `PILENS_CFG_*` codes,
|
|
222
|
+
and the deprecation windows commit pi-lens to.
|
|
@@ -40,9 +40,9 @@ Auto-install behavior depends on gate type:
|
|
|
40
40
|
| `intelephense` | PHP LSP | Yes | Flow-gated |
|
|
41
41
|
| `bash-language-server` | Bash LSP | Yes | Language-default |
|
|
42
42
|
| `yaml-language-server` | YAML LSP | Yes | Language-default |
|
|
43
|
-
| `vscode-
|
|
44
|
-
| `vscode-css-languageserver` | CSS LSP
|
|
45
|
-
| `vscode-html-languageserver-bin` | HTML LSP
|
|
43
|
+
| `vscode-json-language-server` | JSON LSP (`vscode-langservers-extracted`) | Yes | Language-default |
|
|
44
|
+
| `vscode-css-languageserver` | CSS LSP (`vscode-langservers-extracted`) | Yes | Language-default |
|
|
45
|
+
| `vscode-html-languageserver-bin` | HTML LSP (`vscode-langservers-extracted`) | Yes | Language-default |
|
|
46
46
|
| `svelte-language-server` | Svelte LSP | Yes | Flow-gated |
|
|
47
47
|
| `@vue/language-server` | Vue LSP | Yes | Flow-gated |
|
|
48
48
|
| `opengrep` | Experimental security dispatch | Auto-install | Local config / explicit opt-in |
|