@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
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
import * as path from "node:path";
|
|
2
2
|
import { isTestMode } from "./env-utils.js";
|
|
3
|
-
import {
|
|
3
|
+
import { getGlobalPiLensLogDir } from "./probe-home-state.js";
|
|
4
4
|
import { createNdjsonLogger } from "./ndjson-logger.js";
|
|
5
5
|
import { getMaxLogSizeMB } from "./log-cleanup.js";
|
|
6
6
|
import { normalizeLoggedPath } from "./path-utils.js";
|
|
7
|
-
const LATENCY_LOG_DIR =
|
|
7
|
+
const LATENCY_LOG_DIR = getGlobalPiLensLogDir();
|
|
8
8
|
const LATENCY_LOG_FILE = path.join(LATENCY_LOG_DIR, "latency.log");
|
|
9
9
|
const writer = createNdjsonLogger({
|
|
10
10
|
filePath: LATENCY_LOG_FILE,
|
|
@@ -79,6 +79,11 @@ let recentPhases = [];
|
|
|
79
79
|
* usage records. It reports no new work and therefore cannot own last-phase
|
|
80
80
|
* stall attribution.
|
|
81
81
|
*
|
|
82
|
+
* #2249: `concurrent_session_bind_rollup` is the same shape as
|
|
83
|
+
* `session_end_bus_rollup`/`path_attribution_verified_rollup` above — a
|
|
84
|
+
* zero-duration session-end summary of records already logged individually,
|
|
85
|
+
* not new work of its own.
|
|
86
|
+
*
|
|
82
87
|
* #2044: `test_runner_failed_target_state` is a zero-duration decision after a
|
|
83
88
|
* bounded filesystem probe. The surrounding turn-end test-selection phase owns
|
|
84
89
|
* any real work, so this row must not replace it in stall attribution.
|
|
@@ -101,8 +106,11 @@ const LAST_PHASE_EXCLUDED = new Set([
|
|
|
101
106
|
"lsp_scanner_coverage_gap",
|
|
102
107
|
"lsp_notify_resync_deferred",
|
|
103
108
|
"lsp_notify_write_late_landed",
|
|
109
|
+
"lsp_notify_stall_cpu_busy",
|
|
104
110
|
"degradation_ledger",
|
|
105
111
|
"path_attribution_verified_rollup",
|
|
112
|
+
"concurrent_session_bind_rollup",
|
|
113
|
+
"auxiliary_readiness",
|
|
106
114
|
]);
|
|
107
115
|
/**
|
|
108
116
|
* The last non-`loop_block` phase logged, or undefined if none yet. Carries its
|
|
@@ -520,6 +528,156 @@ export function resetCurrentPhaseForSession() {
|
|
|
520
528
|
liveBrackets.clear();
|
|
521
529
|
closedBrackets = [];
|
|
522
530
|
}
|
|
531
|
+
/**
|
|
532
|
+
* Phases already written ONCE for the current session (#2526).
|
|
533
|
+
*
|
|
534
|
+
* Session-scoped telemetry bookkeeping, which is this module's own domain —
|
|
535
|
+
* the same reason `liveBrackets` and `recentPhases` live here rather than in
|
|
536
|
+
* each producer. A producer that is called many times per session but whose
|
|
537
|
+
* record is a SESSION fact (`config_resolved`: `loadLSPConfig` runs at session
|
|
538
|
+
* start, per served root, and on the first edit, all resolving the same
|
|
539
|
+
* config) asks here instead of keeping its own latch, so the "one row per
|
|
540
|
+
* session" a log reader counts against is a property of the logger rather than
|
|
541
|
+
* a convention each producer re-implements.
|
|
542
|
+
*/
|
|
543
|
+
const oncePerSessionPhases = new Set();
|
|
544
|
+
/**
|
|
545
|
+
* The identity every once-per-session record of THIS session is stamped with
|
|
546
|
+
* (#2526 review round 2, F2).
|
|
547
|
+
*
|
|
548
|
+
* A line-oriented log reader cannot join two files by adjacency: sessionstart.
|
|
549
|
+
* log's start lines and latency.log's phase rows interleave differently, rotate
|
|
550
|
+
* independently, and (for the warm MCP server) can span days. The first round
|
|
551
|
+
* therefore SUBTRACTED row counts from start-line counts, which silently
|
|
552
|
+
* assumed the two counted the same population — they do not, and the
|
|
553
|
+
* mismatch both masked total silence and manufactured a permanent false
|
|
554
|
+
* deficit. An id makes the join explicit: `handleSessionStart` publishes it
|
|
555
|
+
* beside its expectation, the record carries it, and the analyzer matches.
|
|
556
|
+
*
|
|
557
|
+
* It is minted HERE, beside the claim set it identifies, so "which session is
|
|
558
|
+
* this record from" and "has this session already recorded" can never answer
|
|
559
|
+
* from different sessions.
|
|
560
|
+
*
|
|
561
|
+
* Minted at module load too, not only on re-arm: the warm MCP server resolves
|
|
562
|
+
* config through `ensureReady` without any session boundary of its own, and a
|
|
563
|
+
* record with no id at all would be unjoinable rather than merely unmatched.
|
|
564
|
+
*/
|
|
565
|
+
let sessionRecordSeq = 0;
|
|
566
|
+
function mintSessionRecordId() {
|
|
567
|
+
sessionRecordSeq += 1;
|
|
568
|
+
return `${process.pid.toString(36)}-${Date.now().toString(36)}-${sessionRecordSeq.toString(36)}`;
|
|
569
|
+
}
|
|
570
|
+
let sessionRecordId = mintSessionRecordId();
|
|
571
|
+
/**
|
|
572
|
+
* The current session's record identity — an opaque, process-local token.
|
|
573
|
+
*
|
|
574
|
+
* Deliberately NOT the host's session id: that is user-facing conversation
|
|
575
|
+
* identity pi-lens does not otherwise write to disk, and the join only needs
|
|
576
|
+
* "the same session", not "which conversation".
|
|
577
|
+
*/
|
|
578
|
+
export function currentSessionRecordId() {
|
|
579
|
+
return sessionRecordId;
|
|
580
|
+
}
|
|
581
|
+
/**
|
|
582
|
+
* The claim key. A phase is claimed per SCOPE (#2526 review round 2, F3):
|
|
583
|
+
* `config_resolved` is a fact about a (session, project root) pair, and the
|
|
584
|
+
* warm MCP server serves N roots from one process — keying on the phase name
|
|
585
|
+
* alone recorded the first root's documents and silently dropped every other
|
|
586
|
+
* root's, so a legacy config in project B could never surface its smell.
|
|
587
|
+
*
|
|
588
|
+
* `scope` is REQUIRED (#2526 review round 3, S3 — narrowed from optional):
|
|
589
|
+
* the one production caller always passes one, and an unscoped claim is the
|
|
590
|
+
* exact shape F3 found unsafe — a phase-only key recording the first caller
|
|
591
|
+
* and silently dropping every later one under a different scope. A future
|
|
592
|
+
* producer with no natural scope can pass a constant string; that is still an
|
|
593
|
+
* explicit choice, not a silently-defaulted one.
|
|
594
|
+
*/
|
|
595
|
+
function claimKey(phase, scope) {
|
|
596
|
+
return `${phase}\0${scope}`;
|
|
597
|
+
}
|
|
598
|
+
/**
|
|
599
|
+
* Claim the session's one record for `phase` within `scope`.
|
|
600
|
+
*
|
|
601
|
+
* Returns true exactly once per session and scope; every later call for the
|
|
602
|
+
* same pair returns false until {@link resetOncePerSessionPhases} re-arms it.
|
|
603
|
+
* Callers should claim BEFORE building the payload, so a claim that loses the
|
|
604
|
+
* race costs nothing.
|
|
605
|
+
*/
|
|
606
|
+
export function claimPhaseOncePerSession(phase, scope) {
|
|
607
|
+
const key = claimKey(phase, scope);
|
|
608
|
+
if (oncePerSessionPhases.has(key))
|
|
609
|
+
return false;
|
|
610
|
+
oncePerSessionPhases.add(key);
|
|
611
|
+
return true;
|
|
612
|
+
}
|
|
613
|
+
/**
|
|
614
|
+
* Release ONE scope's claim for `phase` — the narrow sibling of
|
|
615
|
+
* {@link releaseOncePerSessionPhase}, which releases every scope of a phase.
|
|
616
|
+
*
|
|
617
|
+
* #2518 review F1. A claim is a promise that this session's record for the
|
|
618
|
+
* (phase, scope) pair has already been written, which holds only while the
|
|
619
|
+
* state that record described is still there. When that state is DROPPED —
|
|
620
|
+
* the session-root registry evicting a root, taking its resolved LSP config
|
|
621
|
+
* with it — the next load for that scope is a genuine SECOND resolution, and
|
|
622
|
+
* its row is the only thing that says what the reloaded config was. So the
|
|
623
|
+
* claim is released with the state it described; a claim outliving its state
|
|
624
|
+
* silences the record for the rest of the session, which is catalog shape 17
|
|
625
|
+
* pointed at a positive-observability record.
|
|
626
|
+
*
|
|
627
|
+
* Bounded by the caller: releases are as frequent as the evictions that cause
|
|
628
|
+
* them, and those are counted (`lsp-session-root-evicted`).
|
|
629
|
+
*/
|
|
630
|
+
export function releasePhaseClaim(phase, scope) {
|
|
631
|
+
oncePerSessionPhases.delete(claimKey(phase, scope));
|
|
632
|
+
}
|
|
633
|
+
/**
|
|
634
|
+
* Release every scope's claim for ONE phase, without touching the others
|
|
635
|
+
* (#2526 review round 2, S1).
|
|
636
|
+
*
|
|
637
|
+
* A producer's own `resetForTests` needs its own phase re-armed, not a blanket
|
|
638
|
+
* clear of a shared session-scoped structure: the blanket call reached into
|
|
639
|
+
* claims other producers own and, worse, re-minted the session identity as a
|
|
640
|
+
* side effect of an unrelated module's reset.
|
|
641
|
+
*/
|
|
642
|
+
export function releaseOncePerSessionPhase(phase) {
|
|
643
|
+
const prefix = `${phase}\0`;
|
|
644
|
+
for (const key of oncePerSessionPhases) {
|
|
645
|
+
if (key.startsWith(prefix))
|
|
646
|
+
oncePerSessionPhases.delete(key);
|
|
647
|
+
}
|
|
648
|
+
}
|
|
649
|
+
/**
|
|
650
|
+
* Re-arm every once-per-session phase claim for a new session, and mint the
|
|
651
|
+
* new session's record identity.
|
|
652
|
+
*
|
|
653
|
+
* PLACEMENT (#2526 review round 2, F1): this is called from index.ts's
|
|
654
|
+
* `session_start` closure, from BEHIND the #473 concurrent-secondary gate,
|
|
655
|
+
* beside `resetCurrentPhaseForSession` — and NOT from inside
|
|
656
|
+
* `handleSessionStart`. index.ts resolves this session's config in
|
|
657
|
+
* `ensureLSPConfigInitialized` BEFORE it calls the handler, so a re-arm inside
|
|
658
|
+
* the handler fires between the session's own two resolutions: the ensure
|
|
659
|
+
* writes a row, the handler wipes the claim, and the deferred `loadLSPConfig`
|
|
660
|
+
* writes a second row for the same session. The first session of a process got
|
|
661
|
+
* two rows and every later one (whose ensure the process-lifetime
|
|
662
|
+
* `_lspConfigInitializedCwds` memo short-circuits) got one, which is
|
|
663
|
+
* unrecoverable for any per-session count.
|
|
664
|
+
*
|
|
665
|
+
* A latch that is never re-armed silences its record for the rest of the
|
|
666
|
+
* PROCESS (AGENTS.md catalog shape 17), which for a positive-observability
|
|
667
|
+
* record is the exact silence it exists to end — so the re-arm must exist; it
|
|
668
|
+
* just has to sit ahead of the session's first resolution rather than in the
|
|
669
|
+
* middle of them.
|
|
670
|
+
*
|
|
671
|
+
* The warm MCP server (`clients/mcp/session.ts` calls `handleSessionStart`
|
|
672
|
+
* directly, never through index.ts) therefore keeps ONE identity for the life
|
|
673
|
+
* of the process. That is the honest answer for it: a warm server has no
|
|
674
|
+
* session boundary, its "session" is the process, and F3's per-root scoping is
|
|
675
|
+
* what gives it one record per served root.
|
|
676
|
+
*/
|
|
677
|
+
export function resetOncePerSessionPhases() {
|
|
678
|
+
oncePerSessionPhases.clear();
|
|
679
|
+
sessionRecordId = mintSessionRecordId();
|
|
680
|
+
}
|
|
523
681
|
export function logLatency(entry) {
|
|
524
682
|
const ts = new Date().toISOString();
|
|
525
683
|
if (entry.type === "phase" &&
|
|
@@ -9,6 +9,19 @@
|
|
|
9
9
|
*/
|
|
10
10
|
/** The single truncation bound for every ledger field, and for the reasons callers build. */
|
|
11
11
|
export const LEDGER_FIELD_MAX = 200;
|
|
12
|
+
/**
|
|
13
|
+
* How many retained entries the ledger keeps per kind — and therefore the bound
|
|
14
|
+
* any producer of ledger-bound records sizes itself to.
|
|
15
|
+
*
|
|
16
|
+
* Moved here from `degradation-ledger.ts` (#2426) for the reason this module's
|
|
17
|
+
* doc comment already gives: `config-core/records.ts` bounds its collector to
|
|
18
|
+
* this number, and reading it off the LEDGER made the config core import a sink
|
|
19
|
+
* it is documented not to touch ("Pure: no state, no I/O, no ledger writes").
|
|
20
|
+
* That import also broke three suites that `vi.mock` the ledger wholesale — the
|
|
21
|
+
* exact failure mode this leaf exists to prevent — and closed seven import
|
|
22
|
+
* cycles once the config loaders started resolving through the core.
|
|
23
|
+
*/
|
|
24
|
+
export const DEGRADATION_ENTRIES_PER_KIND = 20;
|
|
12
25
|
export function normalizeForLedger(value) {
|
|
13
26
|
return String(value ?? "unknown");
|
|
14
27
|
}
|
|
@@ -1,41 +1,44 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
3
|
-
import * as fs from "node:fs";
|
|
4
|
-
import * as os from "node:os";
|
|
1
|
+
import { resetIgnoredConfigWarnCache, warnIgnoredConfigOnce, } from "./config-warn.js";
|
|
2
|
+
import { errorClassName } from "./error-class.js";
|
|
5
3
|
import * as path from "node:path";
|
|
6
4
|
import { assignFlagConfigSection, flagConfigSectionKeys, flagValueFromConfig, getLensFlagSpec, GLOBAL_NON_FLAG_CONFIG_SECTIONS, LENS_FLAGS, readFlagConfigValue, } from "./lens-flag-registry.js";
|
|
5
|
+
import { CANONICAL_GLOBAL_CONFIG_FILE, getPiLensGlobalConfigPath, GLOBAL_CONFIG_LOCATIONS, LEGACY_ROOT_LSP_KEYS, } from "./config-locations.js";
|
|
6
|
+
// Re-exported so this module's own, pre-existing import sites (`./lens-config.js`
|
|
7
|
+
// / `../lens-config.js`) keep working. The function itself now lives in
|
|
8
|
+
// `config-locations.ts` (#2426 review round 3, S1) — see the doc comment there.
|
|
9
|
+
export { getPiLensGlobalConfigPath } from "./config-locations.js";
|
|
10
|
+
import { ignoredRecordCollector, readConfigDocument, reportConfigReadFailure, reportPiLensConfigRecords, resolveOnePiLensConfigDocument, } from "./config-resolve.js";
|
|
7
11
|
import { findNestedProjectMutationValue, } from "./project-lens-config.js";
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
12
|
+
/**
|
|
13
|
+
* The canonical global location, looked up rather than constructed, so a change
|
|
14
|
+
* to the shared table cannot leave this loader describing a file that is no
|
|
15
|
+
* longer canonical.
|
|
16
|
+
*/
|
|
17
|
+
function globalCanonicalLocation() {
|
|
18
|
+
const location = GLOBAL_CONFIG_LOCATIONS.find((candidate) => candidate.relativePath === CANONICAL_GLOBAL_CONFIG_FILE);
|
|
19
|
+
if (!location) {
|
|
20
|
+
throw new Error(`no canonical global config location named ${CANONICAL_GLOBAL_CONFIG_FILE}`);
|
|
21
|
+
}
|
|
22
|
+
return location;
|
|
13
23
|
}
|
|
14
|
-
const warnedInvalidGlobalConfigs = new Set();
|
|
15
24
|
/**
|
|
16
25
|
* Same warn-once-per-(path, reason) contract as project-lens-config.ts's
|
|
17
26
|
* `warnInvalidConfigOnce` — a malformed global config value is logged once
|
|
18
|
-
* and then treated as absent, rather than silently dropped (#792).
|
|
27
|
+
* and then treated as absent, rather than silently dropped (#792). Since #2418
|
|
28
|
+
* the latch, the log line, the durable ledger row, and the stable-coded
|
|
29
|
+
* notification all live in the one shared seam.
|
|
19
30
|
*/
|
|
20
|
-
function warnInvalidGlobalConfigOnce(configPath, reason) {
|
|
21
|
-
|
|
22
|
-
if (warnedInvalidGlobalConfigs.has(key))
|
|
23
|
-
return;
|
|
24
|
-
warnedInvalidGlobalConfigs.add(key);
|
|
25
|
-
const message = `ignoring invalid global config ${configPath}: ${reason}`;
|
|
26
|
-
logExtension({
|
|
31
|
+
function warnInvalidGlobalConfigOnce(configPath, reason, code) {
|
|
32
|
+
warnIgnoredConfigOnce({
|
|
27
33
|
subsystem: "lens-config",
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
34
|
+
file: configPath,
|
|
35
|
+
reason,
|
|
36
|
+
...(code === undefined ? {} : { code }),
|
|
31
37
|
});
|
|
32
|
-
// HUMAN-audience too: a config the user wrote is being ignored. Routed
|
|
33
|
-
// through the host's own render path (#1333), never a raw write.
|
|
34
|
-
notifyUserDegradation(`pi-lens: ${message}`);
|
|
35
38
|
}
|
|
36
39
|
/** For tests that need to force the warn-once cache to reset between cases. */
|
|
37
40
|
export function resetGlobalConfigWarnCache() {
|
|
38
|
-
|
|
41
|
+
resetIgnoredConfigWarnCache("lens-config");
|
|
39
42
|
}
|
|
40
43
|
function asConfigObject(value) {
|
|
41
44
|
return value && typeof value === "object" && !Array.isArray(value)
|
|
@@ -43,12 +46,82 @@ function asConfigObject(value) {
|
|
|
43
46
|
: undefined;
|
|
44
47
|
}
|
|
45
48
|
export function loadPiLensGlobalConfig(configPath = getPiLensGlobalConfigPath()) {
|
|
49
|
+
const location = globalCanonicalLocation();
|
|
50
|
+
// #2445: this used to be `JSON.parse(fs.readFileSync(...))` inside a bare
|
|
51
|
+
// `catch { return undefined; }`, so a malformed `~/.pi-lens/config.json`
|
|
52
|
+
// produced ZERO signal of its own — no log line, no ledger row, no
|
|
53
|
+
// notification. The only thing a user saw was the LSP loader's report of the
|
|
54
|
+
// SAME file, mislabelled "ignoring invalid LSP config", because that loader
|
|
55
|
+
// resolves the canonical global too. Both halves are fixed together: the
|
|
56
|
+
// read/parse failure is reported here, under `lens-config`, and
|
|
57
|
+
// `reportConfigReadFailure` derives the subsystem from the DOCUMENT so the
|
|
58
|
+
// LSP loader's report of this file lands under `lens-config` as well and the
|
|
59
|
+
// warn-once latch collapses the two into one honest notice.
|
|
60
|
+
const outcome = readConfigDocument(configPath);
|
|
61
|
+
if (outcome.status === "missing")
|
|
62
|
+
return undefined;
|
|
63
|
+
if (outcome.status === "error") {
|
|
64
|
+
reportConfigReadFailure({
|
|
65
|
+
file: configPath,
|
|
66
|
+
location,
|
|
67
|
+
tier: "global",
|
|
68
|
+
error: outcome.error,
|
|
69
|
+
sourceText: outcome.sourceText,
|
|
70
|
+
});
|
|
71
|
+
return undefined;
|
|
72
|
+
}
|
|
73
|
+
// Every notice this projection composes is BUFFERED and bounded once, at the
|
|
74
|
+
// end, through the SAME `ignoredRecordCollector` the project loader uses
|
|
75
|
+
// (#2426 review round 6, F3; round 7, F2). It used to report each one the
|
|
76
|
+
// moment it was composed, with no collector anywhere in this function, so
|
|
77
|
+
// the unknown-top-level-key scan below — whose count is the number of keys
|
|
78
|
+
// the user typed — put 100 notifications on screen for a 100-key
|
|
79
|
+
// `~/.pi-lens/config.json` while the project loader's identical scan of an
|
|
80
|
+
// identical file produced 19 and a count. Two changelog fragments already
|
|
81
|
+
// claimed one bound for every producer; this is the producer that did not
|
|
82
|
+
// have one.
|
|
83
|
+
//
|
|
84
|
+
// Round 6 gave it that bound by COPYING the project loader's, which left two
|
|
85
|
+
// spellings of one record literal differing only in a tier. Round 7 moved
|
|
86
|
+
// the seam into `config-resolve.ts`, which both loaders already import, and
|
|
87
|
+
// made the tier an argument. This loader never passes a `{ parseError }`:
|
|
88
|
+
// its read/parse failure is reported above by `reportConfigReadFailure`,
|
|
89
|
+
// before the projection starts.
|
|
90
|
+
//
|
|
91
|
+
// The flush is in a `finally` so a throw in the projection still delivers
|
|
92
|
+
// what was composed before it, on top of the whole-config record the catch
|
|
93
|
+
// adds.
|
|
94
|
+
const { note, records: notedRecords } = ignoredRecordCollector(configPath, "global");
|
|
46
95
|
try {
|
|
47
|
-
const parsed =
|
|
48
|
-
if (!parsed || typeof parsed !== "object")
|
|
96
|
+
const parsed = outcome.value;
|
|
97
|
+
if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) {
|
|
98
|
+
// The other half of the same silence: a file that PARSES but is a list
|
|
99
|
+
// or a scalar is not a config either, and was dropped without a word.
|
|
100
|
+
note("top-level value must be an object");
|
|
49
101
|
return undefined;
|
|
50
|
-
|
|
51
|
-
|
|
102
|
+
}
|
|
103
|
+
// Through the #2425 core (#2426). The canonical global file is resolved as
|
|
104
|
+
// a single `global`-tier source against the canonical schema, so the depth
|
|
105
|
+
// bound, the prototype-key policy and the declared `lsp.*` types apply to
|
|
106
|
+
// `~/.pi-lens/config.json` exactly as they do to `.pi-lens.json`. The
|
|
107
|
+
// field-by-field projection below is unchanged and keeps owning the
|
|
108
|
+
// per-key prose its tests assert on — the core validates the SHAPE, this
|
|
109
|
+
// function still decides what a bad value is called.
|
|
110
|
+
const document = {
|
|
111
|
+
tier: "global",
|
|
112
|
+
file: configPath,
|
|
113
|
+
location,
|
|
114
|
+
value: parsed,
|
|
115
|
+
};
|
|
116
|
+
const resolved = resolveOnePiLensConfigDocument(document);
|
|
117
|
+
// EVERY record this document produced (#2426 review round 3, F1) — not
|
|
118
|
+
// filtered to what this loader "owns". `reportPiLensConfigRecords` derives
|
|
119
|
+
// the reporting subsystem per record; the warn-once latch collapses a
|
|
120
|
+
// duplicate report of the SAME record from the LSP loader's resolution of
|
|
121
|
+
// this same file (it resolves the canonical global too) into one notice.
|
|
122
|
+
reportPiLensConfigRecords(resolved.records);
|
|
123
|
+
const raw = resolved.value;
|
|
124
|
+
const warnInvalid = note;
|
|
52
125
|
const config = {};
|
|
53
126
|
for (const spec of LENS_FLAGS) {
|
|
54
127
|
if (spec.readGlobal)
|
|
@@ -127,9 +200,22 @@ export function loadPiLensGlobalConfig(configPath = getPiLensGlobalConfigPath())
|
|
|
127
200
|
// (`GLOBAL_NON_FLAG_CONFIG_SECTIONS`, which co-locates `$schema` and the
|
|
128
201
|
// hand-parsed namespaces beside the registry). Adding a flag needs no
|
|
129
202
|
// edit here; adding a namespace is a one-line edit in that one constant.
|
|
203
|
+
//
|
|
204
|
+
// `LEGACY_ROOT_LSP_KEYS` joins them for #2426 review round 4, F1. The four
|
|
205
|
+
// legacy root LSP keys are read out of THIS file by the LSP loader and
|
|
206
|
+
// their values are applied, exactly as they are in a project
|
|
207
|
+
// `.pi-lens.json` — where `PROJECT_FOREIGN_CONFIG_NAMESPACES` has
|
|
208
|
+
// tolerated them since #2426. The global scan never got the same
|
|
209
|
+
// treatment, so `~/.pi-lens/config.json` with a root `warmFiles` both
|
|
210
|
+
// honored the setting and called it a typo in the same session. Spread
|
|
211
|
+
// from the registry-derived list rather than restated: `lens-config.ts`
|
|
212
|
+
// already imports `config-locations.ts`, which derives it from
|
|
213
|
+
// `DEPRECATED_CONFIG_SURFACES`, so the accepted set and the removal
|
|
214
|
+
// schedule cannot drift apart and there is no second copy of the names.
|
|
130
215
|
const knownGlobalConfigKeys = new Set([
|
|
131
216
|
...flagConfigSectionKeys(LENS_FLAGS),
|
|
132
217
|
...GLOBAL_NON_FLAG_CONFIG_SECTIONS,
|
|
218
|
+
...LEGACY_ROOT_LSP_KEYS,
|
|
133
219
|
]);
|
|
134
220
|
for (const key of Object.keys(raw)) {
|
|
135
221
|
if (!knownGlobalConfigKeys.has(key)) {
|
|
@@ -138,9 +224,34 @@ export function loadPiLensGlobalConfig(configPath = getPiLensGlobalConfigPath())
|
|
|
138
224
|
}
|
|
139
225
|
return config;
|
|
140
226
|
}
|
|
141
|
-
catch {
|
|
227
|
+
catch (error) {
|
|
228
|
+
// #2426 review round 5, S-C. The other half of #2445's silence. The
|
|
229
|
+
// read/parse failure above now reports, but everything AFTER the parse —
|
|
230
|
+
// the resolution through the core and the field-by-field projection —
|
|
231
|
+
// still sat under a bare `catch { return undefined }`, so a throw in any
|
|
232
|
+
// of it dropped the WHOLE global config with no log line, no ledger row
|
|
233
|
+
// and no notification: pi-lens ran on defaults and said nothing, which is
|
|
234
|
+
// the exact defect #2445 was filed for.
|
|
235
|
+
//
|
|
236
|
+
// `PILENS_CFG_0008` ("config resolution failed; whole configuration
|
|
237
|
+
// ignored") rather than `0001`, and the ERROR CLASS only, never its
|
|
238
|
+
// message, which could quote the file — the same rule `resolveConfig`'s
|
|
239
|
+
// own guard follows for the same reason. Round 5 used `0005` here, which
|
|
240
|
+
// is registered as a per-FIELD rejection: a user matching on it would
|
|
241
|
+
// have expected one setting to be missing rather than the whole file
|
|
242
|
+
// (#2426 review round 6, S1). `errorClassName` (#2451) is the ONE
|
|
243
|
+
// implementation of "class name, never the message" — this loader
|
|
244
|
+
// already imports `config-warn.js` for the rest of the seam, so it could
|
|
245
|
+
// call `normalizeParseErrorReason({ classOnly: true })` directly, but
|
|
246
|
+
// calling the same leaf `config-warn.ts` itself delegates to keeps every
|
|
247
|
+
// caller of this guarantee, `config-core/` included, on ONE
|
|
248
|
+
// implementation rather than two that happen to agree today.
|
|
249
|
+
warnInvalidGlobalConfigOnce(configPath, `global config could not be interpreted (${errorClassName(error)}); configuration ignored`, "PILENS_CFG_0008");
|
|
142
250
|
return undefined;
|
|
143
251
|
}
|
|
252
|
+
finally {
|
|
253
|
+
reportPiLensConfigRecords(notedRecords());
|
|
254
|
+
}
|
|
144
255
|
}
|
|
145
256
|
export function getGlobalIgnorePatterns(configPath) {
|
|
146
257
|
return loadPiLensGlobalConfig(configPath)?.ignore ?? [];
|
|
@@ -18,6 +18,7 @@ import { minimatch } from "./deps/minimatch.js";
|
|
|
18
18
|
import { getDiagnosticTracker } from "./diagnostic-tracker.js";
|
|
19
19
|
import { getLatencyReports, } from "./dispatch/integration.js";
|
|
20
20
|
import { getResourceFootprint as getResourceFootprintSnapshot, } from "./instance-registry.js";
|
|
21
|
+
import { extensionsForLanguageToken } from "./language-registry.js";
|
|
21
22
|
import { initLSPConfig } from "./lsp/config.js";
|
|
22
23
|
import { getLSPService } from "./lsp/index.js";
|
|
23
24
|
import { acquireWarmWordIndex } from "./mcp/analyze.js";
|
|
@@ -35,6 +36,12 @@ export { acknowledgeTurnEnd, runSessionStart, runTurnEnd, runTurnEndForIpc, } fr
|
|
|
35
36
|
export { moduleReport, readEnclosing, readSymbol, renderCompactModuleReport, } from "./module-report.js";
|
|
36
37
|
export { projectReport, renderCompactProjectReport, } from "./project-report.js";
|
|
37
38
|
export { createDefaultHostPorts, } from "./host-ports.js";
|
|
39
|
+
// Effective-config introspection (#2427). A facade rather than a wrapper for
|
|
40
|
+
// the same reason the others are: the computation reaches into the config
|
|
41
|
+
// resolution, the LSP registry and the dispatch plan at once, and putting that
|
|
42
|
+
// composition here would make this file the fourth place that knows how a
|
|
43
|
+
// server is selected. Adapters route to it; nobody re-derives it.
|
|
44
|
+
export { effectiveConfig, isEffectiveFileViewError, } from "./effective-config.js";
|
|
38
45
|
// --- Query wrappers (own the remaining internal reach-ins) -------------------
|
|
39
46
|
/** Recent dispatch latency reports (latency.log schema), newest first. */
|
|
40
47
|
export function recentLatency(limit = 5, fileFilter) {
|
|
@@ -163,42 +170,28 @@ export function ensureLspConfig(cwd) {
|
|
|
163
170
|
export function resourceFootprint() {
|
|
164
171
|
return getResourceFootprintSnapshot();
|
|
165
172
|
}
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
php: [".php"],
|
|
189
|
-
python: [".py", ".pyi"],
|
|
190
|
-
ruby: [".rb", ".rake", ".gemspec"],
|
|
191
|
-
rust: [".rs"],
|
|
192
|
-
scala: [".scala", ".sc"],
|
|
193
|
-
solidity: [".sol"],
|
|
194
|
-
swift: [".swift"],
|
|
195
|
-
tsx: [".tsx"],
|
|
196
|
-
typescript: [".ts", ".mts", ".cts"],
|
|
197
|
-
yaml: [".yaml", ".yml"],
|
|
198
|
-
};
|
|
199
|
-
function fileMatchesLang(file, lang) {
|
|
200
|
-
const exts = SYMBOL_SEARCH_LANG_EXTENSIONS[lang];
|
|
201
|
-
if (!exts)
|
|
173
|
+
/**
|
|
174
|
+
* symbol_search's `lang` filter.
|
|
175
|
+
*
|
|
176
|
+
* The extension table this used to consult was a NINTH hand-written language ->
|
|
177
|
+
* extensions map, kept here because `clients/` never reaches into `tools/`
|
|
178
|
+
* (AGENTS.md's MCP-mirror layering note) — and it had drifted from every other
|
|
179
|
+
* one (#2424 review, S2): `css` claimed `.scss`/`.less`, `json` claimed
|
|
180
|
+
* `.jsonc`, `php` omitted its four alias extensions, `ruby` omitted `.ru`, and
|
|
181
|
+
* `solidity` was not a language the registry (or any grammar, or the ast-grep
|
|
182
|
+
* napi matrix) knows at all.
|
|
183
|
+
*
|
|
184
|
+
* The layering constraint was never a reason to duplicate the DATA, only a
|
|
185
|
+
* reason not to import the tool's token list. `extensionsForLanguageToken`
|
|
186
|
+
* resolves the token against the canonical registry instead.
|
|
187
|
+
*
|
|
188
|
+
* Exported so `tests/clients/language-registry-drift.test.ts` guards the SEAM
|
|
189
|
+
* and not just the projection behind it: a future local table reintroduced
|
|
190
|
+
* here would satisfy a registry-only assertion but fail this one.
|
|
191
|
+
*/
|
|
192
|
+
export function symbolSearchFileMatchesLang(file, lang) {
|
|
193
|
+
const exts = extensionsForLanguageToken(lang);
|
|
194
|
+
if (exts.length === 0)
|
|
202
195
|
return false;
|
|
203
196
|
return exts.includes(path.extname(file).toLowerCase());
|
|
204
197
|
}
|
|
@@ -223,7 +216,7 @@ function buildSymbolSearchFileFilter(cwd, options) {
|
|
|
223
216
|
return (file) => {
|
|
224
217
|
if (paths?.length && !fileMatchesPathGlobs(file, cwd, paths))
|
|
225
218
|
return false;
|
|
226
|
-
if (lang && !
|
|
219
|
+
if (lang && !symbolSearchFileMatchesLang(file, lang))
|
|
227
220
|
return false;
|
|
228
221
|
return true;
|
|
229
222
|
};
|
|
@@ -17,6 +17,7 @@
|
|
|
17
17
|
* `~/.pi-lens/config.json`. Adding a toggle means adding one entry here; there
|
|
18
18
|
* is no second place to remember.
|
|
19
19
|
*/
|
|
20
|
+
import { DEPRECATED_CONFIG_SURFACES } from "./config-diagnostic-codes.js";
|
|
20
21
|
export const LENS_FLAGS = [
|
|
21
22
|
{
|
|
22
23
|
name: "no-lens",
|
|
@@ -217,23 +218,75 @@ export const GLOBAL_NON_FLAG_CONFIG_SECTIONS = [
|
|
|
217
218
|
"widget",
|
|
218
219
|
"$schema",
|
|
219
220
|
];
|
|
221
|
+
/**
|
|
222
|
+
* Recognized TOP-LEVEL sections of a project `.pi-lens.json` that are NOT
|
|
223
|
+
* derived from the flag registry — the project loader's own hand-parsed
|
|
224
|
+
* sections (`ignore`, `rules`, `maxProjectFiles`, `reviewGraph`) plus the two
|
|
225
|
+
* namespaces another pi-lens runner reads off `PiLensProjectConfig.raw`
|
|
226
|
+
* (`trivy` in `trivy-client.ts`, `helm.renderValidation.enabled` in the
|
|
227
|
+
* helm-render runner, #1283).
|
|
228
|
+
*
|
|
229
|
+
* Moved here from `project-lens-config.ts` by #2426 so the canonical schema in
|
|
230
|
+
* `config-schema.ts` derives its namespace list from ONE place instead of
|
|
231
|
+
* importing the project loader (which would close an import cycle, since that
|
|
232
|
+
* loader now resolves through the schema).
|
|
233
|
+
*/
|
|
234
|
+
export const PROJECT_NON_FLAG_CONFIG_SECTIONS = [
|
|
235
|
+
"ignore",
|
|
236
|
+
"rules",
|
|
237
|
+
"maxProjectFiles",
|
|
238
|
+
"reviewGraph",
|
|
239
|
+
"trivy",
|
|
240
|
+
"helm",
|
|
241
|
+
];
|
|
242
|
+
/**
|
|
243
|
+
* The four LSP settings a PROJECT config file may carry — at its root during
|
|
244
|
+
* the deprecation window, and under `lsp` canonically. DERIVED from the
|
|
245
|
+
* registry's `kind: "key"` rows so the accepted set and the removal schedule
|
|
246
|
+
* cannot drift apart, and named once because two places below need it.
|
|
247
|
+
*/
|
|
248
|
+
const LSP_PROJECT_HONORED_KEYS = DEPRECATED_CONFIG_SURFACES.filter((row) => row.kind === "key").map((row) => row.surface);
|
|
220
249
|
/**
|
|
221
250
|
* Foreign top-level namespaces that legitimately appear in a SHARED
|
|
222
251
|
* `.pi-lens.json` but belong to a DIFFERENT loader: the LSP config loader
|
|
223
|
-
* (`clients/lsp/config.ts`) reads `
|
|
224
|
-
*
|
|
252
|
+
* (`clients/lsp/config.ts`) reads the `lsp` namespace — and, for its
|
|
253
|
+
* deprecation window, the legacy ROOT keys `servers` / `serverOverrides` /
|
|
254
|
+
* `disabledServers` / `warmFiles` — out of the very same file. The project-lens
|
|
225
255
|
* loader must TOLERATE these (never warn "unknown key") — they are not typos,
|
|
226
256
|
* just another subsystem's namespace. `$schema` is allowed for editor
|
|
227
257
|
* JSON-schema association. Declared once, here, for the same #883 reason as
|
|
228
258
|
* {@link GLOBAL_NON_FLAG_CONFIG_SECTIONS}.
|
|
259
|
+
*
|
|
260
|
+
* `lsp` joined this list in #2426: it is the canonical home of the four legacy
|
|
261
|
+
* keys beside it, so a project config that has already been migrated must not
|
|
262
|
+
* be told its `lsp` section is a global-only setting. Its tolerance is
|
|
263
|
+
* SUB-KEY-SCOPED — see {@link PROJECT_FOREIGN_NAMESPACE_HONORED_KEYS}.
|
|
229
264
|
*/
|
|
230
265
|
export const PROJECT_FOREIGN_CONFIG_NAMESPACES = [
|
|
231
|
-
"
|
|
232
|
-
|
|
233
|
-
"
|
|
234
|
-
|
|
266
|
+
"lsp",
|
|
267
|
+
// DERIVED, not restated: the four legacy root keys are exactly the
|
|
268
|
+
// `kind: "key"` rows of the deprecation registry, and a hand-copied second
|
|
269
|
+
// list of them would be a place for the accepted set and the removal
|
|
270
|
+
// schedule to drift apart. `config-diagnostic-codes.ts` is a dependency-free
|
|
271
|
+
// data leaf, so importing it keeps this module's own no-cycle property.
|
|
272
|
+
...LSP_PROJECT_HONORED_KEYS,
|
|
235
273
|
"$schema",
|
|
236
274
|
];
|
|
275
|
+
/**
|
|
276
|
+
* For a foreign namespace whose PROJECT-honored surface is only PART of what
|
|
277
|
+
* the namespace can hold: which sub-keys a `.pi-lens.json` may set.
|
|
278
|
+
*
|
|
279
|
+
* `lsp` is tolerated at the top level because the LSP loader reads it out of
|
|
280
|
+
* this same file — but only four of its keys are project-scoped. `lsp.enabled`
|
|
281
|
+
* is a `scope: "global"` flag (`--no-lsp`), so blanket namespace tolerance made
|
|
282
|
+
* a project-file `lsp.enabled: false` do nothing with no signal at all, where
|
|
283
|
+
* before #2426 the user got the honest "global-only setting" notice
|
|
284
|
+
* (#2426 review round 2, F3). `docs/configuration.md` promises that nothing
|
|
285
|
+
* about a config is ignored silently, so the namespace is tolerated KEY BY KEY
|
|
286
|
+
* and anything else under it is scanned by the same global-only-vs-typo rules a
|
|
287
|
+
* top-level key gets.
|
|
288
|
+
*/
|
|
289
|
+
export const PROJECT_FOREIGN_NAMESPACE_HONORED_KEYS = new Map([["lsp", LSP_PROJECT_HONORED_KEYS]]);
|
|
237
290
|
/**
|
|
238
291
|
* The distinct TOP-LEVEL section keys a set of flags lives under (the first
|
|
239
292
|
* dotted segment of each `configKey`). Both config loaders derive their
|
|
@@ -22,10 +22,10 @@
|
|
|
22
22
|
*/
|
|
23
23
|
import * as fs from "node:fs";
|
|
24
24
|
import * as path from "node:path";
|
|
25
|
-
import {
|
|
25
|
+
import { getGlobalPiLensLogDir } from "./probe-home-state.js";
|
|
26
26
|
import { getRegisteredLogFiles } from "./ndjson-logger.js";
|
|
27
27
|
import { pathsEqual } from "./path-utils.js";
|
|
28
|
-
const LOG_DIR =
|
|
28
|
+
const LOG_DIR = getGlobalPiLensLogDir();
|
|
29
29
|
const LOGS_SUBDIR = path.join(LOG_DIR, "logs");
|
|
30
30
|
/**
|
|
31
31
|
* Every global `.log` pi-lens writes under ~/.pi-lens, resolved dynamically so
|
|
@@ -34,7 +34,9 @@
|
|
|
34
34
|
* `PromiseDescriptor.budgetMs`.
|
|
35
35
|
*/
|
|
36
36
|
export async function raceToCompletion(promises, shouldComplete, options = { timeoutMs: 1500 }) {
|
|
37
|
-
const results =
|
|
37
|
+
const results = [];
|
|
38
|
+
results.length = promises.length;
|
|
39
|
+
results.fill(undefined);
|
|
38
40
|
let graceTimer;
|
|
39
41
|
let auxGraceTimer;
|
|
40
42
|
let completed = false;
|