@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
|
@@ -53,6 +53,43 @@ so the final state is formatter-stable. A `write` immediately followed by an
|
|
|
53
53
|
deferred too. See `clients/pipeline.ts`, `clients/runtime-tool-result.ts`, and
|
|
54
54
|
`clients/runtime-agent-end.ts`.
|
|
55
55
|
|
|
56
|
+
A tool pi-lens does not name is classified by the SHAPE of its arguments
|
|
57
|
+
(`clients/mutating-tool.ts`). A host or extension edit tool called `replace` or
|
|
58
|
+
`insert` therefore gets a turn-state entry, a change-log receipt attributed to
|
|
59
|
+
the tool itself, and the deferred autofix and format pass — the same chain
|
|
60
|
+
`edit` gets. Its lines are resolved when the anchor is unambiguous (roughly
|
|
61
|
+
two-thirds of anchors in practice — `clients/hashline-anchor.ts`); otherwise
|
|
62
|
+
the mutation is recorded whole-file with lines unknown, and the
|
|
63
|
+
read-before-edit guard takes its no-line-info arm rather than guessing.
|
|
64
|
+
Deferred is the default for any edit-shaped tool pi-lens cannot place, because
|
|
65
|
+
formatting between the calls of a multi-step rewrite fights the tool that is
|
|
66
|
+
still writing. A tool whose SHAPE is unrecognized too is caught by observation:
|
|
67
|
+
pi-lens takes a bounded snapshot of the path that call names — and only that
|
|
68
|
+
path, so a change to a neighbouring file is never blamed on it — replays
|
|
69
|
+
whatever actually changed through the same chain, then remembers that tool as
|
|
70
|
+
mutating for the session, and on disk under the project's data directory once a
|
|
71
|
+
second observation confirms it, so later sessions classify it by name with no
|
|
72
|
+
snapshot at all. A tool that names no file is caught at `agent_settled` by an
|
|
73
|
+
incremental content check over the files pi-lens has already read, written,
|
|
74
|
+
diagnosed or opened on a language server: a rotating window of the set each
|
|
75
|
+
turn, reading only the files whose size or timestamp actually moved, so the
|
|
76
|
+
check stays affordable as the set grows. A file it has never seen has no
|
|
77
|
+
baseline and is therefore not covered, and a file it cannot verify is named
|
|
78
|
+
rather than reformatted on a timestamp alone
|
|
79
|
+
(`clients/observed-mutation.ts`).
|
|
80
|
+
|
|
81
|
+
**Bundled fallback lint configs stay conservative.** When a project ships no
|
|
82
|
+
tool config, the package-owned fallback configs set the rules (`config/biome/core.jsonc`,
|
|
83
|
+
`config/ruff/core.toml`, `config/markdownlint/core.json`). The biome fallback
|
|
84
|
+
disables `useImportType`: its safe fix rewrites a value import used only in
|
|
85
|
+
type positions into `import type`, which erases the runtime binding that
|
|
86
|
+
experimental decorator metadata (`emitDecoratorMetadata`) still needs and
|
|
87
|
+
breaks decorator-based dependency injection (refs #2385). Every other
|
|
88
|
+
recommended rule stays on, and an explicit project `biome.json(c)` remains
|
|
89
|
+
authoritative: if you enable `useImportType` there, pi-lens does not override
|
|
90
|
+
it. The ruff fallback selects no flake8-type-checking (TC) rules and applies
|
|
91
|
+
only safe fixes, so it never hoists imports into `TYPE_CHECKING` blocks.
|
|
92
|
+
|
|
56
93
|
Deferred formatting (the `agent_end` default) runs with **bounded
|
|
57
94
|
concurrency**: at most three formatter subprocesses in flight at once, with
|
|
58
95
|
results applied in admission order and cooperative yields between files, so a
|
|
@@ -140,12 +177,14 @@ pi-lens MCP server expose the same shape to Claude Code / any MCP client.
|
|
|
140
177
|
|
|
141
178
|
### Actionable Warnings
|
|
142
179
|
|
|
143
|
-
At `turn_end`, pi-lens writes
|
|
180
|
+
At `turn_end`, pi-lens writes `<project-data-dir>/cache/actionable-warnings.json` summarizing fixable warnings introduced by the current turn. This powers the optional conservative autofix at `agent_end`.
|
|
181
|
+
|
|
182
|
+
`<project-data-dir>` is whatever `getProjectDataDir(cwd)` resolves to: `<project>/.pi-lens` only when that legacy directory already exists, otherwise `~/.pi-lens/projects/<project-slug>` (or a `PILENS_DATA_DIR` location). The turn-end advisory points at `lens_diagnostics mode=delta` first and names the resolved file second, so you never have to work the layout out by hand (#2521).
|
|
144
183
|
|
|
145
184
|
**Report contents:**
|
|
146
185
|
|
|
147
186
|
- Warnings are delta-only by default: only diagnostics in lines touched during the current turn are included. Pass `--lens-actionable-warning-all` to report all warnings regardless of location
|
|
148
|
-
- Each warning carries a stable `aw:<hash>` ID derived from file, rule, and message, so suppression state persists across turns in
|
|
187
|
+
- Each warning carries a stable `aw:<hash>` ID derived from file, rule, and message, so suppression state persists across turns in `<project-data-dir>/cache/actionable-warning-state.json`
|
|
149
188
|
- Sources: pipeline `fixable` diagnostics (always included) and LSP code-action warnings when `--lens-actionable-warning-actions` is set
|
|
150
189
|
- When warnings are present, a concise advisory is injected into the agent context (no blocker language)
|
|
151
190
|
|
|
@@ -354,14 +393,14 @@ pi-lens ships an MCP (Model Context Protocol) server so Claude Code — or any M
|
|
|
354
393
|
|
|
355
394
|
**Why a second host:** the pi extension's tools are registered via the host SDK and run on pi's event loop. Claude Code lives in a different process with no SDK access. The MCP server sits in that gap, speaking JSON-RPC over stdio (or a warm Unix socket / Windows named pipe side-channel for the Claude Code PostToolUse hook). It's the easiest way to live-test, debug, and dogfood pi-lens — including running a **review loop** where Claude commits to pi-lens and re-measures.
|
|
356
395
|
|
|
357
|
-
**
|
|
396
|
+
**18 tools, grouped by lifecycle layer** (the same three layers the pi agent hooks use):
|
|
358
397
|
|
|
359
398
|
| Layer | MCP tools | What they expose |
|
|
360
399
|
|---|---|---|
|
|
361
|
-
| **Per-edit** | `pilens_analyze`, `pilens_lsp_diagnostics`, `pilens_lsp_navigation`, `pilens_ast_grep_search`, `pilens_ast_grep_replace`, `pilens_module_report`, `pilens_read_symbol` | The fast pipeline (format → autofix → LSP diagnostics → parallel runners) plus the structured read-substitute pair. `analyze` accepts `mode: warm \| fresh` — `warm` reuses the server's in-process LSP, `fresh` forks a worker that loads freshly-built code from disk so the result reflects the latest commit. |
|
|
400
|
+
| **Per-edit** | `pilens_analyze`, `pilens_lsp_diagnostics`, `pilens_lsp_navigation`, `pilens_ast_grep_search`, `pilens_ast_grep_replace`, `pilens_module_report`, `pilens_read_symbol`, `pilens_read_enclosing` | The fast pipeline (format → autofix → LSP diagnostics → parallel runners) plus the structured read-substitute pair. `analyze` accepts `mode: warm \| fresh` — `warm` reuses the server's in-process LSP, `fresh` forks a worker that loads freshly-built code from disk so the result reflects the latest commit. |
|
|
362
401
|
| **Per-turn** | `pilens_turn_end` | Drives the **real** `handleTurnEnd` (knip incremental, dep-circular, cascade, tests, actionable+code-quality warnings) — not a re-implementation. Caller-supplied edited files are auto-registered into turn-state via `addModifiedRange`. |
|
|
363
402
|
| **Per-session** | `pilens_session_start` | Drives the **real** `handleSessionStart` — full jscpd/knip/madge/govulncheck/gitleaks/trivy scans + complexity baselines + LSP warm. The error-debt baseline is not currently populated by the production session-start path. |
|
|
364
|
-
| **Project / observability** | `pilens_project_scan`, `pilens_diagnostics`, `pilens_health`, `pilens_latency`, `pilens_symbol_search` | Cheap project-wide scans, cached diagnostic state, latency telemetry, ranked identifier search (BM25 over the persisted word index — see [docs/word-index.md](word-index.md)). Cross-file blast radius now lives in `pilens_module_report`'s `blastRadius` option. `pilens_health` (and its pi-side `/lens-health` counterpart) also reports a bounded, process-local **degradation ledger** — trust refusals, mode suppressions, LSP breaker trips, formatter skips/failures, TypeScript/word-index/review-graph/project-snapshot idle evictions, WASM aborts, and diagnostics-timeout tallies — so silently degraded behavior stays visible instead of vanishing into a log. |
|
|
403
|
+
| **Project / observability** | `pilens_project_scan`, `pilens_project_report`, `pilens_diagnostics`, `pilens_health`, `pilens_latency`, `pilens_symbol_search`, `pilens_effective_config` | Cheap project-wide scans, cached diagnostic state, latency telemetry, ranked identifier search (BM25 over the persisted word index — see [docs/word-index.md](word-index.md)). Cross-file blast radius now lives in `pilens_module_report`'s `blastRadius` option. `pilens_health` (and its pi-side `/lens-health` counterpart) also reports a bounded, process-local **degradation ledger** — trust refusals, mode suppressions, LSP breaker trips, formatter skips/failures, TypeScript/word-index/review-graph/project-snapshot idle evictions, WASM aborts, and diagnostics-timeout tallies — so silently degraded behavior stays visible instead of vanishing into a log. `pilens_effective_config` answers **“why is X running / why is X not running”** from one query — the resolved configuration with the provenance of every setting, and for a file you name, its language plus every LSP server with the reason it was selected or denied and the runners that would dispatch. It reports sources, never values. |
|
|
365
404
|
| **Lifecycle / loop** | `pilens_rebuild` | Runs `npm run build:dist` so `pilens_analyze mode=fresh` reflects the latest commit. Makes the review loop self-contained: commit → `pilens_rebuild` → `pilens_analyze mode=fresh` → `pilens_latency`. |
|
|
366
405
|
|
|
367
406
|
**Honest limits** (live-tested, documented in `mcp.md`):
|
|
@@ -17,8 +17,8 @@ Dispatch is diagnostics-oriented: automatic formatting and safe autofix happen i
|
|
|
17
17
|
| Shell | ✓ | lsp, shellcheck | shfmt |
|
|
18
18
|
| Fish | ✓ (fish-lsp) | lsp, fish-indent | fish_indent |
|
|
19
19
|
| CSS/SCSS/Less | ✓ | lsp, stylelint | biome, prettier |
|
|
20
|
-
| HTML | ✓ | lsp, htmlhint | prettier
|
|
21
|
-
| YAML | ✓ | lsp, yamllint, actionlint (GitHub workflows), trivy-config (opt-in; Kubernetes manifests, CloudFormation) | prettier
|
|
20
|
+
| HTML | ✓ | lsp, htmlhint | prettier (with project config) |
|
|
21
|
+
| YAML | ✓ | lsp, yamllint, actionlint (GitHub workflows), trivy-config (opt-in; Kubernetes manifests, CloudFormation) | prettier (with project config) |
|
|
22
22
|
| JSON | ✓ | lsp, trivy-config (opt-in; CloudFormation templates only) | biome, prettier |
|
|
23
23
|
| Svelte | ✓ | lsp | oxfmt (needs `svelte` pkg installed + config `svelte: true`) |
|
|
24
24
|
| Vue | ✓ | lsp | prettier, oxfmt |
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
# Fixer contract
|
|
2
|
+
|
|
3
|
+
Deliver a root-caused fix with red proof and a reviewable handoff.
|
|
4
|
+
|
|
5
|
+
Read the issue, repository instructions, shared delegated worker contract, and
|
|
6
|
+
relevant architecture before editing. Reuse the shared seam and existing
|
|
7
|
+
machinery. Keep the change localized and compatible with concurrent branches.
|
|
8
|
+
|
|
9
|
+
Build the smallest faithful reproduction first. Preserve its pre-fix failure
|
|
10
|
+
output. After fixing, prove every new guard mutation-sensitive. Run a pattern
|
|
11
|
+
sweep and a population sweep for the defect class. Record per-member verdicts,
|
|
12
|
+
the blast radius, and bounded observability. Add a changelog fragment for a code
|
|
13
|
+
change.
|
|
14
|
+
|
|
15
|
+
## Tautological tests considered harmful
|
|
16
|
+
|
|
17
|
+
Do not assert a value that the test setup already supplied, duplicate the source
|
|
18
|
+
predicate in the test, or replace a real in-process seam with a fake to keep the
|
|
19
|
+
test green. Drive the production path and assert an independent observable. If
|
|
20
|
+
the test passes after deleting the guard, it is tautological and must be
|
|
21
|
+
redesigned before the fix is complete.
|
|
22
|
+
|
|
23
|
+
Verify the build and every targeted or sibling suite required by repository
|
|
24
|
+
policy. Follow the shared contract's Git authority. Report what ran, what was
|
|
25
|
+
skipped, and why. Use active, plain prose.
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
# Investigator contract
|
|
2
|
+
|
|
3
|
+
Root-cause runtime behavior from reproducible and durable evidence.
|
|
4
|
+
|
|
5
|
+
Define the symptom as a question that evidence can answer. Name the time window,
|
|
6
|
+
sessions, and build in scope. Prefer a tight reproduction loop before code
|
|
7
|
+
reading. Correlate records by stable identifiers, not time alone. Read each
|
|
8
|
+
record's producer before trusting its labels. Count a representative population,
|
|
9
|
+
and separate worker behavior from daemon behavior.
|
|
10
|
+
|
|
11
|
+
Keep the investigation read-only. Rank falsifiable hypotheses with evidence for
|
|
12
|
+
and against each hypothesis and the observation that would settle it. Sweep the
|
|
13
|
+
tree for the root-cause pattern and every member of the affected population.
|
|
14
|
+
State the blast radius and any missing or unbounded observability.
|
|
15
|
+
|
|
16
|
+
Deliver a proven diagnosis and a concrete next step. If the task expands to an
|
|
17
|
+
implementation, stop and return it to the orchestrator for a fixer delegation.
|
|
18
|
+
Use concise, active, plain prose.
|
|
19
|
+
|
|
20
|
+
## Tautological tests considered harmful
|
|
21
|
+
|
|
22
|
+
Treat a probe as evidence only when it can distinguish the competing hypotheses.
|
|
23
|
+
Do not seed the asserted outcome, mirror the production predicate, or rely on a
|
|
24
|
+
mock where the real in-process seam is available. Record the observation that
|
|
25
|
+
would turn the hypothesis red, and preserve that distinction in the handoff.
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
# Reviewer contract
|
|
2
|
+
|
|
3
|
+
Adversarially verify a change before merge and report proven findings.
|
|
4
|
+
|
|
5
|
+
Assume the implementation's claims are incomplete. Read the issue, full diff,
|
|
6
|
+
repository instructions, shared delegated worker contract, PR body, and merge
|
|
7
|
+
state. Keep the review read-only.
|
|
8
|
+
|
|
9
|
+
Reproduce the build and targeted tests. Verify quoted red-first evidence by
|
|
10
|
+
keeping the tests and removing the source fix. Mutate every new guard and demand
|
|
11
|
+
a red test. Probe inversions, concurrency, input channels, trust boundaries,
|
|
12
|
+
strict consumers, and durable-record compatibility. Repeat the pattern and
|
|
13
|
+
population sweeps. Check the stated blast radius, bounded observability,
|
|
14
|
+
changelog fragment, commit shape, and PR conventions.
|
|
15
|
+
|
|
16
|
+
Report `CRITICAL`, `HIGH`, `MEDIUM`, `LOW`, then `NITPICK` findings. Give the
|
|
17
|
+
file and line, a concrete failure, evidence, and a suggested fix. Separate issue
|
|
18
|
+
acceptance findings from repository-standard findings. List cleared categories,
|
|
19
|
+
then record one verdict: merge as-is, merge after fixes, or redesign. Never
|
|
20
|
+
merge or silently repair the author's branch. Use short, active, plain prose.
|
|
21
|
+
|
|
22
|
+
## Tautological tests considered harmful
|
|
23
|
+
|
|
24
|
+
Check that each regression test reaches the real seam and observes an independent
|
|
25
|
+
effect. Remove or mutate the claimed guard and require the test to fail for the
|
|
26
|
+
intended reason. Flag tests that restate the implementation, assert setup data,
|
|
27
|
+
or swap a real in-process store, sink, coordinator, or registry for a fake.
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
# Delegated worker delivery contract
|
|
2
|
+
|
|
3
|
+
This contract applies to every delegated pi-lens worker, regardless of the
|
|
4
|
+
agent runner or model. Pair it with exactly one role contract: fixer, reviewer,
|
|
5
|
+
or investigator.
|
|
6
|
+
|
|
7
|
+
Work only in the assigned worktree. Before editing, verify its absolute path,
|
|
8
|
+
registered worktree entry, branch, and base. Preserve junctioned dependencies.
|
|
9
|
+
Never switch another checkout's branch, and never use `git stash`. Save a patch
|
|
10
|
+
before temporarily reverting work.
|
|
11
|
+
|
|
12
|
+
Treat the acceptance criteria as the contract. For a regression, prove the new
|
|
13
|
+
test red before the fix and green after it. Mutating or removing a new guard
|
|
14
|
+
must make at least one test fail. Sweep the whole tree for the same code pattern
|
|
15
|
+
and every member of any enumerable population. Record both sweeps.
|
|
16
|
+
|
|
17
|
+
State the blast radius, including callers, durable shapes, strict parsers, and
|
|
18
|
+
tool surfaces. Add bounded observability for every new failure path. Include the
|
|
19
|
+
required changelog fragment for a code change. Report verification honestly.
|
|
20
|
+
Write active, direct prose with short sentences and consistent terms.
|
|
21
|
+
|
|
22
|
+
## Tautological tests considered harmful
|
|
23
|
+
|
|
24
|
+
A test must observe behavior through the real seam, not repeat the implementation
|
|
25
|
+
or feed the expected answer in through setup. Keep the red-first failure tied to
|
|
26
|
+
the defect, and mutate the guard or filter to prove the test can detect its loss.
|
|
27
|
+
Mocks belong only at true process or host boundaries. When a test can use the
|
|
28
|
+
real store, sink, coordinator, or registry, use it and assert the durable result.
|
|
29
|
+
|
|
30
|
+
Git authority is separate from the role. Commit, push, or open a PR only when
|
|
31
|
+
the delegation explicitly grants that authority after worktree verification.
|
|
32
|
+
Otherwise, edit and test with the assigned worktree as the command working
|
|
33
|
+
directory, then return the patch and evidence to the orchestrator. Never merge.
|
|
34
|
+
|
|
35
|
+
When Git authority is granted, use one logical commit with an imperative,
|
|
36
|
+
conventional-prefix subject of at most 50 characters, a blank line, and a
|
|
37
|
+
72-column body that states what and why. Reference the issue. Open a PR, do not
|
|
38
|
+
merge it, and report its URL.
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
# PR warden contract
|
|
2
|
+
|
|
3
|
+
Keep every pull request moving through review, fix, verification, and merge.
|
|
4
|
+
|
|
5
|
+
The warden is a read-only workflow controller. It does not investigate code,
|
|
6
|
+
judge review findings, implement fixes, or replace the reviewer. Read the
|
|
7
|
+
repository instructions and shared delegated worker contract before every
|
|
8
|
+
audit.
|
|
9
|
+
|
|
10
|
+
Build the ledger from GitHub and registered worktree evidence. For every pull
|
|
11
|
+
request, record the exact head SHA, matching worktree, dirty or unpushed state,
|
|
12
|
+
mergeability, required checks on that SHA, review outcome, active owner, and
|
|
13
|
+
next action. Use one state from this closed set:
|
|
14
|
+
|
|
15
|
+
- `UNREVIEWED`
|
|
16
|
+
- `REVIEW_FINDINGS`
|
|
17
|
+
- `FIXING`
|
|
18
|
+
- `AWAITING_VERIFY`
|
|
19
|
+
- `AWAITING_COMMIT_PUSH`
|
|
20
|
+
- `CI_PENDING`
|
|
21
|
+
- `CI_REAL_FAILURE`
|
|
22
|
+
- `CI_INFRA_FAILURE`
|
|
23
|
+
- `READY_AUTOMERGE`
|
|
24
|
+
- `MERGED`
|
|
25
|
+
|
|
26
|
+
A worker result becomes durable workflow evidence only when the orchestrator
|
|
27
|
+
records its role, exact head or working-tree identity, verdict, dispositions,
|
|
28
|
+
and next owner on the pull request or another shared ledger. Chat-only results
|
|
29
|
+
cannot drive a later audit. Flag a missing durable handoff record instead of
|
|
30
|
+
guessing that review passed.
|
|
31
|
+
|
|
32
|
+
Assign an owner and next action whenever the state changes. Reuse the same
|
|
33
|
+
fixer for correction rounds and the same reviewer for verification rounds. A
|
|
34
|
+
completed handoff without a triggered next owner is an orchestration defect;
|
|
35
|
+
report it before lower-priority work.
|
|
36
|
+
|
|
37
|
+
Run the audit after every worker completion, push, review verdict, CI verdict,
|
|
38
|
+
merge, and user status request. Poll GitHub and persistent external-worker
|
|
39
|
+
handles when completion notifications are unavailable. Never infer completion
|
|
40
|
+
from a quiet worker or clean worktree.
|
|
41
|
+
|
|
42
|
+
Classify required CI from its log and exact head. Treat assertion failures and
|
|
43
|
+
`[mem-watch] done. exitCode=1` as real. Apply the repository's exit-137 rules
|
|
44
|
+
before calling a failure infrastructure. Do not treat SonarCloud or another
|
|
45
|
+
advisory lane as a merge gate. A skipped required job is not green.
|
|
46
|
+
|
|
47
|
+
Mark `READY_AUTOMERGE` only when the actual final head has passed required CI
|
|
48
|
+
and adversarial review, every material finding has a disposition, and every
|
|
49
|
+
substantive fix has passed the same-reviewer verification loop. The
|
|
50
|
+
orchestrator, not the warden, commits, pushes, comments, enables automerge, or
|
|
51
|
+
merges.
|
|
52
|
+
|
|
53
|
+
Return a compact transition table followed by a priority queue. Name
|
|
54
|
+
orchestration breaches separately. Provide exact safe commands when they help
|
|
55
|
+
the orchestrator, but make no repository or GitHub mutation.
|
|
@@ -0,0 +1,359 @@
|
|
|
1
|
+
# Public API stability and versioning policy
|
|
2
|
+
|
|
3
|
+
**Status:** normative. Landed by #2418; gates #2416.
|
|
4
|
+
**Enforced by:** `clients/config-diagnostic-codes.ts` (the data),
|
|
5
|
+
`tests/support/schema-stability.ts`, `tests/config/schema-stability-tiers.test.ts`,
|
|
6
|
+
`tests/clients/config-diagnostic-codes.test.ts`,
|
|
7
|
+
`tests/clients/config-deprecation-registry.test.ts` (the tests).
|
|
8
|
+
|
|
9
|
+
pi-lens ships to roughly 28k installs a month. A config field, a warning a user
|
|
10
|
+
greps for, or a tool id becomes a compatibility obligation the moment it ships —
|
|
11
|
+
whether or not anyone wrote that obligation down. This document writes it down,
|
|
12
|
+
and every clause below is backed by a test rather than by convention, because a
|
|
13
|
+
policy nobody can fail is not a policy.
|
|
14
|
+
|
|
15
|
+
Scope: the unified config schema (#2415/#2416/#2383/#195), the capability
|
|
16
|
+
facades, the MCP tool mirror, and the versioned `PiLensApi` (#1358). It does not
|
|
17
|
+
define any catalog schema; it constrains how those schemas evolve.
|
|
18
|
+
|
|
19
|
+
## 1. Field stability tiers
|
|
20
|
+
|
|
21
|
+
Every property in a published pi-lens schema carries an `x-stability`
|
|
22
|
+
annotation, whose value is one of a closed vocabulary:
|
|
23
|
+
|
|
24
|
+
| Tier | Meaning |
|
|
25
|
+
| --- | --- |
|
|
26
|
+
| `experimental` | May change shape, semantics, or disappear in a **minor** release. Not covered by the compatibility guarantee. |
|
|
27
|
+
| `stable` | Covered by the guarantee. Shape and semantics change only in a **major**, through the checklist in section 4. |
|
|
28
|
+
|
|
29
|
+
Rules:
|
|
30
|
+
|
|
31
|
+
- **New fields default to `experimental`.** Shipping a field straight to
|
|
32
|
+
`stable` is a deliberate act, not a default.
|
|
33
|
+
- **Promotion `experimental` → `stable` is changelogged** under `Changed`,
|
|
34
|
+
naming the field. Demotion `stable` → `experimental` is a breaking change and
|
|
35
|
+
follows section 4.
|
|
36
|
+
- **A property with no tier fails CI.** `assertSchemaStabilityTiers` walks the
|
|
37
|
+
whole schema — `properties`, `patternProperties`, `items`, `prefixItems`,
|
|
38
|
+
`additionalProperties`, `oneOf`/`anyOf`/`allOf`, `not`, `if`/`then`/`else`,
|
|
39
|
+
`$defs`/`definitions` — so a field cannot hide from the tier requirement by
|
|
40
|
+
living inside a composition keyword.
|
|
41
|
+
- The **root schema** is not itself a property and carries no tier. Entries
|
|
42
|
+
under `$defs`/`definitions` are reusable subschemas, not published fields;
|
|
43
|
+
they need no tier, but every property *inside* them does.
|
|
44
|
+
|
|
45
|
+
The vocabulary lives in `STABILITY_TIERS` and the annotation key in
|
|
46
|
+
`STABILITY_TIER_KEY` (`clients/config-diagnostic-codes.ts`). #2416's first real
|
|
47
|
+
catalog schema asserts itself with the same two exported functions rather than
|
|
48
|
+
writing a second walker.
|
|
49
|
+
|
|
50
|
+
## 2. Stable config diagnostic codes
|
|
51
|
+
|
|
52
|
+
Every user-facing config validation or migration warning carries a code from a
|
|
53
|
+
closed, **append-only** namespace, `PILENS_CFG_NNNN`, registered once in
|
|
54
|
+
`CONFIG_DIAGNOSTIC_CODES`.
|
|
55
|
+
|
|
56
|
+
- **The prose is not API; the code is.** Message text may be rewritten in any
|
|
57
|
+
release. A code is never renumbered, never removed, and a retired number is
|
|
58
|
+
never reused — a retired code keeps its registry entry with an amended
|
|
59
|
+
description.
|
|
60
|
+
- The code is threaded through the one durable choke point
|
|
61
|
+
(`recordDegradationOnce` / `incrementDegradationCount` in
|
|
62
|
+
`clients/degradation-ledger.ts`) and through `notifyUserDegradation`, so the
|
|
63
|
+
same code appears in the user-visible message, in `extension.log`, and in the
|
|
64
|
+
durable `latency.log` degradation row.
|
|
65
|
+
- The durable row writes `code` **after** the bounded caller metadata, so the
|
|
66
|
+
ledger's `MAX_METADATA_KEYS` cap can never evict the one field a user greps
|
|
67
|
+
on.
|
|
68
|
+
- A new `notifyUserDegradation` call from any `clients/**/*config*.ts` file
|
|
69
|
+
without a registered code fails CI
|
|
70
|
+
(`tests/clients/config-diagnostic-codes.test.ts` scans for it; it does not
|
|
71
|
+
keep a hand-maintained list of call sites).
|
|
72
|
+
|
|
73
|
+
### How a user matches or suppresses a warning
|
|
74
|
+
|
|
75
|
+
**The match key is the bracketed suffix, not the prose.** Every coded warning is
|
|
76
|
+
rendered as:
|
|
77
|
+
|
|
78
|
+
```
|
|
79
|
+
pi-lens: ignoring invalid LSP config .pi-lens/lsp.json: Unexpected token } [PILENS_CFG_0001]
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
The trailing ` [PILENS_CFG_NNNN]` marker is appended by
|
|
83
|
+
`withConfigDiagnosticCode`, is idempotent, and is always last. Match on it:
|
|
84
|
+
|
|
85
|
+
```sh
|
|
86
|
+
# every ignored-config warning this session, from the durable degradation log
|
|
87
|
+
grep 'PILENS_CFG_0001' ~/.pi-lens/latency.log
|
|
88
|
+
|
|
89
|
+
# suppress one code while keeping every other pi-lens warning
|
|
90
|
+
pi ... 2>&1 | grep -v 'PILENS_CFG_0001'
|
|
91
|
+
```
|
|
92
|
+
|
|
93
|
+
The extraction pattern is exported as `CONFIG_DIAGNOSTIC_MARKER_PATTERN`
|
|
94
|
+
(capture group 1 is the code) so tooling need not re-derive it. Anything that
|
|
95
|
+
filters on the prose instead — `"ignoring invalid"` — is filtering on a string
|
|
96
|
+
this policy explicitly reserves the right to change.
|
|
97
|
+
|
|
98
|
+
### Registered codes
|
|
99
|
+
|
|
100
|
+
| Code | Meaning | Emitter |
|
|
101
|
+
| --- | --- | --- |
|
|
102
|
+
| `PILENS_CFG_0001` | A config file exists but could not be read or parsed, so it is ignored. | `warnIgnoredConfigOnce` (`clients/config-warn.ts`), the single choke point behind the LSP, global, and project config loaders. |
|
|
103
|
+
| `PILENS_CFG_0002` | A deprecated config **key** was accepted inside its deprecation window. | `deprecationRecords` (`clients/config-resolve.ts`), one record per `(file, key)`, delivered by `reportPiLensConfigRecords` (#2426). |
|
|
104
|
+
| `PILENS_CFG_0003` | A deprecated config **file location** was read inside its window. | Same producer and same delivery path as `PILENS_CFG_0002`. |
|
|
105
|
+
| `PILENS_CFG_0004` | A config field no schema property claims was dropped. | `validate()` (`clients/config-core/normalize.ts`) produces the record; `reportPiLensConfigRecords` (`clients/config-resolve.ts`) delivers it through `warnIgnoredConfigOnce` (#2426). |
|
|
106
|
+
| `PILENS_CFG_0005` | A config field's value did not match its schema and was dropped. One FIELD; the rest of the file is in effect. | Same producer and same delivery path as `PILENS_CFG_0004`. |
|
|
107
|
+
| `PILENS_CFG_0006` | A config key that would modify an object's prototype (`__proto__`, `constructor`, `prototype`) was refused. | Both halves of the config core, through the shared policy in `clients/config-core/safe-object.ts`. |
|
|
108
|
+
| `PILENS_CFG_0007` | Further config notices were suppressed by a bound, and this one carries the count — the WHOLE count, including anything an earlier bound in the same pipeline dropped. Nothing about the config is wrong; the notice list was truncated. | `MigrationRecordCollector.finalize` (`clients/config-core/records.ts`) — the ONE producer, reached through `finalizeRecords` by every record list: the shared resolution, the global loader's unknown-key scan, the project loader's unknown-key scan, and its legacy-document enumeration. Rendered with neutral prose and recorded under the `config-notice-suppressed` degradation kind, never `config-ignored`. |
|
|
109
|
+
| `PILENS_CFG_0008` | Resolving a config failed internally, so the WHOLE file was ignored and pi-lens ran on defaults. | The two guards under the pipeline: `resolveConfig` (`clients/config-core/resolve.ts`) and the global loader's post-parse catch (`clients/lens-config.ts`). Carries the error class only, never its message. |
|
|
110
|
+
|
|
111
|
+
A reserved code is registered and referenced by the deprecation registry, but
|
|
112
|
+
nothing emits it today. That is deliberate: the number must be pinned before the
|
|
113
|
+
migration warning ships, because append-only means the number cannot be chosen
|
|
114
|
+
later.
|
|
115
|
+
|
|
116
|
+
## 3. Config-envelope identity anchor
|
|
117
|
+
|
|
118
|
+
The unified config format reserves a `$schema` URL from its first published
|
|
119
|
+
version. Both halves are pinned in `clients/config-diagnostic-codes.ts`:
|
|
120
|
+
|
|
121
|
+
- `CONFIG_SCHEMA_ID` — the canonical schema URL. The published schema's own
|
|
122
|
+
`$id` must equal it.
|
|
123
|
+
- `CONFIG_SCHEMA_ANCHOR_KEY` (`"$schema"`) — the key a user's config file uses
|
|
124
|
+
to name the schema it was written against.
|
|
125
|
+
|
|
126
|
+
`assertSchemaIdentityAnchor` checks all three facts: the schema's `$id` matches,
|
|
127
|
+
the schema declares a meta-schema, and the root declares a `$schema` **instance**
|
|
128
|
+
property so a user's file can carry the anchor. Pinning the URL in one module is
|
|
129
|
+
what stops it drifting between the schema, the validator, and the docs.
|
|
130
|
+
|
|
131
|
+
## 4. Deprecation window and removal checklist
|
|
132
|
+
|
|
133
|
+
### The maintainer stance
|
|
134
|
+
|
|
135
|
+
**A legacy source is read for exactly one deprecation window, and then it is
|
|
136
|
+
actually removed.** pi-lens does not carry legacy config surfaces forever, and
|
|
137
|
+
it does not silently drop them either. Both failure modes are ruled out by the
|
|
138
|
+
same rule: while a surface is inside its window it is read and honored exactly
|
|
139
|
+
as before, with a bounded coded warning; at the next major it is removed through
|
|
140
|
+
the checklist below, announced in `Removed`. Nothing is ever dropped without an
|
|
141
|
+
announced window that preceded it.
|
|
142
|
+
|
|
143
|
+
### The data
|
|
144
|
+
|
|
145
|
+
Every deprecated key or file location is a row in `DEPRECATED_CONFIG_SURFACES`
|
|
146
|
+
carrying `surface`, `kind`, `code`, `deprecatedSince`, `removeNotBefore`, and a
|
|
147
|
+
`reason`. The registry test enforces:
|
|
148
|
+
|
|
149
|
+
- `deprecatedSince` names the release that **announces** the deprecation — for a
|
|
150
|
+
row announced only in an unreleased `.changelog/` fragment, that must be a
|
|
151
|
+
version later than the newest release in `CHANGELOG.md` (you cannot back-date
|
|
152
|
+
a deprecation into a version that already shipped without it);
|
|
153
|
+
- `removeNotBefore` is a **later major**, `X.0.0` — removal never happens in a
|
|
154
|
+
minor;
|
|
155
|
+
- the row's code is registered, and matches its kind;
|
|
156
|
+
- the surface is announced in a Changelog `Deprecated` section as a delimited
|
|
157
|
+
token (`` `pi-lens.json` ``), so a substring of a longer filename does not
|
|
158
|
+
count as an announcement;
|
|
159
|
+
- FILE rows name a location a loader actually reads, and KEY rows name a key the
|
|
160
|
+
`LSPConfig` interface actually declares — both checked against the exported
|
|
161
|
+
constants and the real interface body, never a hand-copied list.
|
|
162
|
+
|
|
163
|
+
Note that a canonical file is not deprecated because some of its keys are.
|
|
164
|
+
`.pi-lens.json` is a canonical location (#2426); the deprecated surfaces are the
|
|
165
|
+
legacy top-level LSP keys read from it, which are `kind: "key"` rows.
|
|
166
|
+
|
|
167
|
+
### The removal checklist
|
|
168
|
+
|
|
169
|
+
This is the checklist #2372 slice 5's "separately approved breaking-change plan"
|
|
170
|
+
instantiates. It does not invent a second process; slice 5 is one execution of
|
|
171
|
+
this list.
|
|
172
|
+
|
|
173
|
+
1. **Window elapsed.** The current version is at or past the row's
|
|
174
|
+
`removeNotBefore`, and that version is a major.
|
|
175
|
+
2. **Announced.** The surface has been in a shipped `Deprecated` changelog
|
|
176
|
+
section since `deprecatedSince`, continuously.
|
|
177
|
+
3. **Warned in-product.** The migration warning has been emitting its stable
|
|
178
|
+
code for the whole window — the user has had a coded, greppable signal, not
|
|
179
|
+
only a release note.
|
|
180
|
+
4. **Migration path documented and reachable.** The replacement surface exists,
|
|
181
|
+
is `stable`, and the `reason` field names it.
|
|
182
|
+
5. **Canonical-wins collision behavior verified.** For the whole window, a
|
|
183
|
+
config setting both the legacy and the canonical surface resolved to the
|
|
184
|
+
canonical one, with the coded warning naming the ignored legacy value.
|
|
185
|
+
6. **Removal PR does all four:** deletes the reader, deletes the registry row,
|
|
186
|
+
adds a `Removed` changelog entry naming the surface and the replacement, and
|
|
187
|
+
keeps the diagnostic code registered (codes outlive the surfaces they
|
|
188
|
+
described).
|
|
189
|
+
7. **Approved as a breaking change.** A major-version bump plus explicit
|
|
190
|
+
maintainer approval on the plan; a removal never rides in on an unrelated PR.
|
|
191
|
+
|
|
192
|
+
Removing a row from `DEPRECATED_CONFIG_SURFACES` while the reader still exists,
|
|
193
|
+
or removing the reader while the row still exists, fails the registry test. The
|
|
194
|
+
two move together or not at all.
|
|
195
|
+
|
|
196
|
+
## 5. The config core
|
|
197
|
+
|
|
198
|
+
`clients/config-core/` is the one place a pi-lens configuration is validated,
|
|
199
|
+
merged, and explained. Every loader, catalog, and selector resolves through it
|
|
200
|
+
(#2425); a fourth merge semantics is a defect, not a design choice.
|
|
201
|
+
|
|
202
|
+
The pipeline is `RawConfig -> validate(schema) -> NormalizedConfig ->
|
|
203
|
+
merge(sources) -> Resolved<T>`, and `resolveConfig` runs both halves. It is
|
|
204
|
+
pure: no file reads, no logging, no ledger writes. Reporting is the separate,
|
|
205
|
+
explicit `reportPiLensConfigRecords` step (`clients/config-resolve.ts`, which is
|
|
206
|
+
where the loaders share it — never inside the core), so the warn-once latch
|
|
207
|
+
stays with the loaders rather than with the library.
|
|
208
|
+
|
|
209
|
+
Every loader reports **every** record its own resolution produced — it does not
|
|
210
|
+
filter to the records it "owns". Ownership is a property of the RECORD, not of
|
|
211
|
+
the caller: `reportPiLensConfigRecords` derives the reporting subsystem from the
|
|
212
|
+
record's own owner and tier, so an `lsp.*` key always reports as an LSP setting
|
|
213
|
+
and a pi-lens key always reports under the loader for its tier, whichever loader
|
|
214
|
+
happened to open the file. A `(file, key)` that three loaders all resolve is
|
|
215
|
+
reported three times and the warn-once latch — keyed on
|
|
216
|
+
`(subsystem, file, key, reason)` — collapses those into the one notice the user
|
|
217
|
+
sees. Filtering by caller instead is what left a record no loader claimed
|
|
218
|
+
reported by nobody at all (#2426 review round 3, F1).
|
|
219
|
+
|
|
220
|
+
### Source tiers
|
|
221
|
+
|
|
222
|
+
Seven tiers, lowest value-precedence first. A later tier's value replaces an
|
|
223
|
+
earlier one for the same leaf.
|
|
224
|
+
|
|
225
|
+
| Tier | Class | Meaning |
|
|
226
|
+
| --- | --- | --- |
|
|
227
|
+
| `builtin` | **default** | pi-lens's own shipped defaults. |
|
|
228
|
+
| `global` | operator | The user's machine-global config. |
|
|
229
|
+
| `project` | **repo** | A config file inside the checkout. |
|
|
230
|
+
| `nested-project` | **repo** | A config file in a nested package. |
|
|
231
|
+
| `env` | operator | Environment variables. |
|
|
232
|
+
| `cli` | operator | Command-line arguments. |
|
|
233
|
+
| `host` | operator | The host application's decision. |
|
|
234
|
+
|
|
235
|
+
The class column is a second, independent axis, and it has **three** values, not
|
|
236
|
+
two. `repo` tiers carry content that arrived with a checkout — content a user
|
|
237
|
+
may never have read. `operator` tiers are a deliberate act by the person running
|
|
238
|
+
pi-lens. `default` is pi-lens's own shipped opinion, which nobody chose. Only the
|
|
239
|
+
class decides who may lift a denial; `builtin` being its own class is what keeps
|
|
240
|
+
a shipped default overridable by the operator while still out of reach of
|
|
241
|
+
repository content.
|
|
242
|
+
|
|
243
|
+
### Monotonic deny precedence
|
|
244
|
+
|
|
245
|
+
A schema node marked `x-deny` resolves by denial rules instead of
|
|
246
|
+
last-tier-wins:
|
|
247
|
+
|
|
248
|
+
- `x-deny: "boolean-false"` — a `false` from an **operator** tier is never
|
|
249
|
+
lifted, by anything. A `false` from a `default` or `repo` tier is lifted only
|
|
250
|
+
by an explicit `true` from an **operator** tier of higher precedence. A repo
|
|
251
|
+
tier never lifts a denial at all, its own class included.
|
|
252
|
+
- `x-deny: "array-union"` — the resolved list is the union of every tier's
|
|
253
|
+
members. There is no vocabulary for un-denying a member, so a nearer tier that
|
|
254
|
+
omits one is expressing nothing. This outranks the node's own
|
|
255
|
+
`x-merge-strategy`: a denial a merge strategy could erase would not be
|
|
256
|
+
monotonic.
|
|
257
|
+
|
|
258
|
+
Provenance for a denied leaf names the tier that **made** the denial, not the
|
|
259
|
+
last tier to restate it — the answer to "why can I not turn this back on".
|
|
260
|
+
|
|
261
|
+
Two consequences are deliberate rulings rather than accidents of the algorithm,
|
|
262
|
+
and both are load-bearing:
|
|
263
|
+
|
|
264
|
+
**A built-in denial is a default, not a law.** `builtin: false` plus
|
|
265
|
+
`global: true` resolves to `true`, attributed to `global`; `builtin: false` plus
|
|
266
|
+
`project: true` stays `false`, attributed to `builtin`. When `builtin` sat in the
|
|
267
|
+
operator class, a conservative default pi-lens shipped — an `enabled: false`, or
|
|
268
|
+
any member of a built-in deny list — could never be lifted by anyone, including
|
|
269
|
+
the person who installed pi-lens, and the only escape was editing pi-lens's
|
|
270
|
+
source. A default the operator cannot override is not a default.
|
|
271
|
+
|
|
272
|
+
**An operator denial is not liftable by a nearer operator tier.** `global: false`
|
|
273
|
+
plus `cli: true` stays `false`. This is the spec letter and it is kept on
|
|
274
|
+
purpose: a denial is a security decision, and letting one operator surface
|
|
275
|
+
out-shout another would make the guarantee depend on which surface an attacker
|
|
276
|
+
could reach (an inherited `PILENS_*` environment variable, a wrapper script's
|
|
277
|
+
argv) rather than on what the operator decided. The escape hatch is an
|
|
278
|
+
operator-tier **change** — edit the global config, unset the variable — never a
|
|
279
|
+
repo-tier one.
|
|
280
|
+
|
|
281
|
+
### Prototype-safe keys
|
|
282
|
+
|
|
283
|
+
`__proto__`, `constructor`, and `prototype` are refused wherever a config
|
|
284
|
+
supplies a key, in both halves of the pipeline, with a `PILENS_CFG_0006` record
|
|
285
|
+
naming the key. No pi-lens setting is spelled that way, so there is nothing to
|
|
286
|
+
preserve, and assigning one would change an object's behavior rather than its
|
|
287
|
+
contents — a document that serializes as `{}` while answering an attacker's
|
|
288
|
+
value on every field read.
|
|
289
|
+
|
|
290
|
+
Both halves also bound their own recursion at `MAX_CONFIG_DEPTH` (32) and
|
|
291
|
+
`resolveConfig` never throws: a config that cannot be resolved degrades to
|
|
292
|
+
absent with records, never to a failed session.
|
|
293
|
+
|
|
294
|
+
A schema node that declares no `type` — or a `type` keyword the core does not
|
|
295
|
+
recognize — is **opaque**, and an opaque node is walked by the value's own
|
|
296
|
+
shape rather than passed through. Its children are kept (that is what an opaque
|
|
297
|
+
node means), but they are copied, depth-counted, key-checked, and recorded like
|
|
298
|
+
any other. A schema that wants a genuinely free-form subtree should still say
|
|
299
|
+
`additionalProperties: true`, which states the intent instead of relying on an
|
|
300
|
+
omission.
|
|
301
|
+
|
|
302
|
+
### Merge strategies
|
|
303
|
+
|
|
304
|
+
Objects are always merged field-wise; a nearer tier setting one key never erases
|
|
305
|
+
its siblings. Arrays follow the node's `x-merge-strategy`:
|
|
306
|
+
|
|
307
|
+
| Value | Behavior |
|
|
308
|
+
| --- | --- |
|
|
309
|
+
| `replace` (default) | The highest-precedence tier that sets the array supplies all of it. |
|
|
310
|
+
| `append` | Every tier's entries, concatenated lowest precedence first. |
|
|
311
|
+
| `keyed:<field>` | Entries matched across tiers by `<field>` and merged field-wise; unmatched entries appended. |
|
|
312
|
+
|
|
313
|
+
### The trust-gated `ProcessSpec`
|
|
314
|
+
|
|
315
|
+
A `ProcessSpec` carries a non-empty argv, a bounded env (count and bytes), a
|
|
316
|
+
closed `cwdMode`/`inputMode`, a timeout, its provenance, and the trust decision
|
|
317
|
+
that applied when it was read. `toSpawnArgs(spec)` is the only way to get
|
|
318
|
+
spawnable arguments out of one, and for a `project` or `nested-project` spec it
|
|
319
|
+
refuses unless **both** the spec's recorded trust and the host's current
|
|
320
|
+
`isProjectTrusted()` decision are `"trusted"`. Two conditions, because a session
|
|
321
|
+
can revoke trust after the config was read; one condition would make a spec a
|
|
322
|
+
permanent capability token.
|
|
323
|
+
|
|
324
|
+
`unknown` fails closed here, unlike `isToolInstallAllowedByTrust`. That gate
|
|
325
|
+
governs pi-lens's own managed tools; this one governs a command string a
|
|
326
|
+
repository wrote.
|
|
327
|
+
|
|
328
|
+
Refusals record under the existing `trust-refusal` degradation kind through
|
|
329
|
+
`incrementDegradationCount`, carrying the tier, `argv[0]`, and the trust
|
|
330
|
+
generation — never an argument or an env value.
|
|
331
|
+
|
|
332
|
+
### Redaction
|
|
333
|
+
|
|
334
|
+
`redactProcessSpec` is the only projection of a spec for a diagnostic or
|
|
335
|
+
telemetry surface. It strips every env **value** and every argv entry after
|
|
336
|
+
`argv[0]`; env names survive, because a name is a label and "which variables did
|
|
337
|
+
this server get" is the question an operator asks.
|
|
338
|
+
|
|
339
|
+
`provenanceView(resolved)` is redacted by construction: it is built from the
|
|
340
|
+
provenance map alone and never reads the resolved value, so no un-redacted view
|
|
341
|
+
exists. Validation records are bounded and structural — a reason names a key, a
|
|
342
|
+
type, and a count, never a value or a source snippet.
|
|
343
|
+
|
|
344
|
+
## Where each policy point is enforced
|
|
345
|
+
|
|
346
|
+
| Policy point | Data | Test |
|
|
347
|
+
| --- | --- | --- |
|
|
348
|
+
| 1. `x-stability` on every published field | `STABILITY_TIER_KEY`, `STABILITY_TIERS` | `tests/config/schema-stability-tiers.test.ts` via `assertSchemaStabilityTiers` |
|
|
349
|
+
| 2. Append-only `PILENS_CFG_*` codes | `CONFIG_DIAGNOSTIC_CODES` | `tests/clients/config-diagnostic-codes.test.ts` |
|
|
350
|
+
| 3. Reserved `$schema` identity anchor | `CONFIG_SCHEMA_ID`, `CONFIG_SCHEMA_ANCHOR_KEY` | `assertSchemaIdentityAnchor` |
|
|
351
|
+
| 4. Deprecation window + removal checklist | `DEPRECATED_CONFIG_SURFACES` | `tests/clients/config-deprecation-registry.test.ts` |
|
|
352
|
+
| 5. Config core: tiers, deny precedence, ProcessSpec trust | `clients/config-core/` | `tests/clients/config-core/*.test.ts`, `tests/config/config-core-schema-stability.test.ts` |
|
|
353
|
+
|
|
354
|
+
## Related
|
|
355
|
+
|
|
356
|
+
#2415 (shared config core), #2416/#2372 (catalog schema and its compat
|
|
357
|
+
template), #2383, #195 (selector semantics), #1358 (facade versioning — a
|
|
358
|
+
separate version axis this policy only has to compose with), #2426 (canonical
|
|
359
|
+
config locations).
|