@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
|
@@ -0,0 +1,182 @@
|
|
|
1
|
+
# Release-QA baseline matrix
|
|
2
|
+
|
|
3
|
+
The feature × modality matrix a release candidate is witnessed against before a
|
|
4
|
+
tag is cut. `scripts/release-qa.mjs` reads THIS FILE — the table below is the
|
|
5
|
+
runner's row list, not a copy of one — exports the committed tree, packs and
|
|
6
|
+
installs the candidate into a scratch `HOME`, drives each row's entry point
|
|
7
|
+
against a real `pi`, and writes `release-qa-report.md` plus one witness file per
|
|
8
|
+
row under `release-qa-evidence/`.
|
|
9
|
+
|
|
10
|
+
Every child process the runner spawns — `pi`, the MCP server, `node`, `npm` —
|
|
11
|
+
runs under a pinned environment: `HOME`, `USERPROFILE`, `PI_LENS_HOME`,
|
|
12
|
+
`PILENS_DATA_DIR`, `PI_LENS_INSTALL_LOG` and `npm_config_cache` all inside the
|
|
13
|
+
scratch root. `PI_LENS_INSTALL_LOG` is on that list by hard experience: it is
|
|
14
|
+
what `scripts/warm-loader-cache.mjs` keys its install log on, `PI_LENS_HOME`
|
|
15
|
+
does NOT redirect it, and the runner's first six runs — which pinned the pi-lens
|
|
16
|
+
home but passed no environment to `npm` at all — put 41 records into the
|
|
17
|
+
maintainer's real `~/.pi-lens/install.log` (#2619 review F1). The pack runs in a
|
|
18
|
+
`git archive HEAD` export, never the live checkout, because `npm pack` fires our
|
|
19
|
+
own `prepack` (rewrites `package.json` + `package-lock.json`) and `prepare`
|
|
20
|
+
(rebuilds `dist/`, downloads grammars, reinstalls git hooks).
|
|
21
|
+
|
|
22
|
+
Why it exists: #2587. The four shipped skills were suspected of never
|
|
23
|
+
registering for four releases because **no check ever asked a real pi what it
|
|
24
|
+
loaded**. The unit suite (~10.8k tests) and the nightly smokes (install, compat,
|
|
25
|
+
tool, lifecycle, parser) are per-seam; nothing composed them into a release
|
|
26
|
+
verdict with counted coverage, so a missing row read as absence rather than
|
|
27
|
+
arithmetic.
|
|
28
|
+
|
|
29
|
+
## Reading the table
|
|
30
|
+
|
|
31
|
+
- **row id** — the runner's key. Every id here must have a probe in
|
|
32
|
+
`scripts/release-qa.mjs`, and every probe there must appear here; the tie is
|
|
33
|
+
enforced by `tests/scripts/release-qa.test.ts`, so neither list can drift into
|
|
34
|
+
a hand-maintained mirror of the other.
|
|
35
|
+
- **entry point** — the command or RPC a **user path** actually takes. Never a
|
|
36
|
+
raw internal function: a row whose entry point is an internal call proves the
|
|
37
|
+
function works, not the product.
|
|
38
|
+
- **pass criterion** — the concrete thing the witness must SHOW (a status, a
|
|
39
|
+
count, a named record). "It ran without throwing" is not a criterion.
|
|
40
|
+
- **witness** — the artifact captured under `release-qa-evidence/`. A witness
|
|
41
|
+
that merely exists is not a witness; the report quotes the line that shows the
|
|
42
|
+
asserted result.
|
|
43
|
+
- **reuse** — the existing script that already produces this witness, or the
|
|
44
|
+
smoke that would have caught this row's regression. `new` means nothing in the
|
|
45
|
+
repo covers it, and the cell says so rather than leaving the gap implicit.
|
|
46
|
+
- **umbrella** — the open smoke-umbrella issue whose scope this row overlaps
|
|
47
|
+
(#1605 lifecycle/real-host lanes, #1829 tool-contract lanes), with one line on
|
|
48
|
+
where the two differ. `—` means neither umbrella claims this ground. This
|
|
49
|
+
column exists so a reader can tell at a glance which rows are a down-payment
|
|
50
|
+
on an already-filed umbrella and which are genuinely uncovered — and so the
|
|
51
|
+
umbrella issues are not re-litigated row by row when they are eventually
|
|
52
|
+
built.
|
|
53
|
+
|
|
54
|
+
## Modalities
|
|
55
|
+
|
|
56
|
+
| modality | what it stands for |
|
|
57
|
+
| --- | --- |
|
|
58
|
+
| `npm-pack` | the published artifact itself — what `npm publish` uploads |
|
|
59
|
+
| `npm-install` | a user installing the tarball into a project's `node_modules` |
|
|
60
|
+
| `pi-rpc` | pi loading the installed package, driven headless via `pi --mode rpc` |
|
|
61
|
+
| `mcp-stdio` | an MCP client speaking JSON-RPC to `dist/mcp/server.js` |
|
|
62
|
+
| `git-install` | `pi install git:...` against a pushed ref |
|
|
63
|
+
|
|
64
|
+
## The matrix
|
|
65
|
+
|
|
66
|
+
| row id | feature | modality | entry point | pass criterion | witness | reuse | umbrella |
|
|
67
|
+
| --- | --- | --- | --- | --- | --- | --- | --- |
|
|
68
|
+
| pack-skills-payload | the four shipped skills and the compiled entry are IN the published artifact | npm-pack | `npm pack --json` on the release candidate | packed file list contains `dist/index.js` and at least 4 `skills/**/SKILL.md` | pack listing JSON | new — `tests/packaging.test.ts` asserts `files[]` NAMES `skills/`, never that the pack carries SKILL.md files | — |
|
|
69
|
+
| install-selftest | the runtime dependency graph and the `pi.skills` manifest resolve AS INSTALLED | npm-install | `node <installed>/scripts/install-selftest.mjs --allow-soft` | process exits 0 and no `[FAIL]` line | selftest stdout | `scripts/install-selftest.mjs` verbatim — install-smoke's `smoke` job | #1605 lane 5 (real-host install), narrower: this row asserts the packaged artifact resolves, not that a host classifier parses |
|
|
70
|
+
| skills-registered | a real pi registers the four pi-lens skills from the installed package | pi-rpc | `pi install <installed pkg>` then `pi --mode rpc` plus `{"type":"get_commands"}` | at least 4 commands with `source` `skill`; every `sourceInfo.path` inside the installed package AND every `sourceInfo.source` equal to `extension:index` | get_commands response JSON | new probe on the #2589 mechanism — the recurrence is #2587 | — |
|
|
71
|
+
| commands-registered | the extension loads and registers its `lens-*` slash commands | pi-rpc | same RPC session as above | at least 1 command with `source` `extension` named `lens-*`, and zero `extension_error` events | same get_commands response plus the event stream | `scripts/rpc-load-check.mjs` assertion — install-smoke's `pi-load` job, which runs it against the PUBLISHED package only | #1605 lane 1 (real-host): the same real-host principle, applied to extension registration rather than stderr classification |
|
|
72
|
+
| mcp-tools-registered | the MCP mirror advertises the `pilens_*` tool surface | mcp-stdio | `node <installed>/dist/mcp/server.js` then `initialize` plus `tools/list` | every advertised tool name starts `pilens_`, and the set contains analyze, diagnostics, turn_end, lsp_navigation, health | tools/list response JSON | new — no smoke drives the MCP mirror from an install | — |
|
|
73
|
+
| mcp-diagnostics-full | `lens_diagnostics` full mode answers on a fixture repo | mcp-stdio | `tools/call` `pilens_diagnostics` with `mode` `full` and `refreshRunners` `cheap`, POLLED | text carries a `Summary (N files diagnosed this session)` line with N at least 1 | tool result text | new — `tests/clients` covers the handler, nothing covers it through a packaged install | — |
|
|
74
|
+
| mcp-turn-end | the turn-end pipeline runs over the turn's files and returns an advisory | mcp-stdio | `tools/call` `pilens_turn_end` with the fixture file | text carries `Turn-end over N file(s).` with N at least 1 | tool result text | new — `scripts/smoke-availability-lifecycle.mjs` covers lifecycle availability, not the packaged turn-end path | #1605 lane 2 (availability-lifecycle): overlaps the turn-end half; #1605 asserts latch recovery, this row asserts the packaged turn-end path answers at all |
|
|
75
|
+
| mcp-lsp-navigation | LSP navigation answers on a fixture | mcp-stdio | `tools/call` `pilens_lsp_navigation` with operation `documentSymbol` and the fixture path | result is not an error and names the fixture's exported `releaseQaFixtureSymbol` | tool result text | `scripts/smoke-tools.mjs --lsp` is the per-server sibling; this row is the packaged-path variant | #1829 lane 2/3 (gated real-binary + the rotating install lane): #1829 pins each tool's own contract, this row pins that the packaged LSP path answers |
|
|
76
|
+
| config-provenance | a project config is LOADED and its provenance is reportable | mcp-stdio | `tools/call` `pilens_effective_config` with the fixture file | result names the fixture's `.pi-lens.json` as a contributing document | tool result text | new — `tests/config/pi-lens-config-schema.test.ts` covers the schema, not the packaged load | — |
|
|
77
|
+
| degradation-visible | a silently-ignored input is RECORDED as a degradation instead of vanishing | mcp-stdio | `tools/call` `pilens_health` with the fixture's project-tier `lsp.enabled` (a global-only setting) loaded | health text carries a `config-ignored` degradation line naming the fixture's `.pi-lens.json` | health tool result text | `clients/degradation-ledger.ts` is the reused machinery; no smoke asserts it end to end | #1605 lane 2 (availability-lifecycle): the degradation-recorded half; #1605 additionally asserts RECOVERY, which this row does not |
|
|
78
|
+
| git-install-loads | a `git:` install of a pushed ref builds and loads in a real pi | git-install | `pi install git:github.com/apmantza/pi-lens@<ref>` then `get_commands` | at least 1 `lens-*` command and at least 4 skills | get_commands response JSON | `scripts/rpc-load-check.mjs` assertion, re-run against the git layout | — |
|
|
79
|
+
|
|
80
|
+
## Why `skills-registered` pins the registrar
|
|
81
|
+
|
|
82
|
+
pi-lens has **two independent skill registrars**: the `pi.skills` manifest, and
|
|
83
|
+
`index.ts`'s own `resources_discover` handler (#205,
|
|
84
|
+
`resolvePackagePath(import.meta.url, "skills")`), which never reads the
|
|
85
|
+
manifest. #2587 is the proof that one half can be broken for four releases while
|
|
86
|
+
the other silently covers for it — driving published pi-lens 4.1.3, with the
|
|
87
|
+
broken `["../../skills"]` manifest, through a real pi registers all four skills,
|
|
88
|
+
via `extension:index`.
|
|
89
|
+
|
|
90
|
+
So the row asserts `sourceInfo.source === "extension:index"` on every skill, not
|
|
91
|
+
merely that four skills appeared. The cost is stated plainly: a future release
|
|
92
|
+
that deliberately moved registration to the manifest would FAIL this row until
|
|
93
|
+
the criterion is updated. That is the intended trade — the row's job is to name
|
|
94
|
+
which half is load-bearing, and a row that accepts "some path worked" is exactly
|
|
95
|
+
the check that was missing for four releases. The observed registrar values are
|
|
96
|
+
printed in the witness either way, so a pi-side rename reads as a diagnosable
|
|
97
|
+
mismatch rather than a mystery.
|
|
98
|
+
|
|
99
|
+
## Outcomes
|
|
100
|
+
|
|
101
|
+
Every row ends in exactly one of four states, and the four partition the
|
|
102
|
+
discovered set — the report asserts the identity
|
|
103
|
+
`discovered = pass + fail + untested + skipped` and says ARITHMETIC MISMATCH if
|
|
104
|
+
it does not hold.
|
|
105
|
+
|
|
106
|
+
The printed arithmetic is `discovered / rows / untested`, and the three words
|
|
107
|
+
mean different things:
|
|
108
|
+
|
|
109
|
+
- **`discovered`** — rows in the matrix above. The denominator.
|
|
110
|
+
- **`rows`** — of those, the ones this run actually DROVE a probe for. A row the
|
|
111
|
+
runner has no probe for is not counted; a BLOCKED run drives none, so `rows`
|
|
112
|
+
reads 0. A SKIPPED row IS counted: its probe ran and decided the row
|
|
113
|
+
unreachable.
|
|
114
|
+
- **`untested`** — rows that produced no witness.
|
|
115
|
+
|
|
116
|
+
- **PASS** — the witness shows the pass criterion.
|
|
117
|
+
- **FAIL(cause)** — the witness shows something else. The cause is the observed
|
|
118
|
+
value, not a category.
|
|
119
|
+
- **UNTESTED(reason)** — no witness was produced. An async row that did not
|
|
120
|
+
reach a terminal state before its polling cap expires **UNTESTED, never PASS**;
|
|
121
|
+
a row with no probe implementation is UNTESTED too, so an unimplemented row is
|
|
122
|
+
arithmetic rather than silence.
|
|
123
|
+
- **SKIPPED(reason)** — the row is unreachable in this run by construction (a
|
|
124
|
+
`git:` install with no ref given, for instance). Reachability is decided in
|
|
125
|
+
planning, not discovered mid-run.
|
|
126
|
+
|
|
127
|
+
**BLOCKED is about the HOST, not the candidate.** The runner probes
|
|
128
|
+
`pi --mode rpc` **before anything is installed**; only a pi that cannot start a
|
|
129
|
+
bare session makes the run BLOCKED, because then nothing about the candidate
|
|
130
|
+
was measured. A candidate that will not pack, will not install, or stops a
|
|
131
|
+
working pi from booting is a **result** — DO-NOT-SHIP — not an untestable
|
|
132
|
+
state. A blocked run is not a failed run and must never be reported as one.
|
|
133
|
+
|
|
134
|
+
**A run that witnessed nothing is INCONCLUSIVE, never ship-with-caveats.** If pi
|
|
135
|
+
booted and no row reached PASS, "no row disagreed" is not evidence; the run gets
|
|
136
|
+
no ship verdict either.
|
|
137
|
+
|
|
138
|
+
Ship line, from the outcomes:
|
|
139
|
+
|
|
140
|
+
| condition | verdict | exit | rows |
|
|
141
|
+
| --- | --- | --- | --- |
|
|
142
|
+
| pi did not boot with NO candidate installed | BLOCKED — no verdict | 3 | 0 |
|
|
143
|
+
| pi booted, the candidate would not install or activate | do not ship, cause named on the verdict | 1 | 0 |
|
|
144
|
+
| any row FAILED | do not ship | 1 | N |
|
|
145
|
+
| pi booted but zero rows PASSED | INCONCLUSIVE — no verdict | 3 | N |
|
|
146
|
+
| any UNTESTED or SKIPPED, at least one PASS | ship with caveats, each named | 2 | N |
|
|
147
|
+
| all PASS | ship | 0 | N |
|
|
148
|
+
|
|
149
|
+
A candidate that never activated leaves **every row UNTESTED, none FAILED, and
|
|
150
|
+
`rows` at 0** — no probe ran, so nothing was witnessed and nothing can honestly
|
|
151
|
+
be called a failure of that row. The activation failure is the verdict's own
|
|
152
|
+
cause. (An earlier revision copied it onto all eleven rows as FAILs and wrote an
|
|
153
|
+
empty evidence dir — a verdict with no witness, against the first hard rule.)
|
|
154
|
+
|
|
155
|
+
**A row is PASS only if its witness has something in it.** A probe that reports
|
|
156
|
+
success and produces no artifact — or an EMPTY one — is recorded UNTESTED, not
|
|
157
|
+
PASS, and the report's excerpt column carries the downgrade reason rather than
|
|
158
|
+
the pass line. The empty case is the reachable one: every probe attaches a
|
|
159
|
+
witness object on its pass path, but `install-selftest` passes on "exit 0 with
|
|
160
|
+
no `[FAIL]` line", which a packaged selftest that printed nothing satisfies
|
|
161
|
+
vacuously, and its witness is that same empty stdout. The check is on CONTENT,
|
|
162
|
+
not on the presence of a file.
|
|
163
|
+
|
|
164
|
+
A usage or self-check error (bad option, unparseable matrix, arithmetic
|
|
165
|
+
mismatch) exits **4**. **Exit 2 is the EXPECTED verdict for a working-tree run**:
|
|
166
|
+
`git-install-loads` is SKIPPED without `--git-ref`. A CI lane should treat 2 as
|
|
167
|
+
a warning and 1/3/4 as failures.
|
|
168
|
+
|
|
169
|
+
## Deliberately out of scope
|
|
170
|
+
|
|
171
|
+
- **Anything needing a model turn.** Every row above is model-free by
|
|
172
|
+
construction; `get_commands` and the MCP tool calls never reach a provider. A
|
|
173
|
+
row that needs a real LLM turn cannot be a release gate on an unfunded key,
|
|
174
|
+
and a stubbed turn would be a double that mirrors our own assumption
|
|
175
|
+
(AGENTS.md, external contracts).
|
|
176
|
+
- **The `concurrent_session_bind` guard.** Observing it needs a second in-process
|
|
177
|
+
`createAgentSession()`, which needs model config. `docs/subagent-compat.md`
|
|
178
|
+
carries the same TODO; duplicating it here would add a row that can only ever
|
|
179
|
+
be UNTESTED.
|
|
180
|
+
- **Per-language tool and LSP coverage.** `scripts/smoke-tools.mjs` sweeps the
|
|
181
|
+
whole registry nightly. This matrix asserts the packaged path answers at all,
|
|
182
|
+
not that every server answers well.
|
|
@@ -17,7 +17,7 @@ every run.
|
|
|
17
17
|
|
|
18
18
|
| # | Contract | Depended on by | Third-party file (as of the versions below) | Verified against |
|
|
19
19
|
|---|----------|-----------------|-------------------------------------------------|-------------------|
|
|
20
|
-
| 1 | `PI_SUBAGENT_CHILD` is set to the literal string `"1"`
|
|
20
|
+
| 1 | `PI_SUBAGENT_CHILD` is set to the literal string `"1"` on every process that hosts a child session. | `clients/subagent-mode.ts` (`isSubagentSession()`, `getSubagentIdentity()`) | `pi-subagents@0.34.0` — co-located in `src/runs/shared/pi-args.ts` (`SUBAGENT_CHILD_ENV` const + the `env[SUBAGENT_CHILD_ENV] = "1"` assignment); as of `pi-subagents@0.66.0` the const moved to `src/runs/shared/child-runtime-config.ts` and the assignment to `src/runs/background/subagent-runner.ts` (#2581) — `compat-contract-locator.mjs`'s `locateContractSources` tries both layouts and concatenates whichever resolves. | `checkNicobailonChildEnv` |
|
|
21
21
|
| 1b | avtc-pi-subagent sets `PI_SUBAGENT_CHILD_AGENT` + `PI_SUBAGENT_PARENT_PID` (never `PI_SUBAGENT_CHILD`) on the per-spawn subagent env; `isSubagentSession()` treats the PAIR (both non-empty) as an additional subagent signal (#507). | `clients/subagent-mode.ts` (`isSubagentSession()`, `getSubagentIdentity()`) | `avtc-pi-subagent@1.0.3` — `src/process-runner.ts` (`subagentEnv.PI_SUBAGENT_CHILD_AGENT = agent.name` + `subagentEnv.PI_SUBAGENT_PARENT_PID = String(process.pid)`) | `checkAvtcChildEnv` |
|
|
22
22
|
| 2a | The pi SDK's extension loader keeps a **process-global** cache (`extensionCache = new Map()`). This is what makes an in-process `bindExtensions()` reuse pi-lens's own module-scope singletons instead of a fresh isolated instance. | `clients/session-lifecycle.ts` (the whole premise of the concurrent-session guard) | `@earendil-works/pi-coding-agent@0.80.6` — `dist/core/extensions/loader.js` | `checkSdkExtensionCache` |
|
|
23
23
|
| 2b | `AgentSession.bindExtensions()` **unconditionally** emits a `session_start`-typed event (`this._extensionRunner.emit(this._sessionStartEvent)`). | Same as 2a — this is why an in-process subagent bind re-triggers pi-lens's `session_start` handler at all. | `@earendil-works/pi-coding-agent@0.80.6` — `dist/core/agent-session.js` (`bindExtensions()`, ~line 1717) | `checkSdkBindExtensionsEmitsSessionStart` |
|
|
@@ -30,7 +30,24 @@ unit-tested regex matchers against RESILIENT semantic shapes (never a line
|
|
|
30
30
|
number — those drift on every third-party release). `scripts/compat-contracts.mjs`
|
|
31
31
|
is the orchestration script: it `npm install`s the four packages (SDK,
|
|
32
32
|
`pi-subagents`, `avtc-pi-subagent`, `@tintinweb/pi-subagents`) into a scratch
|
|
33
|
-
directory,
|
|
33
|
+
directory, resolves each contract's source file(s) independently (see
|
|
34
|
+
"Layer A" below) and runs every check.
|
|
35
|
+
|
|
36
|
+
**Contract 1's identity vars were removed upstream, not relocated (#2581).**
|
|
37
|
+
The doc used to also pin `PI_SUBAGENT_RUN_ID` / `PI_SUBAGENT_CHILD_AGENT` as
|
|
38
|
+
part of contract 1 — nicobailon/pi-subagents set them alongside
|
|
39
|
+
`PI_SUBAGENT_CHILD=1` for best-effort child identity. `pi-subagents@0.65.0`'s
|
|
40
|
+
rewrite to run subagents as native, in-process `AgentSession`s (instead of
|
|
41
|
+
spawning a separate `pi` CLI process per child) deleted both vars from the
|
|
42
|
+
package entirely — grep-verified absent from the whole 0.66.0 source tree;
|
|
43
|
+
child identity now travels through an in-process `ChildRuntimeConfig` object
|
|
44
|
+
that never touches `process.env`. This is real, permanent upstream drift, but
|
|
45
|
+
it needed no pi-lens code change: `getSubagentIdentity()` was already
|
|
46
|
+
documented and tested as best-effort, returning `runId`/`agentName: undefined`
|
|
47
|
+
when the vars are absent (`tests/clients/subagent-mode.test.ts`) — exactly the
|
|
48
|
+
degraded state this vocabulary is now always in. `checkNicobailonChildEnv`
|
|
49
|
+
no longer requires them; only the `PI_SUBAGENT_CHILD='1'` flag pi-lens's
|
|
50
|
+
light-mode detection actually depends on behaviorally still gates the check.
|
|
34
51
|
|
|
35
52
|
## The three env levers
|
|
36
53
|
|
|
@@ -45,10 +62,46 @@ directory, reads the specific files above, and runs every check.
|
|
|
45
62
|
### Layer A — pinned-contract verification (`scripts/compat-contracts.mjs`)
|
|
46
63
|
|
|
47
64
|
No `pi` process, no LLM turn. Installs the real packages (table above) and
|
|
48
|
-
mechanically re-checks all
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
65
|
+
mechanically re-checks all seven contracts against the installed source.
|
|
66
|
+
|
|
67
|
+
Each contract resolves independently to one of **three outcomes**, printed
|
|
68
|
+
per-contract and rolled up into a run-level `outcome` (also exposed as a
|
|
69
|
+
GITHUB_OUTPUT for the workflow's alert step, distinct from the GH step's own
|
|
70
|
+
success/failure) and exit code:
|
|
71
|
+
|
|
72
|
+
- **verified** (exit 0 when every contract is this) — the contract's source
|
|
73
|
+
file(s) were found and their content matches the pinned shape.
|
|
74
|
+
- **drift** (exit 1) — the source file(s) were found, but the content no
|
|
75
|
+
longer matches. This is an actual upstream behavioral change worth
|
|
76
|
+
investigating (see "What to do when the nightly alerts" below).
|
|
77
|
+
- **infra** (exit 2, when nothing drifted but at least one contract hit
|
|
78
|
+
this) — the contract's source file could not be located at ANY of its
|
|
79
|
+
known candidate paths (each `CONTRACTS` entry's `parts` field in
|
|
80
|
+
`scripts/lib/compat-contracts.mjs`, resolved via
|
|
81
|
+
`compat-contract-locator.mjs` and `compat-contract-resolution.mjs`), or
|
|
82
|
+
the `npm install` of the four packages itself failed. This means Layer A
|
|
83
|
+
has NOT actually re-checked that contract's content at all — it is
|
|
84
|
+
distinct from drift and must never be reported as one. #2581: before this
|
|
85
|
+
three-way split, a single relocated file (`pi-subagents@0.65.0` moving
|
|
86
|
+
`src/runs/shared/pi-args.ts`) threw inside one shared try/catch, aborted
|
|
87
|
+
the whole run, and got reported — both in the run log and the tracking
|
|
88
|
+
issue's body — as generic "failure" alongside the other six contracts that
|
|
89
|
+
were never actually re-checked that run either. A contract's own outcome
|
|
90
|
+
only becomes "infra" when ITS candidate paths are all missing; every other
|
|
91
|
+
contract is still resolved and checked independently in the same run.
|
|
92
|
+
|
|
93
|
+
Candidate paths are walked NEWEST-observed-layout first, not oldest (#2680
|
|
94
|
+
F1) — a stale leftover file at an old path (left behind by a partial
|
|
95
|
+
publish, or an npm install that added files without pruning ones the
|
|
96
|
+
package's current `files` list no longer references) must never outrank the
|
|
97
|
+
package's actual current layout. When a candidate path list needs a NEW
|
|
98
|
+
entry (the package relocated the file again), APPEND it to that contract's
|
|
99
|
+
`parts` in the `CONTRACTS` list (`scripts/lib/compat-contracts.mjs`) —
|
|
100
|
+
oldest-observed-layout first in how the list reads, rather than replacing
|
|
101
|
+
the old entry — the locator resolves the newest EXISTING one regardless of
|
|
102
|
+
authored order, so older installs stay covered too. `parts` and `package`
|
|
103
|
+
live directly on each `CONTRACTS` entry, not a second table keyed by a
|
|
104
|
+
string id (#2680 F2) — there is nowhere else to update.
|
|
52
105
|
|
|
53
106
|
### Layer B — real-pi behavioral smoke (`scripts/compat-smoke-behavioral.mjs`)
|
|
54
107
|
|
|
@@ -71,7 +124,7 @@ first session.
|
|
|
71
124
|
Assertions:
|
|
72
125
|
|
|
73
126
|
1. **Subagent light mode engages** — with `PI_SUBAGENT_CHILD=1` set,
|
|
74
|
-
`subagent_light_mode` is logged to
|
|
127
|
+
`subagent_light_mode` is logged to `$PI_LENS_HOME/latency.log` (a `type:
|
|
75
128
|
"phase"` entry) and none of the seven heavyweight-scan phases
|
|
76
129
|
(`knip`/`jscpd`/`madge`/`dead-code`/`govulncheck`/`gitleaks`/`trivy`) are
|
|
77
130
|
logged for that run.
|
|
@@ -99,22 +152,32 @@ Assertions:
|
|
|
99
152
|
`PI_SUBAGENT_PARENT_PID`), no `subagent_light_mode` phase is logged.
|
|
100
153
|
`subagent-mode.ts`'s doc comment requires the PAIR — a lone var set by
|
|
101
154
|
some unrelated tool must not trigger light mode.
|
|
102
|
-
6. **`concurrent_session_bind` (#473)
|
|
155
|
+
6. **`concurrent_session_bind` (#473) and its `concurrent_session_bind_rollup`
|
|
156
|
+
session-end summary (#2249) — NOT asserted, documented TODO.**
|
|
103
157
|
The guard is fully wired on master (PR #477): `index.ts`'s `session_start`
|
|
104
158
|
handler calls `decideSessionStart()` and logs a `concurrent_session_bind`
|
|
105
159
|
latency phase for a concurrent-secondary bind — so the phase exists to
|
|
106
|
-
observe.
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
160
|
+
observe. `clients/session-start-observability.ts` also keeps a bounded,
|
|
161
|
+
process-singleton-backed tally of declined binds by classification
|
|
162
|
+
(`concurrent-secondary` / `secondary-root`), which `index.ts`'s
|
|
163
|
+
`session_shutdown` handler logs as one `concurrent_session_bind_rollup`
|
|
164
|
+
row (primary sessions only) and clears — same primary-only placement as
|
|
165
|
+
`session_end_bus_rollup`/`path_attribution_verified_rollup`. The blocker is
|
|
166
|
+
DRIVING either keylessly: reproducing tintinweb's in-process model for real
|
|
167
|
+
(mirroring `agent-runner.ts`'s `createAgentSession()` +
|
|
168
|
+
`DefaultResourceLoader` + `bindExtensions()` sequence) requires full
|
|
169
|
+
session construction, which in turn needs model/provider config — not
|
|
170
|
+
cheaply stubbable without a real model key, and #476 explicitly asks not
|
|
171
|
+
to ship something flaky here. The unit + behavioral coverage in
|
|
172
|
+
`tests/clients/session-lifecycle.test.ts` guards the classifier and the
|
|
173
|
+
no-reset contract, and `tests/clients/session-start-observability.test.ts`
|
|
174
|
+
plus `tests/index-integration.test.ts` guard the rollup's counting,
|
|
175
|
+
process-singleton survival, and primary-only reset/emit wiring, all
|
|
176
|
+
in-repo; what Layer B cannot yet add is the end-to-end SDK-driven variant.
|
|
177
|
+
**Revisit if the pi SDK grows a model-free session constructor or stub
|
|
178
|
+
provider** — at that point add a Layer B assertion analogous to 1-3
|
|
179
|
+
checking the `concurrent_session_bind`/`concurrent_session_bind_rollup`
|
|
180
|
+
phases and the absence of a second LSP fleet teardown.
|
|
118
181
|
|
|
119
182
|
## What to do when the nightly alerts
|
|
120
183
|
|
|
@@ -125,18 +188,35 @@ third-party contract drift detected"** — search for it by title before
|
|
|
125
188
|
assuming a NEW investigation is needed; the workflow already
|
|
126
189
|
create-or-updates it, never duplicates.
|
|
127
190
|
|
|
128
|
-
1. Read the linked run log —
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
191
|
+
1. Read the linked run log — the alert issue body now says which of Layer
|
|
192
|
+
A's three outcomes fired (**verified** / **drift** / **infra**, #2581 —
|
|
193
|
+
never just a generic "failure"); Layer A/B each print a `[PASS]`/`[FAIL]`
|
|
194
|
+
or `[INFRA]` line per check with a one-line detail on exactly what didn't
|
|
195
|
+
match or couldn't be found.
|
|
196
|
+
2. **If Layer A says infra**: the run log's `INFRA` line names every
|
|
197
|
+
candidate path tried for that contract. Read the installed package at the
|
|
198
|
+
printed version and find where the file actually lives now, then append
|
|
199
|
+
it to that contract's `parts` in the `CONTRACTS` list
|
|
200
|
+
(`scripts/lib/compat-contracts.mjs`) — don't replace the old candidate,
|
|
201
|
+
the locator resolves whichever existing one is newest regardless of
|
|
202
|
+
authored order (#2680 F1), so older installs stay covered too. This is a
|
|
203
|
+
relocation, not a confirmed content change; only move to step 3 once the
|
|
204
|
+
check actually runs against the relocated file.
|
|
205
|
+
3. **If Layer A says drift**: find the failed check's row in the
|
|
206
|
+
pinned-contracts table above and read the current third-party source at
|
|
207
|
+
the referenced file — the semantic shape genuinely changed upstream (a
|
|
208
|
+
renamed env var, a moved `emit()` call, a reworded error message, ...).
|
|
209
|
+
Update the corresponding matcher in `scripts/lib/compat-contracts.mjs`
|
|
135
210
|
(and its test in `tests/scripts/compat-contracts.test.ts`) to match the
|
|
136
|
-
new shape, update the pinned-contracts table's version/
|
|
137
|
-
|
|
211
|
+
new shape, update the pinned-contracts table's version/reference above,
|
|
212
|
+
and fix whichever pi-lens module (`subagent-mode.ts` /
|
|
138
213
|
`session-lifecycle.ts` / `instance-reaper.ts`) actually depended on the
|
|
139
|
-
old shape if the drift broke real behavior — not just the check.
|
|
214
|
+
old shape if the drift broke real behavior — not just the check. If
|
|
215
|
+
pi-lens's own dependent code already tolerates the drift gracefully (as
|
|
216
|
+
with contract 1's now-removed identity vars, #2581), relaxing the check
|
|
217
|
+
to stop requiring what upstream removed IS the fix — don't keep a check
|
|
218
|
+
that can only ever report drift forever for something pi-lens never
|
|
219
|
+
needed to work.
|
|
140
220
|
4. A Layer B failure (an assertion, not an infra error) means real pi-lens
|
|
141
221
|
behavior regressed under a real `pi` — treat it like any other bug: write
|
|
142
222
|
a fixture-level test if the gap wasn't otherwise covered, then fix.
|
|
@@ -135,10 +135,10 @@ Rule source: `rules/tree-sitter-queries/<language>/`.
|
|
|
135
135
|
| `open-invalid-mode` | error | reliability | open() called with invalid mode '{{MODE}}' |
|
|
136
136
|
| `python-assert-production` | warning | correctness | assert statement stripped by Python -O flag — use explicit checks with exceptions in production code |
|
|
137
137
|
| `python-command-injection` | error | security | Potential command injection sink — avoid shell execution with dynamic input |
|
|
138
|
-
| `python-cross-language-method` | warning | correctness | '{METHOD}' is not a Python method — likely a
|
|
138
|
+
| `python-cross-language-method` | warning | correctness | '{{METHOD}}' is not a Python method — likely a cross-language idiom leaking in |
|
|
139
139
|
| `python-debugger` | warning | debugging | Debugger call '{{FUNC}}' — remove before committing |
|
|
140
140
|
| `python-empty-except` | warning | reliability | Except block only contains 'pass' — handle or re-raise the exception |
|
|
141
|
-
| `python-hallucinated-import` | warning | correctness | Hallucinated import — '{NAME}' does not exist in '{MODULE}' |
|
|
141
|
+
| `python-hallucinated-import` | warning | correctness | Hallucinated import — '{{NAME}}' does not exist in '{{MODULE}}' |
|
|
142
142
|
| `python-hardcoded-secrets` | warning | security | Hardcoded {{VARNAME}} — use environment variables or a secrets manager |
|
|
143
143
|
| `python-insecure-deserialization` | error | security | Potential insecure deserialization sink — avoid unsafe loaders |
|
|
144
144
|
| `python-insecure-random` | warning | security | Insecure randomness source detected — use secrets or os.urandom for security-sensitive values |
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "pi-lens",
|
|
3
|
-
"version": "4.1.
|
|
3
|
+
"version": "4.1.4",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "Real-time code feedback for pi — LSP, linters, formatters, type-checking, structural analysis & booboo",
|
|
6
6
|
"repository": {
|
|
@@ -15,10 +15,13 @@
|
|
|
15
15
|
},
|
|
16
16
|
"scripts": {
|
|
17
17
|
"build": "tsc --project tsconfig.build.json",
|
|
18
|
-
"build:dist": "node -e \"require('fs').rmSync('dist',{recursive:true,force:true})\" &&
|
|
18
|
+
"build:dist": "node -e \"require('fs').rmSync('dist',{recursive:true,force:true})\" && node scripts/build-dist-tsc.mjs tsconfig.dist.json && npm run bundle:dist",
|
|
19
19
|
"bundle:dist": "node scripts/bundle-dist.mjs",
|
|
20
20
|
"prepare": "npm run build:dist && node scripts/download-grammars.js --core --dest grammars && node scripts/setup-git-hooks.mjs && node scripts/warm-loader-cache.mjs",
|
|
21
|
-
"
|
|
21
|
+
"prepack": "node scripts/strip-dev-deps-for-pack.mjs --strip",
|
|
22
|
+
"postpack": "node scripts/strip-dev-deps-for-pack.mjs --restore",
|
|
23
|
+
"lint": "tsc --project tsconfig.json && npm run lint:js",
|
|
24
|
+
"lint:js": "oxlint --deny-warnings --ignore-pattern \"tests/**/*.ts\" --ignore-pattern \"tests/**/*.tsx\" --ignore-pattern \"**/*.d.mts\" --ignore-pattern \"tests/fixtures/autofix-smoke/**\" --ignore-pattern \"tests/fixtures/format-smoke/**\" --ignore-pattern \"tests/fixtures/tool-smoke/**\" --ignore-pattern \"tests/fixtures/call-graph/javascript/**\" --ignore-pattern \"tests/fixtures/function-facts/javascript-parameter.js\" .",
|
|
22
25
|
"depcruise:check": "depcruise --validate --config .dependency-cruiser.cjs --ignore-known .dependency-cruiser-known-violations.json --output-type err index.ts \"clients/**/*.ts\"",
|
|
23
26
|
"fmt": "oxfmt",
|
|
24
27
|
"fmt:check": "oxfmt --check",
|
|
@@ -26,7 +29,9 @@
|
|
|
26
29
|
"test": "node scripts/with-test-lock.mjs -- vitest run",
|
|
27
30
|
"test:unit": "node scripts/with-test-lock.mjs -- vitest run",
|
|
28
31
|
"test:integration": "node scripts/with-test-lock.mjs -- vitest run tests/index-integration.test.ts tests/clients/lsp/integration.test.ts",
|
|
32
|
+
"test:targeted": "node scripts/with-test-lock.mjs --shared -- vitest run",
|
|
29
33
|
"test:watch": "vitest",
|
|
34
|
+
"hygiene": "node scripts/prune-agent-worktrees.mjs",
|
|
30
35
|
"check": "node scripts/check-extensions.mjs",
|
|
31
36
|
"selftest:install": "node scripts/install-selftest.mjs",
|
|
32
37
|
"check:lockfile": "node scripts/check-lockfile-sync.mjs",
|
|
@@ -72,6 +77,9 @@
|
|
|
72
77
|
],
|
|
73
78
|
"author": "Apostolos Mantzaris",
|
|
74
79
|
"license": "MIT",
|
|
80
|
+
"engines": {
|
|
81
|
+
"node": ">=22.19.0"
|
|
82
|
+
},
|
|
75
83
|
"files": [
|
|
76
84
|
"dist/",
|
|
77
85
|
"docs/",
|
|
@@ -85,6 +93,7 @@
|
|
|
85
93
|
"scripts/analyze-pi-lens-logs.mjs",
|
|
86
94
|
"scripts/install-selftest.mjs",
|
|
87
95
|
"scripts/lib/host-provided-deps.mjs",
|
|
96
|
+
"scripts/lib/skills-predicate.mjs",
|
|
88
97
|
"scripts/lib/warm-loader-cache.mjs",
|
|
89
98
|
"scripts/warm-loader-cache.mjs",
|
|
90
99
|
"scripts/rpc-load-check.mjs",
|
|
@@ -103,7 +112,7 @@
|
|
|
103
112
|
},
|
|
104
113
|
"peerDependencies": {
|
|
105
114
|
"@earendil-works/pi-coding-agent": "*",
|
|
106
|
-
"@earendil-works/pi-tui": "^0.84.1",
|
|
115
|
+
"@earendil-works/pi-tui": "^0.84.1 || ^0.85.0",
|
|
107
116
|
"typebox": "^1.0.0"
|
|
108
117
|
},
|
|
109
118
|
"peerDependenciesMeta": {
|
|
@@ -121,29 +130,12 @@
|
|
|
121
130
|
"jiti": "^2.7.0",
|
|
122
131
|
"web-tree-sitter": "0.25.10"
|
|
123
132
|
},
|
|
124
|
-
"devDependencies": {
|
|
125
|
-
"@biomejs/biome": "^2.4.10",
|
|
126
|
-
"@earendil-works/pi-coding-agent": "^0.84.1",
|
|
127
|
-
"@earendil-works/pi-tui": "^0.84.1",
|
|
128
|
-
"@types/node": "^26.0.0",
|
|
129
|
-
"@types/pidusage": "^2.0.5",
|
|
130
|
-
"@vitest/coverage-v8": "^4.1.5",
|
|
131
|
-
"dependency-cruiser": "^18.2.0",
|
|
132
|
-
"husky": "^9.1.7",
|
|
133
|
-
"json5": "^2.2.3",
|
|
134
|
-
"oxfmt": "0.64.0",
|
|
135
|
-
"oxlint": "1.79.0",
|
|
136
|
-
"typebox": "^1.0.0",
|
|
137
|
-
"typescript": "^7.0.2",
|
|
138
|
-
"typescript-language-server": "^6.0.0",
|
|
139
|
-
"vitest": "^4.1.1"
|
|
140
|
-
},
|
|
141
133
|
"pi": {
|
|
142
134
|
"extensions": [
|
|
143
135
|
"./dist/index.js"
|
|
144
136
|
],
|
|
145
137
|
"skills": [
|
|
146
|
-
"
|
|
138
|
+
"./skills"
|
|
147
139
|
]
|
|
148
140
|
},
|
|
149
141
|
"knip": {
|
|
@@ -159,7 +151,7 @@
|
|
|
159
151
|
]
|
|
160
152
|
},
|
|
161
153
|
"allowScripts": {
|
|
162
|
-
"@ast-grep/cli@0.45.
|
|
154
|
+
"@ast-grep/cli@0.45.2": true,
|
|
163
155
|
"@google/genai@1.52.0": true,
|
|
164
156
|
"protobufjs@7.6.5": true
|
|
165
157
|
}
|
package/node_modules/pi-lens/rules/tree-sitter-queries/python/python-cross-language-method.yml
CHANGED
|
@@ -9,7 +9,7 @@ defect_class: hallucination
|
|
|
9
9
|
inline_tier: warning
|
|
10
10
|
language: python
|
|
11
11
|
|
|
12
|
-
message: "'{METHOD}' is not a Python method — likely a
|
|
12
|
+
message: "'{{METHOD}}' is not a Python method — likely a cross-language idiom leaking in"
|
|
13
13
|
|
|
14
14
|
description: |
|
|
15
15
|
A method name from another language is being called on a Python object.
|
|
@@ -27,7 +27,7 @@ query: |
|
|
|
27
27
|
function: (attribute
|
|
28
28
|
object: (_) @OBJ
|
|
29
29
|
attribute: (identifier) @METHOD)
|
|
30
|
-
(#match? @METHOD "^(push|forEach|indexOf|charAt|substring|hasOwnProperty|unshift|flatMap|padStart|padEnd|trimStart|trimEnd|equals|isEmpty|println|printf|getClass|hashCode|toCharArray|getBytes|compareTo|equalsIgnoreCase|startsWith|endsWith|each|collect|
|
|
30
|
+
(#match? @METHOD "^(push|forEach|indexOf|charAt|substring|hasOwnProperty|unshift|flatMap|padStart|padEnd|trimStart|trimEnd|equals|isEmpty|println|printf|getClass|hashCode|toCharArray|getBytes|compareTo|equalsIgnoreCase|startsWith|endsWith|each|collect|reject|detect|inject|chomp|chop|gsub|upcase|downcase|present|blank|Add|Contains|ToLower|ToUpper|Trim|Substring|WriteLine|ReadLine|TryParse|forEach|includes|assign|freeze|splice|unshift|shift|flatMap)$"))
|
|
31
31
|
|
|
32
32
|
metavars:
|
|
33
33
|
- OBJ
|
|
@@ -35,7 +35,7 @@ metavars:
|
|
|
35
35
|
|
|
36
36
|
post_filter: match_captures
|
|
37
37
|
post_filter_params:
|
|
38
|
-
METHOD: "^(push|forEach|indexOf|charAt|substring|hasOwnProperty|unshift|flatMap|padStart|padEnd|trimStart|trimEnd|equals|isEmpty|println|printf|getClass|hashCode|toCharArray|getBytes|compareTo|equalsIgnoreCase|startsWith|endsWith|each|collect|
|
|
38
|
+
METHOD: "^(push|forEach|indexOf|charAt|substring|hasOwnProperty|unshift|flatMap|padStart|padEnd|trimStart|trimEnd|equals|isEmpty|println|printf|getClass|hashCode|toCharArray|getBytes|compareTo|equalsIgnoreCase|startsWith|endsWith|each|collect|reject|detect|inject|chomp|chop|gsub|upcase|downcase|present|blank|Add|Contains|ToLower|ToUpper|Trim|Substring|WriteLine|ReadLine|TryParse|forEach|includes|assign|freeze|splice|unshift|shift|flatMap)$"
|
|
39
39
|
|
|
40
40
|
has_fix: false
|
|
41
41
|
|
package/node_modules/pi-lens/rules/tree-sitter-queries/python/python-hallucinated-import.yml
CHANGED
|
@@ -9,7 +9,7 @@ defect_class: hallucination
|
|
|
9
9
|
inline_tier: blocking
|
|
10
10
|
language: python
|
|
11
11
|
|
|
12
|
-
message: "Hallucinated import — '{NAME}' does not exist in '{MODULE}'"
|
|
12
|
+
message: "Hallucinated import — '{{NAME}}' does not exist in '{{MODULE}}'"
|
|
13
13
|
|
|
14
14
|
description: |
|
|
15
15
|
This import is from the wrong package. A name from one framework is being
|
|
@@ -32,7 +32,7 @@ metavars:
|
|
|
32
32
|
|
|
33
33
|
post_filter: match_captures
|
|
34
34
|
post_filter_params:
|
|
35
|
-
MODULE: "^(requests|flask|django|typing|collections|asyncio|json|unittest|pytest|urllib
|
|
35
|
+
MODULE: "^(requests|flask|django|typing|collections|asyncio|json|unittest|pytest|urllib)$"
|
|
36
36
|
NAME: "^(JSONResponse|HTMLResponse|RedirectResponse|StreamingResponse|Depends|Query|Path|Body|Header|Cookie|Form|File|UploadFile|FastAPI|APIRouter|HTTPException|BackgroundTasks|dataclass|fields|BaseModel|Field|validator|aiohttp|parse|stringify|fixture|TestCase|get|post|put|delete|Model|Session|Column|Integer|String)$"
|
|
37
37
|
|
|
38
38
|
has_fix: false
|
|
@@ -18,8 +18,18 @@ description: |
|
|
|
18
18
|
|
|
19
19
|
Suppressed:
|
|
20
20
|
- cursor.execute(query, params) — parameterized query (safe)
|
|
21
|
-
- session.execute(
|
|
22
|
-
-
|
|
21
|
+
- session.execute(...) — receiver conventionally named for a SQLAlchemy session
|
|
22
|
+
- x.execute(select(...)) — statement builder in argument position (safe by
|
|
23
|
+
construction)
|
|
24
|
+
- db.query(...) / db.execute(stmt) where `db: Session` and `Session` is proven
|
|
25
|
+
from a same-file `sqlalchemy.orm` / `sqlalchemy.ext.asyncio` import, and
|
|
26
|
+
`stmt` is bound exactly once to a builder call
|
|
27
|
+
- cursor.execute(sql.SQL("...").format(sql.Identifier(...))) where `sql` is
|
|
28
|
+
an unshadowed same-file psycopg or psycopg2 import and every format argument
|
|
29
|
+
is an Identifier
|
|
30
|
+
|
|
31
|
+
Other raw, dynamic, or ambiguous SQL remains diagnostic so this rule fails
|
|
32
|
+
closed when it cannot prove the safe API provenance.
|
|
23
33
|
|
|
24
34
|
✅ FIX: use placeholders and parameter binding instead of string composition.
|
|
25
35
|
|