@herbertgao/pi-extensions 2026.9.0 → 2026.9.2
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/@narumitw/pi-btw/README.md +57 -141
- package/node_modules/@narumitw/pi-btw/dist/index.ts +466 -41
- package/node_modules/@narumitw/pi-btw/dist/index.ts.map +4 -4
- package/node_modules/@narumitw/pi-btw/docs/workflows.md +74 -0
- package/node_modules/@narumitw/pi-btw/package.json +2 -1
- package/node_modules/@narumitw/pi-btw/src/btw.ts +15 -1
- package/node_modules/@narumitw/pi-btw/src/fullscreen-ui.ts +32 -2
- package/node_modules/@narumitw/pi-btw/src/keybindings.ts +330 -0
- package/node_modules/@narumitw/pi-btw/src/menu.ts +136 -19
- package/node_modules/@narumitw/pi-btw/src/settings.ts +32 -0
- package/node_modules/@narumitw/pi-btw/src/side-thread.ts +57 -5
- package/node_modules/@narumitw/pi-btw/src/transcript-pager.ts +52 -30
- 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 +1072 -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 -9
- package/node_modules/pi-lens/dist/clients/actionable-warnings.js +927 -80
- package/node_modules/pi-lens/dist/clients/advisory-provenance.js +1 -1
- 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 -9
- package/node_modules/pi-lens/dist/clients/ast-grep-types.js +2 -0
- package/node_modules/pi-lens/dist/clients/bash-file-access.js +133 -3
- package/node_modules/pi-lens/dist/clients/biome-client.js +9 -2
- package/node_modules/pi-lens/dist/clients/blocker-freshness.js +14 -6
- 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-pid-file-lock.js +1 -1
- package/node_modules/pi-lens/dist/clients/bounded-telemetry.js +59 -9
- package/node_modules/pi-lens/dist/clients/bundled-resource-health.js +113 -0
- package/node_modules/pi-lens/dist/clients/bus-events-logger.js +3 -11
- 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 +40 -19
- package/node_modules/pi-lens/dist/clients/cargo-manifest.js +422 -0
- package/node_modules/pi-lens/dist/clients/cascade-logger.js +2 -9
- package/node_modules/pi-lens/dist/clients/child-unref.js +1 -19
- 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 +50 -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 +164 -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 +165 -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 +234 -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 -6
- 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-dispositions.js +1 -1
- package/node_modules/pi-lens/dist/clients/diagnostic-line-freshness.js +12 -9
- package/node_modules/pi-lens/dist/clients/diagnostic-logger.js +15 -5
- package/node_modules/pi-lens/dist/clients/dispatch/collect-later-tier.js +0 -4
- package/node_modules/pi-lens/dist/clients/dispatch/dispatcher.js +162 -44
- package/node_modules/pi-lens/dist/clients/dispatch/fact-store.js +97 -0
- package/node_modules/pi-lens/dist/clients/dispatch/integration.js +27 -8
- package/node_modules/pi-lens/dist/clients/dispatch/lazy.js +0 -6
- package/node_modules/pi-lens/dist/clients/dispatch/pending-runner-findings.js +1 -1
- package/node_modules/pi-lens/dist/clients/dispatch/plan.js +0 -3
- package/node_modules/pi-lens/dist/clients/dispatch/rules/high-complexity.js +2 -2
- package/node_modules/pi-lens/dist/clients/dispatch/rules/high-fan-out.js +1 -1
- 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 +383 -27
- 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 +4 -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 +1 -2
- 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 +14 -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 +6 -3
- 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 +1 -2
- 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 +1 -2
- package/node_modules/pi-lens/dist/clients/dispatch/runners/shfmt.js +0 -1
- package/node_modules/pi-lens/dist/clients/dispatch/runners/spellcheck.js +4 -3
- 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 -67
- 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/utils.js +0 -21
- package/node_modules/pi-lens/dist/clients/dispatch/runners/vale.js +0 -1
- package/node_modules/pi-lens/dist/clients/dispatch/runners/yaml-rule-parser.js +2 -20
- package/node_modules/pi-lens/dist/clients/dispatch/runners/yamllint.js +1 -1
- package/node_modules/pi-lens/dist/clients/dispatch/runners/zig-check.js +0 -1
- package/node_modules/pi-lens/dist/clients/dispatch/utils/format-utils.js +2 -2
- package/node_modules/pi-lens/dist/clients/disposition-logger.js +3 -10
- 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/event-loop-monitor.js +2 -2
- 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-kinds.js +1 -38
- package/node_modules/pi-lens/dist/clients/file-time.js +7 -2
- package/node_modules/pi-lens/dist/clients/file-utils.js +117 -10
- package/node_modules/pi-lens/dist/clients/finding-delivery-gate.js +50 -13
- package/node_modules/pi-lens/dist/clients/format-service.js +6 -2
- package/node_modules/pi-lens/dist/clients/formatters.js +385 -104
- package/node_modules/pi-lens/dist/clients/freshness-cadence.js +17 -0
- package/node_modules/pi-lens/dist/clients/generated-artifacts.js +116 -22
- package/node_modules/pi-lens/dist/clients/generation-guard.js +4 -9
- package/node_modules/pi-lens/dist/clients/git-guard.js +6 -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/grammar-source.js +3 -3
- 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 +289 -59
- package/node_modules/pi-lens/dist/clients/installer/managed-tool-refresh.js +84 -18
- package/node_modules/pi-lens/dist/clients/instance-reaper.js +110 -236
- package/node_modules/pi-lens/dist/clients/instance-registry.js +6 -3
- package/node_modules/pi-lens/dist/clients/language-profile.js +0 -9
- package/node_modules/pi-lens/dist/clients/language-registry.js +599 -0
- package/node_modules/pi-lens/dist/clients/latency-logger.js +165 -9
- package/node_modules/pi-lens/dist/clients/ledger-bounds.js +34 -1
- package/node_modules/pi-lens/dist/clients/lens-config.js +160 -30
- package/node_modules/pi-lens/dist/clients/lens-engine.js +33 -41
- package/node_modules/pi-lens/dist/clients/lens-events.js +1 -1
- package/node_modules/pi-lens/dist/clients/lens-flag-registry.js +77 -6
- package/node_modules/pi-lens/dist/clients/lens-map.js +1 -1
- package/node_modules/pi-lens/dist/clients/log-cleanup.js +2 -38
- package/node_modules/pi-lens/dist/clients/lsp/aggregation.js +3 -1
- package/node_modules/pi-lens/dist/clients/lsp/client.js +172 -33
- package/node_modules/pi-lens/dist/clients/lsp/config.js +484 -158
- package/node_modules/pi-lens/dist/clients/lsp/diagnostic-binding.js +1 -1
- package/node_modules/pi-lens/dist/clients/lsp/document-drift.js +1 -1
- package/node_modules/pi-lens/dist/clients/lsp/edits.js +18 -5
- package/node_modules/pi-lens/dist/clients/lsp/index.js +892 -96
- package/node_modules/pi-lens/dist/clients/lsp/inferred-project.js +1 -1
- package/node_modules/pi-lens/dist/clients/lsp/language.js +18 -177
- package/node_modules/pi-lens/dist/clients/lsp/launch.js +2 -1
- package/node_modules/pi-lens/dist/clients/lsp/path-utils.js +1 -1
- package/node_modules/pi-lens/dist/clients/lsp/pending-aux-coverage.js +5 -18
- 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/sync-kind.js +0 -1
- package/node_modules/pi-lens/dist/clients/lsp/tsserver-sync.js +14 -7
- package/node_modules/pi-lens/dist/clients/lsp/wait-policy/classification.js +6 -0
- package/node_modules/pi-lens/dist/clients/lsp/wait-policy/strategies.js +2 -1
- package/node_modules/pi-lens/dist/clients/lsp/workspace-diagnostics-cache.js +1 -1
- package/node_modules/pi-lens/dist/clients/lsp-document-symbols.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/metrics-history.js +28 -107
- package/node_modules/pi-lens/dist/clients/middle-man-analysis.js +3 -5
- package/node_modules/pi-lens/dist/clients/module-report.js +21 -46
- 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 -24
- 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 +70 -28
- package/node_modules/pi-lens/dist/clients/opengrep-config.js +5 -1
- 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 +451 -15
- package/node_modules/pi-lens/dist/clients/performance-report.js +2 -2
- 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 +79 -18
- 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-changes.js +1 -1
- package/node_modules/pi-lens/dist/clients/project-diagnostics/extractors.js +1 -1
- 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/jscpd.js +1 -1
- package/node_modules/pi-lens/dist/clients/project-diagnostics/runner-adapters/knip.js +1 -1
- package/node_modules/pi-lens/dist/clients/project-diagnostics/runner-adapters/madge.js +1 -1
- package/node_modules/pi-lens/dist/clients/project-diagnostics/runner-adapters/opengrep.js +1 -1
- package/node_modules/pi-lens/dist/clients/project-diagnostics/runner-adapters/runner-findings.js +28 -4
- package/node_modules/pi-lens/dist/clients/project-diagnostics/scanner.js +51 -20
- package/node_modules/pi-lens/dist/clients/project-lens-config.js +438 -122
- package/node_modules/pi-lens/dist/clients/project-scan-policy.js +3 -51
- 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 +16 -5
- package/node_modules/pi-lens/dist/clients/read-guard-tool-lines.js +364 -212
- package/node_modules/pi-lens/dist/clients/read-guard.js +26 -2
- package/node_modules/pi-lens/dist/clients/recent-touches.js +2 -2
- package/node_modules/pi-lens/dist/clients/resource-sampler.js +195 -96
- package/node_modules/pi-lens/dist/clients/review-graph/builder.js +155 -114
- package/node_modules/pi-lens/dist/clients/review-graph/import-resolvers.js +1 -1
- 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 +19 -3
- 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 +184 -32
- package/node_modules/pi-lens/dist/clients/runtime-tool-call.js +179 -36
- 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 -12
- package/node_modules/pi-lens/dist/clients/scan-utils.js +1 -56
- 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/session-summary.js +0 -24
- package/node_modules/pi-lens/dist/clients/sessionstart-logger.js +12 -3
- package/node_modules/pi-lens/dist/clients/sgconfig.js +7 -6
- package/node_modules/pi-lens/dist/clients/shared-checkout-guard.js +1 -1
- package/node_modules/pi-lens/dist/clients/skills-resolver.js +105 -0
- package/node_modules/pi-lens/dist/clients/smells-rollup.js +4 -4
- package/node_modules/pi-lens/dist/clients/startup-scan.js +2 -10
- 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 +244 -0
- package/node_modules/pi-lens/dist/clients/tool-definition.js +41 -1
- package/node_modules/pi-lens/dist/clients/tool-policy.js +92 -22
- package/node_modules/pi-lens/dist/clients/tree-sitter-cache.js +40 -40
- package/node_modules/pi-lens/dist/clients/tree-sitter-client.js +87 -100
- 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/tui-fit.js +0 -4
- package/node_modules/pi-lens/dist/clients/typos-config.js +5 -0
- package/node_modules/pi-lens/dist/clients/user-notify.js +6 -6
- package/node_modules/pi-lens/dist/clients/widget-state.js +191 -26
- package/node_modules/pi-lens/dist/clients/word-index-logger.js +2 -9
- package/node_modules/pi-lens/dist/clients/word-index-store.js +23 -12
- package/node_modules/pi-lens/dist/clients/word-index.js +252 -47
- package/node_modules/pi-lens/dist/clients/workspace-topology.js +8 -1
- package/node_modules/pi-lens/dist/clients/zizmor-config.js +4 -1
- package/node_modules/pi-lens/dist/index.js +65899 -55340
- package/node_modules/pi-lens/dist/mcp/analyze-cli.js +3 -1
- package/node_modules/pi-lens/dist/mcp/build-staleness.js +1 -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 +96 -25
- package/node_modules/pi-lens/dist/tools/lsp-diagnostics.js +104 -86
- package/node_modules/pi-lens/dist/tools/lsp-navigation.js +37 -16
- package/node_modules/pi-lens/dist/tools/lsp-structured-output.js +3 -3
- package/node_modules/pi-lens/dist/tools/render-compact.js +1 -1
- package/node_modules/pi-lens/dist/tools/shared.js +0 -1
- package/node_modules/pi-lens/dist/tools/symbol-search.js +1 -2
- 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/globalconfig.md +20 -0
- package/node_modules/pi-lens/docs/language-coverage.md +2 -2
- package/node_modules/pi-lens/docs/lsp-capability-matrix.md +9 -1
- 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 +33 -0
- package/node_modules/pi-lens/docs/pi-lens-subagent.md +49 -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 +190 -0
- package/node_modules/pi-lens/docs/servercapabilities.md +7 -3
- 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/docs/word-index.md +1 -1
- package/node_modules/pi-lens/package.json +18 -35
- 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/rules/typos/_typos.toml +4 -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/lib/warm-loader-cache.mjs +1 -1
- package/node_modules/pi-lens/scripts/rpc-load-check.mjs +3 -1
- package/node_modules/pi-lens/scripts/warm-loader-cache.mjs +4 -2
- 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 +6 -6
|
@@ -57,37 +57,28 @@
|
|
|
57
57
|
* patterns apply to files inside that package, in addition to (and with
|
|
58
58
|
* higher precedence than) the root config's `ignore` patterns.
|
|
59
59
|
*/
|
|
60
|
-
import {
|
|
61
|
-
import { notifyUserDegradation } from "./user-notify.js";
|
|
60
|
+
import { resetIgnoredConfigWarnCache, warnIgnoredConfigOnce, } from "./config-warn.js";
|
|
62
61
|
import * as fs from "node:fs";
|
|
63
62
|
import * as os from "node:os";
|
|
64
63
|
import * as path from "node:path";
|
|
65
64
|
import { toPositiveFinite } from "./env-utils.js";
|
|
66
|
-
import {
|
|
67
|
-
import {
|
|
65
|
+
import { FRESHNESS_CADENCE_MS } from "./freshness-cadence.js";
|
|
66
|
+
import { assignFlagConfigSection, flagConfigSectionKeys, GLOBAL_NON_FLAG_CONFIG_SECTIONS, LENS_FLAGS, PROJECT_FOREIGN_CONFIG_NAMESPACES, PROJECT_FOREIGN_NAMESPACE_HONORED_KEYS, PROJECT_NON_FLAG_CONFIG_SECTIONS, PROJECT_SCOPED_LENS_FLAGS, readFlagConfigValue, } from "./lens-flag-registry.js";
|
|
67
|
+
import { configSearchDirs, getPiLensGlobalConfigPath, PROJECT_CONFIG_BASENAMES, PROJECT_CONFIG_LOCATIONS, } from "./config-locations.js";
|
|
68
|
+
import { deprecationRecords, ignoredRecordCollector, projectLocationFor, readConfigDocument, reportConfigReadFailure, reportPiLensConfigRecords, resolveOnePiLensConfigDocument, } from "./config-resolve.js";
|
|
69
|
+
import { finalizeRecords, } from "./config-core/records.js";
|
|
70
|
+
import { homeRelativePath, isAtOrAboveHomeDir, walkUpDirs, } from "./path-utils.js";
|
|
68
71
|
import { findPiLensConfigMarkerInDir } from "./workspace-topology.js";
|
|
69
|
-
const PROJECT_CONFIG_BASENAMES = [".pi-lens.json", "pi-lens.json"];
|
|
70
72
|
/**
|
|
71
|
-
*
|
|
72
|
-
*
|
|
73
|
-
*
|
|
74
|
-
*
|
|
75
|
-
*
|
|
76
|
-
*
|
|
77
|
-
*
|
|
78
|
-
* file also carries live in `PROJECT_FOREIGN_CONFIG_NAMESPACES` beside the
|
|
79
|
-
* registry.
|
|
73
|
+
* Project config basenames, in DESCENDING precedence (first match wins), for
|
|
74
|
+
* this loader's own discovery.
|
|
75
|
+
*
|
|
76
|
+
* Re-exported from `config-locations.ts`, which owns the derivation, so this
|
|
77
|
+
* loader's long-standing export keeps working while there is exactly ONE list
|
|
78
|
+
* (#2426 review round 2: `workspace-topology.ts` was still carrying a third
|
|
79
|
+
* copy).
|
|
80
80
|
*/
|
|
81
|
-
|
|
82
|
-
"ignore",
|
|
83
|
-
"rules",
|
|
84
|
-
"maxProjectFiles",
|
|
85
|
-
"reviewGraph",
|
|
86
|
-
"trivy",
|
|
87
|
-
// `helm.renderValidation.enabled` — the opt-in for rendered-manifest
|
|
88
|
-
// validation, read via `.raw` in the helm-render runner (#1283).
|
|
89
|
-
"helm",
|
|
90
|
-
];
|
|
81
|
+
export { PROJECT_CONFIG_BASENAMES } from "./config-locations.js";
|
|
91
82
|
/** Clamp bounds for `reviewGraph.maxFiles` — see the field's doc comment above. */
|
|
92
83
|
const REVIEW_GRAPH_MAX_FILES_MIN = 100;
|
|
93
84
|
const REVIEW_GRAPH_MAX_FILES_MAX = 20_000;
|
|
@@ -102,34 +93,93 @@ export const EMPTY_PROJECT_CONFIG = {
|
|
|
102
93
|
/** Cache by absolute config path; we read each candidate's mtime before reuse. */
|
|
103
94
|
const configCache = new Map();
|
|
104
95
|
const discoveryCache = new Map();
|
|
105
|
-
|
|
96
|
+
/**
|
|
97
|
+
* The shared body of `loadPiLensProjectConfig` and `loadPiLensConfigInDir`:
|
|
98
|
+
* reuse a fresh cache entry, or parse and cache one, and — EITHER WAY (#2426
|
|
99
|
+
* review round 3, F2) — report the resolution's migration records. Content
|
|
100
|
+
* caching (skip re-reading unchanged bytes off disk) and per-session
|
|
101
|
+
* reporting (tell the user once a session about a deprecated setting) are two
|
|
102
|
+
* different lifetimes; folding "already cached" into "already reported"
|
|
103
|
+
* silently dropped the report the moment the file stopped changing.
|
|
104
|
+
*/
|
|
105
|
+
function loadCachedConfigFile(info) {
|
|
106
|
+
const cached = configCache.get(info.path);
|
|
107
|
+
if (cached && cached.mtimeMs === info.mtimeMs && cached.size === info.size) {
|
|
108
|
+
replayConfigNotices(cached);
|
|
109
|
+
return cached.config;
|
|
110
|
+
}
|
|
111
|
+
const parsed = parseConfigFile(info.path);
|
|
112
|
+
const entry = {
|
|
113
|
+
mtimeMs: info.mtimeMs,
|
|
114
|
+
size: info.size,
|
|
115
|
+
config: parsed.config,
|
|
116
|
+
records: parsed.records,
|
|
117
|
+
ignored: parsed.ignored,
|
|
118
|
+
};
|
|
119
|
+
configCache.set(info.path, entry);
|
|
120
|
+
replayConfigNotices(entry);
|
|
121
|
+
return parsed.config;
|
|
122
|
+
}
|
|
123
|
+
/**
|
|
124
|
+
* Report BOTH classes of notice a parse produced (#2426 review round 4, F3).
|
|
125
|
+
*
|
|
126
|
+
* The resolution's records go through the shared seam, which derives each
|
|
127
|
+
* one's subsystem from the record. This loader's own records do not: they are
|
|
128
|
+
* `project-lens-config`'s by construction — it composed their prose — so
|
|
129
|
+
* routing them through that derivation would relabel `"lsp.enabled" is a
|
|
130
|
+
* global-only pi-lens setting` as an LSP-config problem, which is the opposite
|
|
131
|
+
* of what it says.
|
|
132
|
+
*/
|
|
133
|
+
function replayConfigNotices(entry) {
|
|
134
|
+
reportPiLensConfigRecords(entry.records);
|
|
135
|
+
for (const record of entry.ignored) {
|
|
136
|
+
warnIgnoredConfigOnce({
|
|
137
|
+
subsystem: "project-lens-config",
|
|
138
|
+
file: record.file,
|
|
139
|
+
reason: record.reason,
|
|
140
|
+
code: record.code,
|
|
141
|
+
});
|
|
142
|
+
}
|
|
143
|
+
}
|
|
106
144
|
/**
|
|
107
145
|
* Walk up from `startDir` looking for a `.pi-lens.json` or `pi-lens.json`.
|
|
108
146
|
* Returns the parsed config, or an empty config if none was found.
|
|
109
147
|
*/
|
|
110
|
-
export function loadPiLensProjectConfig(startDir, preloadedInfo
|
|
111
|
-
|
|
148
|
+
export function loadPiLensProjectConfig(startDir, preloadedInfo) {
|
|
149
|
+
// ONE discovery per load (#2426 review round 5, F-C). The legacy-document
|
|
150
|
+
// enumeration below and the config-file lookup are two READS of the same
|
|
151
|
+
// cache entry, and resolving that entry twice — the default argument once,
|
|
152
|
+
// the record replay again — doubled the freshness stats every warm load
|
|
153
|
+
// pays, on a path called per dispatch. The entry is resolved here and both
|
|
154
|
+
// halves read it.
|
|
155
|
+
const entry = discoveryEntryFor(startDir);
|
|
156
|
+
// #2426 review round 4, F4. The half-migrated notices — a legacy
|
|
157
|
+
// `pi-lens.json` sitting BESIDE or ABOVE the canonical `.pi-lens.json` this
|
|
158
|
+
// walk stops at — used to be produced only by `loadLSPConfig`, whose
|
|
159
|
+
// discovery collects from every bearing directory rather than stopping at
|
|
160
|
+
// the first. Under `--no-lsp`, `lsp.enabled: false`, or a subagent session
|
|
161
|
+
// (#449, routine) that loader never runs, and the pi-lens-OWNED records for
|
|
162
|
+
// a pi-lens-owned file were then produced by nobody at all. The pi-lens
|
|
163
|
+
// loader now enumerates those documents itself, for records only: nothing
|
|
164
|
+
// here is merged, and which file supplies a VALUE is unchanged.
|
|
165
|
+
const configInfo = preloadedInfo ?? freshInfoFor(entry);
|
|
166
|
+
// The selected legacy document is resolved below and its bounded migration
|
|
167
|
+
// records are cached with that projection. Reporting the discovery copy as
|
|
168
|
+
// well would produce two suppression records with different totals, because
|
|
169
|
+
// the discovery walk and the single-document resolution see different
|
|
170
|
+
// record populations. Keep discovery-only documents here; the selected file
|
|
171
|
+
// is reported by `loadCachedConfigFile`.
|
|
172
|
+
const selectedLegacyPath = configInfo?.path;
|
|
173
|
+
reportPiLensConfigRecords(entry.legacyRecords.filter((record) => record.file !== selectedLegacyPath));
|
|
112
174
|
if (!configInfo)
|
|
113
175
|
return EMPTY_PROJECT_CONFIG;
|
|
114
|
-
|
|
115
|
-
if (cached &&
|
|
116
|
-
cached.mtimeMs === configInfo.mtimeMs &&
|
|
117
|
-
cached.size === configInfo.size) {
|
|
118
|
-
return cached.config;
|
|
119
|
-
}
|
|
120
|
-
const config = parseConfigFile(configInfo.path);
|
|
121
|
-
configCache.set(configInfo.path, {
|
|
122
|
-
mtimeMs: configInfo.mtimeMs,
|
|
123
|
-
size: configInfo.size,
|
|
124
|
-
config,
|
|
125
|
-
});
|
|
126
|
-
return config;
|
|
176
|
+
return loadCachedConfigFile(configInfo);
|
|
127
177
|
}
|
|
128
178
|
/** For tests + callers that need to force a re-read (e.g. config-watcher hooks). */
|
|
129
179
|
export function resetProjectLensConfigCache() {
|
|
130
180
|
configCache.clear();
|
|
131
181
|
discoveryCache.clear();
|
|
132
|
-
|
|
182
|
+
resetIgnoredConfigWarnCache("project-lens-config");
|
|
133
183
|
}
|
|
134
184
|
/**
|
|
135
185
|
* Look for a `.pi-lens.json`/`pi-lens.json` directly IN `dir` — no upward
|
|
@@ -189,31 +239,37 @@ export function loadPiLensConfigInDir(dir) {
|
|
|
189
239
|
const info = findPiLensConfigInDir(dir);
|
|
190
240
|
if (!info)
|
|
191
241
|
return EMPTY_PROJECT_CONFIG;
|
|
192
|
-
|
|
193
|
-
if (cached && cached.mtimeMs === info.mtimeMs && cached.size === info.size) {
|
|
194
|
-
return cached.config;
|
|
195
|
-
}
|
|
196
|
-
const config = parseConfigFile(info.path);
|
|
197
|
-
configCache.set(info.path, {
|
|
198
|
-
mtimeMs: info.mtimeMs,
|
|
199
|
-
size: info.size,
|
|
200
|
-
config,
|
|
201
|
-
});
|
|
202
|
-
return config;
|
|
242
|
+
return loadCachedConfigFile(info);
|
|
203
243
|
}
|
|
204
|
-
|
|
244
|
+
/** The cached discovery for `startDir`, recomputed when it is no longer fresh. */
|
|
245
|
+
function discoveryEntryFor(startDir) {
|
|
205
246
|
const cacheKey = path.resolve(startDir);
|
|
206
247
|
const cached = discoveryCache.get(cacheKey);
|
|
207
|
-
if (cached && discoveryCacheStillFresh(cached))
|
|
208
|
-
|
|
209
|
-
return undefined;
|
|
210
|
-
const stat = safeFileStat(cached.info.path);
|
|
211
|
-
if (stat?.isFile())
|
|
212
|
-
return { ...cached.info, mtimeMs: stat.mtimeMs, size: stat.size };
|
|
213
|
-
}
|
|
248
|
+
if (cached && discoveryCacheStillFresh(cached))
|
|
249
|
+
return cached;
|
|
214
250
|
const discovered = discoverPiLensProjectConfig(cacheKey);
|
|
215
251
|
discoveryCache.set(cacheKey, discovered);
|
|
216
|
-
return discovered
|
|
252
|
+
return discovered;
|
|
253
|
+
}
|
|
254
|
+
export function findPiLensProjectConfig(startDir) {
|
|
255
|
+
return freshInfoFor(discoveryEntryFor(startDir));
|
|
256
|
+
}
|
|
257
|
+
/**
|
|
258
|
+
* The winning config file's info, re-statted.
|
|
259
|
+
*
|
|
260
|
+
* Split out of `findPiLensProjectConfig` so a caller that already holds the
|
|
261
|
+
* discovery entry does not resolve it a second time to get here (#2426 review
|
|
262
|
+
* round 5, F-C). The re-stat itself stays: the entry can be fresh by directory
|
|
263
|
+
* mtime while the config file was rewritten in place, and the caller keys its
|
|
264
|
+
* content cache on the mtime/size this returns.
|
|
265
|
+
*/
|
|
266
|
+
function freshInfoFor(entry) {
|
|
267
|
+
if (!entry.info)
|
|
268
|
+
return undefined;
|
|
269
|
+
const stat = safeFileStat(entry.info.path);
|
|
270
|
+
if (!stat?.isFile())
|
|
271
|
+
return entry.info;
|
|
272
|
+
return { ...entry.info, mtimeMs: stat.mtimeMs, size: stat.size };
|
|
217
273
|
}
|
|
218
274
|
function safeFileStat(filePath) {
|
|
219
275
|
try {
|
|
@@ -232,48 +288,192 @@ function safeDirMtimeMs(dir) {
|
|
|
232
288
|
}
|
|
233
289
|
}
|
|
234
290
|
function discoveryCacheStillFresh(entry) {
|
|
235
|
-
|
|
291
|
+
if (!entry.dirMtimes.every((cached) => safeDirMtimeMs(cached.dir) === cached.mtimeMs)) {
|
|
292
|
+
return false;
|
|
293
|
+
}
|
|
294
|
+
// #2483 round 2. When no config was found anywhere, `bearingDirMtimes`'s
|
|
295
|
+
// no-`info` branch scopes `dirMtimes` to `startDir` alone, so the `.every`
|
|
296
|
+
// above can only ever see churn AT `startDir` — a config file created at
|
|
297
|
+
// any ancestor above it moves nothing this entry tracks, and the entry
|
|
298
|
+
// would then read as fresh for the rest of the process (no production
|
|
299
|
+
// caller resets it, and a same-`startDir` load never rediscovers). The
|
|
300
|
+
// issue's acceptance line rules that out ("a new config file created in
|
|
301
|
+
// the chain IS noticed (bounded staleness stated)"), so a no-`info` entry
|
|
302
|
+
// is force-expired at most once per `FRESHNESS_CADENCE_MS` regardless of
|
|
303
|
+
// what `dirMtimes` says — the same negative-cache cadence bound
|
|
304
|
+
// `file-utils.ts`'s `patternsForDir` already applies to its own no-match
|
|
305
|
+
// case, reused rather than a second cadence mechanism invented here. The
|
|
306
|
+
// forced re-walk that follows re-stats the FULL ancestor chain (see
|
|
307
|
+
// `discoverPiLensProjectConfig`), so a config created anywhere in it is
|
|
308
|
+
// found — bounded to at most one cadence window of staleness, not
|
|
309
|
+
// unbounded.
|
|
310
|
+
if (entry.info === undefined &&
|
|
311
|
+
Date.now() - entry.checkedAtMs >= FRESHNESS_CADENCE_MS) {
|
|
312
|
+
return false;
|
|
313
|
+
}
|
|
314
|
+
// A legacy document can be EDITED in place without its directory's mtime
|
|
315
|
+
// moving, and its top-level key set is what `legacyRecords` describes — so
|
|
316
|
+
// those files carry their own freshness axis, the same (mtime, size) pair
|
|
317
|
+
// `CacheEntry` uses.
|
|
318
|
+
return entry.legacySources.every((source) => {
|
|
319
|
+
const stat = safeFileStat(source.path);
|
|
320
|
+
return (stat?.isFile() === true &&
|
|
321
|
+
stat.mtimeMs === source.mtimeMs &&
|
|
322
|
+
stat.size === source.size);
|
|
323
|
+
});
|
|
236
324
|
}
|
|
325
|
+
const LEGACY_PROJECT_LOCATIONS = PROJECT_CONFIG_LOCATIONS.filter((location) => location.legacy);
|
|
237
326
|
function discoverPiLensProjectConfig(startDir) {
|
|
238
327
|
const dirMtimes = [];
|
|
239
|
-
|
|
328
|
+
const legacyDocuments = [];
|
|
329
|
+
const legacySources = [];
|
|
330
|
+
let info;
|
|
331
|
+
// #2426: ceiling-bounded, same rule and same shared primitive as the LSP
|
|
332
|
+
// loader and as `findNestedProjectMutationValue` below. This walk ran to the
|
|
333
|
+
// filesystem root before, so a `.pi-lens.json` in `$HOME` (or at `C:\`) was
|
|
334
|
+
// adopted by every project on the machine — the #622/#625 class.
|
|
335
|
+
//
|
|
336
|
+
// It no longer STOPS at the first bearing directory (#2426 review round 4,
|
|
337
|
+
// F4): the first hit still decides `info`, and therefore still decides every
|
|
338
|
+
// value this loader returns, but the walk continues to the ceiling so the
|
|
339
|
+
// legacy documents a user is being asked to migrate are enumerated wherever
|
|
340
|
+
// they sit — beside the winning file or above it.
|
|
341
|
+
for (const dir of configSearchDirs(startDir)) {
|
|
240
342
|
dirMtimes.push({ dir, mtimeMs: safeDirMtimeMs(dir) });
|
|
241
|
-
|
|
242
|
-
const
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
info
|
|
343
|
+
if (!info) {
|
|
344
|
+
for (const name of PROJECT_CONFIG_BASENAMES) {
|
|
345
|
+
const candidate = path.join(dir, name);
|
|
346
|
+
const stat = safeFileStat(candidate);
|
|
347
|
+
if (stat?.isFile()) {
|
|
348
|
+
info = {
|
|
247
349
|
path: candidate,
|
|
248
350
|
dir,
|
|
249
351
|
mtimeMs: stat.mtimeMs,
|
|
250
352
|
size: stat.size,
|
|
251
|
-
}
|
|
252
|
-
|
|
253
|
-
}
|
|
353
|
+
};
|
|
354
|
+
break;
|
|
355
|
+
}
|
|
254
356
|
}
|
|
255
357
|
}
|
|
358
|
+
for (const location of LEGACY_PROJECT_LOCATIONS) {
|
|
359
|
+
const file = path.join(dir, location.relativePath);
|
|
360
|
+
const stat = safeFileStat(file);
|
|
361
|
+
if (!stat?.isFile())
|
|
362
|
+
continue;
|
|
363
|
+
legacySources.push({
|
|
364
|
+
path: file,
|
|
365
|
+
mtimeMs: stat.mtimeMs,
|
|
366
|
+
size: stat.size,
|
|
367
|
+
});
|
|
368
|
+
const outcome = readConfigDocument(file);
|
|
369
|
+
if (outcome.status === "error") {
|
|
370
|
+
reportConfigReadFailure({
|
|
371
|
+
file,
|
|
372
|
+
location,
|
|
373
|
+
tier: "project",
|
|
374
|
+
error: outcome.error,
|
|
375
|
+
sourceText: outcome.sourceText,
|
|
376
|
+
});
|
|
377
|
+
continue;
|
|
378
|
+
}
|
|
379
|
+
if (outcome.status !== "ok")
|
|
380
|
+
continue;
|
|
381
|
+
legacyDocuments.push({
|
|
382
|
+
tier: "project",
|
|
383
|
+
file,
|
|
384
|
+
location,
|
|
385
|
+
value: outcome.value,
|
|
386
|
+
});
|
|
387
|
+
}
|
|
256
388
|
}
|
|
257
|
-
return {
|
|
389
|
+
return {
|
|
390
|
+
info,
|
|
391
|
+
dirMtimes: bearingDirMtimes(dirMtimes, info),
|
|
392
|
+
legacyRecords: legacyDeprecationRecords(legacyDocuments),
|
|
393
|
+
legacySources,
|
|
394
|
+
checkedAtMs: Date.now(),
|
|
395
|
+
};
|
|
258
396
|
}
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
397
|
+
/**
|
|
398
|
+
* The legacy documents' deprecation records, BOUNDED per document (#2426
|
|
399
|
+
* review round 5, F-A/F-B).
|
|
400
|
+
*
|
|
401
|
+
* This path shipped its records raw. A legacy file's recognized top-level key
|
|
402
|
+
* count is user input, so one 28-key `pi-lens.json` produced 28 notifications
|
|
403
|
+
* through this loader while the LSP loader — which finalizes the same records —
|
|
404
|
+
* produced the bound plus a count for the identical file, and five nested
|
|
405
|
+
* legacy files produced 145 with no suppression record anywhere. Every producer
|
|
406
|
+
* now goes through the one \`finalizeRecords\`.
|
|
407
|
+
*
|
|
408
|
+
* Per DOCUMENT rather than per walk, because these are not one resolution: each
|
|
409
|
+
* file is separately actionable ("move these keys out of THIS file"), and a
|
|
410
|
+
* per-walk bound would silently drop whole files' advice while naming only the
|
|
411
|
+
* last one. Per document also makes the two loaders agree on the count for a
|
|
412
|
+
* given file, which is the parity `config-notice-ownership` asserts.
|
|
413
|
+
*/
|
|
414
|
+
function legacyDeprecationRecords(documents) {
|
|
415
|
+
const home = os.homedir();
|
|
416
|
+
return documents.flatMap((document) => finalizeRecords(deprecationRecords([document], home), {
|
|
417
|
+
file: document.file,
|
|
418
|
+
tier: document.tier,
|
|
419
|
+
}));
|
|
420
|
+
}
|
|
421
|
+
/**
|
|
422
|
+
* The directory mtimes this entry's freshness is keyed on: the BEARING chain —
|
|
423
|
+
* `startDir` up to and including the directory that supplied `info` (#2426
|
|
424
|
+
* review round 5, F-C).
|
|
425
|
+
*
|
|
426
|
+
* The walk itself no longer stops at the first bearing directory, because the
|
|
427
|
+
* legacy documents a user is asked to migrate can sit above it. Keying
|
|
428
|
+
* freshness on every directory it VISITS is a different decision, and a bad
|
|
429
|
+
* one: the walk runs to just below `$HOME`, so the entry was invalidated by any
|
|
430
|
+
* churn in an ancestor like `~/Desktop` — a full re-walk, re-read and re-parse
|
|
431
|
+
* of every legacy document, on a hot path, triggered by an unrelated directory.
|
|
432
|
+
*
|
|
433
|
+
* Scoping it back to the bearing chain restores the pre-#2426 invalidation
|
|
434
|
+
* surface exactly. Nothing that decides a VALUE is outside that chain, and an
|
|
435
|
+
* already-discovered legacy document above it carries its own (mtime, size)
|
|
436
|
+
* stamp in `legacySources`, so an EDIT to one is still noticed. What is given
|
|
437
|
+
* up is noticing a legacy file NEWLY CREATED above the bearing directory
|
|
438
|
+
* mid-process — records-only, and strictly more than the pre-#2426 loader saw,
|
|
439
|
+
* since it never looked above that directory at all.
|
|
440
|
+
*
|
|
441
|
+
* When NO config file is found anywhere (#2483), `info` is undefined and there
|
|
442
|
+
* is no bearing directory to stop at — but the majority of projects have no
|
|
443
|
+
* config at all, so this is the COMMON case, not an edge one. Falling back to
|
|
444
|
+
* the full chain here (the pre-fix behavior) keyed freshness on every
|
|
445
|
+
* directory up to just below `$HOME`: unrelated churn in `~/Desktop` or
|
|
446
|
+
* `~/projects` invalidated the entry and forced a full re-walk on the very
|
|
447
|
+
* next load, every load, forever.
|
|
448
|
+
*
|
|
449
|
+
* The nearest directory a config COULD have appeared in is `startDir` itself
|
|
450
|
+
* — `dirMtimes[0]`, first in the innermost-first walk order (`configSearchDirs`)
|
|
451
|
+
* — so that is what per-call freshness is scoped to, the same bearing-directory
|
|
452
|
+
* principle as the presence case (a directory always includes itself as the
|
|
453
|
+
* degenerate bearing chain). A config file created directly in `startDir`
|
|
454
|
+
* bumps `startDir`'s own mtime and is found on the next load.
|
|
455
|
+
*
|
|
456
|
+
* A config file created further up the chain does not move `startDir`'s own
|
|
457
|
+
* mtime, so it is invisible to THIS check alone (round 1 of #2483 stopped
|
|
458
|
+
* here, leaving staleness unbounded — no production caller ever resets the
|
|
459
|
+
* cache and a same-`startDir` load never rediscovers). `discoveryCacheStillFresh`
|
|
460
|
+
* closes that gap: a no-`info` entry is force-expired at most once per
|
|
461
|
+
* `FRESHNESS_CADENCE_MS`, independent of what `dirMtimes` says, which sends
|
|
462
|
+
* the NEXT load through a full re-walk of the ancestor chain regardless — so
|
|
463
|
+
* a config created anywhere in it is noticed within one cadence window.
|
|
464
|
+
* Bounded staleness, and strictly narrower than the pre-fix "any ancestor up
|
|
465
|
+
* to $HOME invalidates on every load".
|
|
466
|
+
*/
|
|
467
|
+
function bearingDirMtimes(dirMtimes, info) {
|
|
468
|
+
if (info) {
|
|
469
|
+
const bearing = dirMtimes.findIndex((entry) => entry.dir === info.dir);
|
|
470
|
+
return bearing < 0 ? [...dirMtimes] : dirMtimes.slice(0, bearing + 1);
|
|
471
|
+
}
|
|
472
|
+
return dirMtimes.slice(0, 1);
|
|
273
473
|
}
|
|
274
|
-
function parseRulePolicyList(
|
|
474
|
+
function parseRulePolicyList(note, ruleId, key, value) {
|
|
275
475
|
if (!Array.isArray(value)) {
|
|
276
|
-
|
|
476
|
+
note(`rules.${ruleId}.${key} must be an array of strings`);
|
|
277
477
|
return { list: [], invalid: true };
|
|
278
478
|
}
|
|
279
479
|
const list = [];
|
|
@@ -290,34 +490,78 @@ function parseRulePolicyList(configPath, ruleId, key, value) {
|
|
|
290
490
|
// but none were usable strings (all blank / non-string), which is a real
|
|
291
491
|
// authoring mistake that must not fail silently.
|
|
292
492
|
if (value.length > 0) {
|
|
293
|
-
|
|
493
|
+
note(`rules.${ruleId}.${key} must contain at least one non-empty string`);
|
|
294
494
|
return { list: [], invalid: true };
|
|
295
495
|
}
|
|
296
496
|
return { list: [], invalid: false };
|
|
297
497
|
}
|
|
298
498
|
return { list, invalid: false };
|
|
299
499
|
}
|
|
500
|
+
const NO_RECORDS = [];
|
|
300
501
|
function parseConfigFile(configPath) {
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
502
|
+
const { note, records: ignoredRecords } = ignoredRecordCollector(configPath, "project");
|
|
503
|
+
const outcome = readConfigDocument(configPath);
|
|
504
|
+
if (outcome.status === "error") {
|
|
505
|
+
// `{ parseError }`, not a pre-stringified message (#2431): the raw error
|
|
506
|
+
// reaches one seam, which decides how much of a `JSON.parse`
|
|
507
|
+
// `SyntaxError#message` (which embeds a snippet of the file being parsed)
|
|
508
|
+
// survives into the sinks.
|
|
509
|
+
note({ parseError: outcome.error, sourceText: outcome.sourceText });
|
|
510
|
+
return {
|
|
511
|
+
config: EMPTY_PROJECT_CONFIG,
|
|
512
|
+
records: NO_RECORDS,
|
|
513
|
+
ignored: ignoredRecords(),
|
|
514
|
+
};
|
|
305
515
|
}
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
516
|
+
// The file was stat'd as present by the discovery above, so `missing` here is
|
|
517
|
+
// a delete that raced the read. Nothing to warn about — the next call
|
|
518
|
+
// re-discovers and finds no config at all.
|
|
519
|
+
if (outcome.status === "missing") {
|
|
520
|
+
return {
|
|
521
|
+
config: EMPTY_PROJECT_CONFIG,
|
|
522
|
+
records: NO_RECORDS,
|
|
523
|
+
ignored: NO_RECORDS,
|
|
524
|
+
};
|
|
309
525
|
}
|
|
310
|
-
if (!
|
|
311
|
-
|
|
312
|
-
|
|
526
|
+
if (!outcome.value ||
|
|
527
|
+
typeof outcome.value !== "object" ||
|
|
528
|
+
Array.isArray(outcome.value)) {
|
|
529
|
+
note("top-level value must be an object");
|
|
530
|
+
return {
|
|
531
|
+
config: EMPTY_PROJECT_CONFIG,
|
|
532
|
+
records: NO_RECORDS,
|
|
533
|
+
ignored: ignoredRecords(),
|
|
534
|
+
};
|
|
313
535
|
}
|
|
314
|
-
|
|
536
|
+
// Through the #2425 core (#2426): the value is validated against the
|
|
537
|
+
// canonical schema before this loader's own field parsing sees it, so the
|
|
538
|
+
// depth bound, the prototype-key policy and the declared `lsp.*` types apply
|
|
539
|
+
// here exactly as they do in the LSP loader. `raw` is the VALIDATED value
|
|
540
|
+
// rather than the parse output, which is the one place the field's
|
|
541
|
+
// documented "the parsed JSON as-is" narrows: a `__proto__` key or a
|
|
542
|
+
// 4000-deep blob no longer rides into `.raw`'s consumers (`trivy-client.ts`,
|
|
543
|
+
// the helm-render runner).
|
|
544
|
+
const resolved = resolveOnePiLensConfigDocument({
|
|
545
|
+
tier: "project",
|
|
546
|
+
file: configPath,
|
|
547
|
+
location: projectLocationFor(configPath),
|
|
548
|
+
value: outcome.value,
|
|
549
|
+
});
|
|
550
|
+
// The records are RETURNED, not reported here (#2426 review round 3, F2):
|
|
551
|
+
// this function's result is what the caller caches, and a cache HIT must
|
|
552
|
+
// still report them every session — a call this function never makes on a
|
|
553
|
+
// hit. Reporting here would fire only on a cache MISS (session 1), and
|
|
554
|
+
// `resetProjectLensConfigCache` has no production caller, so every session
|
|
555
|
+
// after the first silently lost the `config-deprecated` ledger row despite
|
|
556
|
+
// the file still being the exact deprecated one on disk.
|
|
557
|
+
const raw = resolved.value;
|
|
558
|
+
const obj = resolved.value;
|
|
315
559
|
const ignore = Array.isArray(obj.ignore)
|
|
316
560
|
? obj.ignore.filter((p) => typeof p === "string")
|
|
317
561
|
: [];
|
|
318
562
|
const mutations = {};
|
|
319
563
|
for (const spec of PROJECT_SCOPED_LENS_FLAGS) {
|
|
320
|
-
assignFlagConfigSection(obj, mutations, spec.configKey,
|
|
564
|
+
assignFlagConfigSection(obj, mutations, spec.configKey, note);
|
|
321
565
|
}
|
|
322
566
|
const rules = {};
|
|
323
567
|
if (obj.rules && typeof obj.rules === "object" && !Array.isArray(obj.rules)) {
|
|
@@ -327,7 +571,7 @@ function parseConfigFile(configPath) {
|
|
|
327
571
|
// disable`), which lands here as an array and would otherwise be
|
|
328
572
|
// dropped without a word — the one shape a user is most likely to try.
|
|
329
573
|
if (!ruleCfg || typeof ruleCfg !== "object" || Array.isArray(ruleCfg)) {
|
|
330
|
-
|
|
574
|
+
note(`rules.${ruleId} must be an object with threshold, disable, or select; ignored`);
|
|
331
575
|
continue;
|
|
332
576
|
}
|
|
333
577
|
const r = ruleCfg;
|
|
@@ -338,17 +582,17 @@ function parseConfigFile(configPath) {
|
|
|
338
582
|
entry.threshold = r.threshold;
|
|
339
583
|
}
|
|
340
584
|
else if ("threshold" in r) {
|
|
341
|
-
|
|
585
|
+
note(`rules.${ruleId}.threshold must be a positive finite number`);
|
|
342
586
|
}
|
|
343
587
|
if ("disable" in r) {
|
|
344
|
-
const parsed = parseRulePolicyList(
|
|
588
|
+
const parsed = parseRulePolicyList(note, ruleId, "disable", r.disable);
|
|
345
589
|
// #1087: an explicitly empty list is valid-but-empty (no warning);
|
|
346
590
|
// don't store a pointless no-op entry for it.
|
|
347
591
|
if (!parsed.invalid && parsed.list.length > 0)
|
|
348
592
|
entry.disable = parsed.list;
|
|
349
593
|
}
|
|
350
594
|
if ("select" in r) {
|
|
351
|
-
const parsed = parseRulePolicyList(
|
|
595
|
+
const parsed = parseRulePolicyList(note, ruleId, "select", r.select);
|
|
352
596
|
if (!parsed.invalid && parsed.list.length > 0)
|
|
353
597
|
entry.select = parsed.list;
|
|
354
598
|
}
|
|
@@ -361,7 +605,7 @@ function parseConfigFile(configPath) {
|
|
|
361
605
|
rules[ruleId] = entry;
|
|
362
606
|
}
|
|
363
607
|
else if (!("threshold" in r) && !("disable" in r) && !("select" in r)) {
|
|
364
|
-
|
|
608
|
+
note(`rules.${ruleId} has no recognized setting (threshold, disable, select); ignored`);
|
|
365
609
|
}
|
|
366
610
|
}
|
|
367
611
|
}
|
|
@@ -373,7 +617,7 @@ function parseConfigFile(configPath) {
|
|
|
373
617
|
maxProjectFiles = obj.maxProjectFiles;
|
|
374
618
|
}
|
|
375
619
|
else {
|
|
376
|
-
|
|
620
|
+
note("maxProjectFiles must be a positive finite number");
|
|
377
621
|
}
|
|
378
622
|
}
|
|
379
623
|
let reviewGraph;
|
|
@@ -381,7 +625,7 @@ function parseConfigFile(configPath) {
|
|
|
381
625
|
if (!obj.reviewGraph ||
|
|
382
626
|
typeof obj.reviewGraph !== "object" ||
|
|
383
627
|
Array.isArray(obj.reviewGraph)) {
|
|
384
|
-
|
|
628
|
+
note("reviewGraph must be an object");
|
|
385
629
|
}
|
|
386
630
|
else {
|
|
387
631
|
const rg = obj.reviewGraph;
|
|
@@ -392,7 +636,44 @@ function parseConfigFile(configPath) {
|
|
|
392
636
|
reviewGraph = { maxFiles: clamped };
|
|
393
637
|
}
|
|
394
638
|
else {
|
|
395
|
-
|
|
639
|
+
note("reviewGraph.maxFiles must be a positive finite number");
|
|
640
|
+
}
|
|
641
|
+
}
|
|
642
|
+
}
|
|
643
|
+
}
|
|
644
|
+
let startup;
|
|
645
|
+
if (obj.startup !== undefined) {
|
|
646
|
+
if (!obj.startup ||
|
|
647
|
+
typeof obj.startup !== "object" ||
|
|
648
|
+
Array.isArray(obj.startup)) {
|
|
649
|
+
note("startup must be an object");
|
|
650
|
+
}
|
|
651
|
+
else {
|
|
652
|
+
const section = obj.startup;
|
|
653
|
+
if (section.mode === "quick" ||
|
|
654
|
+
section.mode === "full" ||
|
|
655
|
+
section.mode === "minimal") {
|
|
656
|
+
startup = { mode: section.mode };
|
|
657
|
+
}
|
|
658
|
+
else if ("mode" in section) {
|
|
659
|
+
note('startup.mode must be "quick", "full", or "minimal"');
|
|
660
|
+
}
|
|
661
|
+
if (section.scans !== undefined) {
|
|
662
|
+
if (!section.scans ||
|
|
663
|
+
typeof section.scans !== "object" ||
|
|
664
|
+
Array.isArray(section.scans)) {
|
|
665
|
+
note("startup.scans must be an object");
|
|
666
|
+
}
|
|
667
|
+
else if (typeof section.scans.enabled ===
|
|
668
|
+
"boolean") {
|
|
669
|
+
startup ??= {};
|
|
670
|
+
startup.scans = {
|
|
671
|
+
enabled: section.scans
|
|
672
|
+
.enabled,
|
|
673
|
+
};
|
|
674
|
+
}
|
|
675
|
+
else if ("enabled" in section.scans) {
|
|
676
|
+
note("startup.scans.enabled must be a boolean");
|
|
396
677
|
}
|
|
397
678
|
}
|
|
398
679
|
}
|
|
@@ -407,7 +688,7 @@ function parseConfigFile(configPath) {
|
|
|
407
688
|
// than being lumped in with typos — docs previously called this "silently
|
|
408
689
|
// ignored".
|
|
409
690
|
const knownProjectKeys = new Set([
|
|
410
|
-
...
|
|
691
|
+
...PROJECT_NON_FLAG_CONFIG_SECTIONS,
|
|
411
692
|
...flagConfigSectionKeys(PROJECT_SCOPED_LENS_FLAGS),
|
|
412
693
|
...PROJECT_FOREIGN_CONFIG_NAMESPACES,
|
|
413
694
|
]);
|
|
@@ -415,23 +696,58 @@ function parseConfigFile(configPath) {
|
|
|
415
696
|
...flagConfigSectionKeys(LENS_FLAGS),
|
|
416
697
|
...GLOBAL_NON_FLAG_CONFIG_SECTIONS,
|
|
417
698
|
].filter((key) => !knownProjectKeys.has(key)));
|
|
699
|
+
// The full DOTTED config keys of the flags a project file cannot set, for the
|
|
700
|
+
// sub-key scan below. Section-level keys are too coarse for a namespace that
|
|
701
|
+
// mixes scopes: `lsp` holds four project-scoped settings AND the global-only
|
|
702
|
+
// `lsp.enabled`.
|
|
703
|
+
const projectScoped = new Set(PROJECT_SCOPED_LENS_FLAGS.map((spec) => spec.configKey));
|
|
704
|
+
const globalScopeOnlyFlagKeys = LENS_FLAGS.map((spec) => spec.configKey).filter((configKey) => !projectScoped.has(configKey));
|
|
705
|
+
// The literal path is derived, not hand-typed (#2426 review round 3, S1):
|
|
706
|
+
// under `PI_LENS_CONFIG_PATH` the canonical global config is NOT
|
|
707
|
+
// `~/.pi-lens/config.json`, and a hardcoded string in this notice would name
|
|
708
|
+
// a file the resolver never reads.
|
|
709
|
+
const globalConfigLabel = homeRelativePath(getPiLensGlobalConfigPath(), os.homedir());
|
|
710
|
+
const warnUnhonoredKey = (label, globalOnly) => {
|
|
711
|
+
note(globalOnly
|
|
712
|
+
? `"${label}" is a global-only pi-lens setting and is not honored in a project .pi-lens.json (set it in ${globalConfigLabel} or pass the matching CLI flag); ignored`
|
|
713
|
+
: `unknown key "${label}" is not a recognized pi-lens setting (check for a typo); ignored`);
|
|
714
|
+
};
|
|
418
715
|
for (const key of Object.keys(obj)) {
|
|
419
716
|
if (knownProjectKeys.has(key))
|
|
420
717
|
continue;
|
|
421
|
-
|
|
422
|
-
|
|
718
|
+
warnUnhonoredKey(key, globalScopeOnlyKeys.has(key));
|
|
719
|
+
}
|
|
720
|
+
// A tolerated foreign namespace is tolerated KEY BY KEY (#2426 review round
|
|
721
|
+
// 2, F3). `lsp` is read out of this file by the LSP loader, but only four of
|
|
722
|
+
// its keys are project-scoped; `lsp.enabled` is the `--no-lsp` flag, which is
|
|
723
|
+
// `scope: "global"`. Blanket namespace tolerance swallowed it silently, which
|
|
724
|
+
// `docs/configuration.md`'s "nothing is ignored silently" forbids — so every
|
|
725
|
+
// other sub-key gets the same global-only-vs-typo signal a top-level key does,
|
|
726
|
+
// named with its DOTTED path so the notice says which setting is meant.
|
|
727
|
+
for (const [namespace, honored] of PROJECT_FOREIGN_NAMESPACE_HONORED_KEYS) {
|
|
728
|
+
const section = obj[namespace];
|
|
729
|
+
if (!section || typeof section !== "object" || Array.isArray(section)) {
|
|
730
|
+
continue;
|
|
423
731
|
}
|
|
424
|
-
|
|
425
|
-
|
|
732
|
+
for (const key of Object.keys(section)) {
|
|
733
|
+
if (honored.includes(key))
|
|
734
|
+
continue;
|
|
735
|
+
const dotted = `${namespace}.${key}`;
|
|
736
|
+
warnUnhonoredKey(dotted, globalScopeOnlyFlagKeys.some((configKey) => configKey === dotted || configKey.startsWith(`${dotted}.`)));
|
|
426
737
|
}
|
|
427
738
|
}
|
|
428
739
|
return {
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
740
|
+
config: {
|
|
741
|
+
...(startup === undefined ? {} : { startup }),
|
|
742
|
+
ignore,
|
|
743
|
+
rules,
|
|
744
|
+
...mutations,
|
|
745
|
+
maxProjectFiles,
|
|
746
|
+
reviewGraph,
|
|
747
|
+
raw,
|
|
748
|
+
configPath,
|
|
749
|
+
},
|
|
750
|
+
records: resolved.records,
|
|
751
|
+
ignored: ignoredRecords(),
|
|
436
752
|
};
|
|
437
753
|
}
|