@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
|
@@ -63,4 +63,35 @@ export class RustClient {
|
|
|
63
63
|
isRustFile(filePath) {
|
|
64
64
|
return path.extname(filePath).toLowerCase() === ".rs";
|
|
65
65
|
}
|
|
66
|
+
/** Forget the memoized cargo path and latched availability verdict — #2455. */
|
|
67
|
+
resetAvailability() {
|
|
68
|
+
this.availability.reset();
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
/**
|
|
72
|
+
* The one `RustClient` this process owns (#2455 fix round 4, F2).
|
|
73
|
+
*
|
|
74
|
+
* Same shape as `go-client.ts`'s `goClient`, and the same round-2 defect: the
|
|
75
|
+
* runner (`dispatch/runners/rust-clippy.ts`) and `bootstrap.ts` each built
|
|
76
|
+
* their own instance, so `resetRustAvailability` re-armed one latch while
|
|
77
|
+
* `handleSessionStart`'s "Active tools" line read the other's never-expiring
|
|
78
|
+
* probe-class "missing" verdict. One instance, in the module that owns the
|
|
79
|
+
* class; `tests/clients/toolchain-client-singleton.test.ts` holds the line.
|
|
80
|
+
*/
|
|
81
|
+
export const rustClient = new RustClient();
|
|
82
|
+
/**
|
|
83
|
+
* Forget `rustClient`'s memoized cargo path and latched availability verdict —
|
|
84
|
+
* #2455. Same #1496/#1535 shape as `resetZizmorTokenAvailability`; wired into
|
|
85
|
+
* `handleSessionStart` beside it (`clients/runtime-session.ts`) so a Rust
|
|
86
|
+
* toolchain installed mid-process is observed by the next session instead of
|
|
87
|
+
* staying "missing" for the rest of the process's life.
|
|
88
|
+
*
|
|
89
|
+
* This module — not `rust-clippy.ts` — because the reset must sit beside the
|
|
90
|
+
* single instance it clears (#2455 fix round 4, F2). `rust-clippy.ts`'s
|
|
91
|
+
* `clippyAvailabilityByCargo` is a separate, already-covered latch: it rides
|
|
92
|
+
* `createCwdCachedProbe`'s shared `availabilityGeneration` counter (see
|
|
93
|
+
* `runner-helpers.ts`'s `resetDispatchAvailabilityState`), not this reset.
|
|
94
|
+
*/
|
|
95
|
+
export function resetRustAvailability() {
|
|
96
|
+
rustClient.resetAvailability();
|
|
66
97
|
}
|
|
@@ -16,6 +16,7 @@
|
|
|
16
16
|
import { spawn, spawnSync, } from "node:child_process";
|
|
17
17
|
import * as fs from "node:fs";
|
|
18
18
|
import * as path from "node:path";
|
|
19
|
+
import { BoundedFifoMap } from "./bounded-cache.js";
|
|
19
20
|
import { logLatency } from "./latency-logger.js";
|
|
20
21
|
import { recordDegradation } from "./degradation-ledger.js";
|
|
21
22
|
import { logExtension } from "./extension-log.js";
|
|
@@ -570,23 +571,21 @@ function resolveWindowsPathEntry(entry, effectiveCwd, env) {
|
|
|
570
571
|
* cache is also count-bounded with oldest-entry eviction because a long-lived
|
|
571
572
|
* process can encounter unbounded cwd/environment combinations.
|
|
572
573
|
*/
|
|
573
|
-
const WINDOWS_COMMAND_CACHE_MAX_ENTRIES = 256;
|
|
574
|
+
export const WINDOWS_COMMAND_CACHE_MAX_ENTRIES = 256;
|
|
574
575
|
const WINDOWS_COMMAND_NEGATIVE_CACHE_TTL_MS = 1000;
|
|
575
|
-
const windowsCommandCache = new
|
|
576
|
+
const windowsCommandCache = new BoundedFifoMap(WINDOWS_COMMAND_CACHE_MAX_ENTRIES);
|
|
576
577
|
/** Reset after session replacement or a successful managed install. */
|
|
577
578
|
export function resetSafeSpawnWindowsCommandCache() {
|
|
578
579
|
windowsCommandCache.clear();
|
|
579
580
|
loggedSpawnClassifications.clear();
|
|
580
581
|
}
|
|
581
582
|
function cacheWindowsCommandResult(key, resolved) {
|
|
582
|
-
|
|
583
|
-
|
|
584
|
-
|
|
585
|
-
|
|
586
|
-
|
|
587
|
-
|
|
588
|
-
windowsCommandCache.delete(oldest);
|
|
589
|
-
}
|
|
583
|
+
// Resolution entries are session-scoped and cheap to recompute. The
|
|
584
|
+
// caller always deletes any stale entry for `key` before reaching here
|
|
585
|
+
// (see resolveWindowsCommandForEnvironment), so this can only grow the
|
|
586
|
+
// map; BoundedFifoMap evicts the oldest insertion first once the map
|
|
587
|
+
// exceeds capacity, so a long-lived process cannot retain every cwd /
|
|
588
|
+
// environment it has ever touched.
|
|
590
589
|
windowsCommandCache.set(key, { resolved, checkedAt: Date.now() });
|
|
591
590
|
}
|
|
592
591
|
function getPathExts(env) {
|
|
@@ -848,6 +847,30 @@ const EXIT_PIPE_IDLE_MAX_WAIT_MS = 2000;
|
|
|
848
847
|
* - Kills the process on timeout (preventing zombies)
|
|
849
848
|
* - Supports cancellation via AbortSignal
|
|
850
849
|
*
|
|
850
|
+
* ## Why this bound is NOT `bounded()` — the one documented exception (#2523)
|
|
851
|
+
*
|
|
852
|
+
* #2523 slice 2 folded every other "deadline AND abort signal" implementation
|
|
853
|
+
* in the tree onto `clients/deadline-utils.ts#bounded`. This one stays, and it
|
|
854
|
+
* is not a copy of the same idea:
|
|
855
|
+
*
|
|
856
|
+
* `bounded()` ABANDONS a promise — it stops waiting and lets the work run on
|
|
857
|
+
* unobserved, which is safe precisely because everything it wraps is in-process
|
|
858
|
+
* (a dynamic import, an LSP round trip, a `stat`). This function's work is a
|
|
859
|
+
* CHILD PROCESS, and abandoning one leaks it. So its timer does not settle a
|
|
860
|
+
* race at all: `timeoutId` sets `timedOut`, then runs `killTree()` — SIGTERM,
|
|
861
|
+
* an escalation timer, SIGKILL, and on Windows a `taskkill /T` of the whole
|
|
862
|
+
* tree — and the promise settles only when the child's own `close` arrives (or
|
|
863
|
+
* the escalation gives up). The result it produces carries the teardown
|
|
864
|
+
* EVIDENCE (`timeoutTeardown`, #2010): which signal killed it, whether the
|
|
865
|
+
* tree actually died, how long it took. Replacing that with `bounded()` would
|
|
866
|
+
* return `undefined` at the deadline and leave a live `vitest`/`gradle` behind
|
|
867
|
+
* — the orphan class #2504 measured as 59 concurrent spawns starving a turn.
|
|
868
|
+
*
|
|
869
|
+
* The rule the exception preserves: a bound that can CANCEL its work must
|
|
870
|
+
* cancel it. `bounded()` is for work that cannot be cancelled; this is not
|
|
871
|
+
* that. Anything wrapping THIS function still gets `bounded()` around its own
|
|
872
|
+
* await if it needs one.
|
|
873
|
+
*
|
|
851
874
|
* @example
|
|
852
875
|
* const result = await safeSpawnAsync("npm", ["test"], { timeout: 30000 });
|
|
853
876
|
* if (result.error) console.error("Failed:", result.error);
|
|
@@ -6,8 +6,14 @@
|
|
|
6
6
|
*/
|
|
7
7
|
// --- Constants ---
|
|
8
8
|
// ANSI escape codes for colors and formatting
|
|
9
|
+
// oxlint-disable-next-line no-control-regex -- ESC (\x1b) is the literal ANSI escape-sequence lead byte this pattern strips, not accidental input.
|
|
9
10
|
const ANSI_ESCAPE = /\x1b\[[0-9;]*m/g;
|
|
10
|
-
|
|
11
|
+
// Full ECMA-48 CSI grammar (parameter bytes 0-9;? , intermediate bytes
|
|
12
|
+
// space-/, final byte @-~) — matches every CSI sequence ANSI_ESCAPE does
|
|
13
|
+
// plus non-SGR ones (cursor moves, private-mode `?` sequences like
|
|
14
|
+
// `\x1b[?25l`, etc.), not just the `m`-terminated color codes.
|
|
15
|
+
// oxlint-disable-next-line no-control-regex -- ESC (\x1b) is the literal ANSI escape-sequence lead byte this pattern strips, not accidental input.
|
|
16
|
+
const ANSI_ESCAPE_EXTENDED = /\x1b\[[0-9;?]*[ -/]*[@-~]/g;
|
|
11
17
|
// Common error patterns from different tools
|
|
12
18
|
const ERROR_INDICATORS = [
|
|
13
19
|
/\berror\b/i,
|
|
@@ -54,6 +54,7 @@
|
|
|
54
54
|
* fully in scope.
|
|
55
55
|
*/
|
|
56
56
|
import { EXCLUDED_DIRS, getExcludedDirGlobs } from "./file-utils.js";
|
|
57
|
+
import { escapeRegExp } from "./string-utils.js";
|
|
57
58
|
/** Directory-name entries only — drops glob entries (e.g. `*.dSYM`) that a
|
|
58
59
|
* bare directory-name/regex exclude can't express. */
|
|
59
60
|
function literalExcludedDirNames() {
|
|
@@ -68,9 +69,6 @@ function literalExcludedDirNames() {
|
|
|
68
69
|
export function getScratchTreeGlobPatterns() {
|
|
69
70
|
return getExcludedDirGlobs();
|
|
70
71
|
}
|
|
71
|
-
function escapeRegExp(literal) {
|
|
72
|
-
return literal.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
73
|
-
}
|
|
74
72
|
/** Bare directory names, for tools (opengrep/semgrep `--exclude`) that treat a
|
|
75
73
|
* slash-free pattern as "this directory name, anywhere in the tree". */
|
|
76
74
|
export function getScratchTreeDirNames() {
|
|
@@ -71,6 +71,7 @@ export class SecurityScanClient {
|
|
|
71
71
|
logDurableAbsence(evidence, elapsedMs = 0) {
|
|
72
72
|
logAvailabilityDecision({
|
|
73
73
|
tool: this.toolName,
|
|
74
|
+
producer: "security-scan",
|
|
74
75
|
verdict: "unavailable",
|
|
75
76
|
outcome: "missing",
|
|
76
77
|
cause: "not-found",
|
|
@@ -154,6 +155,7 @@ export class SecurityScanClient {
|
|
|
154
155
|
this.log(`${this.toolName} found: ${probe.stdout.trim().split("\n")[0]}`);
|
|
155
156
|
logAvailabilityDecision({
|
|
156
157
|
tool: this.toolName,
|
|
158
|
+
producer: "security-scan",
|
|
157
159
|
verdict: "available",
|
|
158
160
|
outcome: "success",
|
|
159
161
|
cause: "ok",
|
|
@@ -185,6 +187,7 @@ export class SecurityScanClient {
|
|
|
185
187
|
: 0;
|
|
186
188
|
logAvailabilityDecision({
|
|
187
189
|
tool: this.toolName,
|
|
190
|
+
producer: "security-scan",
|
|
188
191
|
verdict: "unavailable",
|
|
189
192
|
outcome,
|
|
190
193
|
cause,
|
|
@@ -91,7 +91,7 @@ export function getActivePrimaryRoot() {
|
|
|
91
91
|
* `concurrent-secondary`: skip the destructive resets and the expensive
|
|
92
92
|
* battery, leave the registered primary's ctx/session id/root untouched. The
|
|
93
93
|
* root still gets served — `initLSPConfig` registers session roots lazily,
|
|
94
|
-
* per file (`clients/lsp/session-roots.ts
|
|
94
|
+
* per file (`clients/lsp/session-roots.ts`), not from this handler.
|
|
95
95
|
*
|
|
96
96
|
* Ordering note: the root check sits BELOW the `priorCtxActive === true`
|
|
97
97
|
* branch so a live sibling still reports the more specific
|
|
@@ -1,10 +1,42 @@
|
|
|
1
1
|
import { logLatency } from "./latency-logger.js";
|
|
2
|
+
import { getProcessSingleton } from "./process-singletons.js";
|
|
2
3
|
/**
|
|
3
4
|
* The complete observability path for a concurrent secondary. It deliberately
|
|
4
5
|
* emits one bind record only: secondary sessions skip every primary reset and
|
|
5
6
|
* hydration phase.
|
|
6
7
|
*/
|
|
8
|
+
// #2249: bounded per-session rollup of declined binds, counted at this shared
|
|
9
|
+
// seam so every decline the process's PRIMARY has seen this session —
|
|
10
|
+
// `concurrent-secondary` and `secondary-root` alike — is summarized in one row
|
|
11
|
+
// at session end instead of requiring a reader to hand-count
|
|
12
|
+
// `concurrent_session_bind` lines. Process-singleton backed (AGENTS.md catalog
|
|
13
|
+
// shape 25), NOT a module-scope `let` like the other `*_rollup` counters
|
|
14
|
+
// (bus-events-logger.ts, path-attribution-telemetry.ts): a `let` here exists
|
|
15
|
+
// once per module EVALUATION, not once per process, and #2146 measured one pid
|
|
16
|
+
// evaluating this exact graph nine times — a bare `let` would only ever see
|
|
17
|
+
// the binds routed through its own copy, undercounting every rollup that
|
|
18
|
+
// isn't reached through the first evaluation. `decideSessionStart` never
|
|
19
|
+
// returns a declined classification outside `concurrent-secondary`/
|
|
20
|
+
// `secondary-root` (session-lifecycle.ts), so those two are the whole
|
|
21
|
+
// contract; `unclassified` is a bounded third bucket for the legacy callers
|
|
22
|
+
// this function's `classification?` param still accepts.
|
|
23
|
+
const BIND_ROLLUP_FAMILY = "concurrent-session-bind-rollup";
|
|
24
|
+
const BIND_ROLLUP_VERSION = 1;
|
|
25
|
+
function bindRollupCounts() {
|
|
26
|
+
return getProcessSingleton(BIND_ROLLUP_FAMILY, BIND_ROLLUP_VERSION, () => ({
|
|
27
|
+
"concurrent-secondary": 0,
|
|
28
|
+
"secondary-root": 0,
|
|
29
|
+
unclassified: 0,
|
|
30
|
+
}));
|
|
31
|
+
}
|
|
32
|
+
function bindRollupKey(classification) {
|
|
33
|
+
return classification === "concurrent-secondary" ||
|
|
34
|
+
classification === "secondary-root"
|
|
35
|
+
? classification
|
|
36
|
+
: "unclassified";
|
|
37
|
+
}
|
|
7
38
|
export function logConcurrentSessionBind(args) {
|
|
39
|
+
bindRollupCounts()[bindRollupKey(args.classification)] += 1;
|
|
8
40
|
logLatency({
|
|
9
41
|
type: "phase",
|
|
10
42
|
filePath: "<pi-lens>",
|
|
@@ -13,3 +45,50 @@ export function logConcurrentSessionBind(args) {
|
|
|
13
45
|
metadata: args,
|
|
14
46
|
});
|
|
15
47
|
}
|
|
48
|
+
/** Snapshot of the current rollup counters, keyed by classification.
|
|
49
|
+
* Non-mutating — for tests/observability, mirroring
|
|
50
|
+
* `getBusEventRollupCounts`/`getVerifiedPathAttributionGuessCount`. */
|
|
51
|
+
export function getConcurrentSessionBindRollupCounts() {
|
|
52
|
+
return { ...bindRollupCounts() };
|
|
53
|
+
}
|
|
54
|
+
/**
|
|
55
|
+
* Log one `concurrent_session_bind_rollup` row summarizing this session's
|
|
56
|
+
* declined binds by classification, then clear the counters. Call from
|
|
57
|
+
* index.ts's `session_shutdown` handler at the same primary-only placement as
|
|
58
|
+
* `emitBusEventRollupAtSessionEnd`/`emitVerifiedPathAttributionRollup` — a
|
|
59
|
+
* concurrent secondary's own shutdown returns before reaching that point, and
|
|
60
|
+
* the counters are process-wide state a still-live secondary would still need.
|
|
61
|
+
* A no-op when nothing was ever declined this session, matching those same
|
|
62
|
+
* rollups' "no noise on an ordinary session" shape.
|
|
63
|
+
*/
|
|
64
|
+
export function emitConcurrentSessionBindRollupAtSessionEnd(cwd) {
|
|
65
|
+
const counts = bindRollupCounts();
|
|
66
|
+
const total = counts["concurrent-secondary"] +
|
|
67
|
+
counts["secondary-root"] +
|
|
68
|
+
counts.unclassified;
|
|
69
|
+
if (total === 0)
|
|
70
|
+
return;
|
|
71
|
+
logLatency({
|
|
72
|
+
type: "phase",
|
|
73
|
+
filePath: cwd,
|
|
74
|
+
phase: "concurrent_session_bind_rollup",
|
|
75
|
+
durationMs: 0,
|
|
76
|
+
metadata: { ...counts },
|
|
77
|
+
});
|
|
78
|
+
resetConcurrentSessionBindRollupCounts();
|
|
79
|
+
}
|
|
80
|
+
/**
|
|
81
|
+
* Session-boundary reset (AGENTS.md catalog shape 17). Call from index.ts's
|
|
82
|
+
* `session_start` handler on the PRIMARY continuation path only — never from
|
|
83
|
+
* a declined bind's own `session_start`, which is exactly what increments
|
|
84
|
+
* these counters, so resetting there would erase every prior sibling's tally
|
|
85
|
+
* from the same primary session. Covers the case a primary session never
|
|
86
|
+
* reaches `session_shutdown` (a crash, a forced kill) and the process's next
|
|
87
|
+
* primary must still start from zero. Also exported for tests.
|
|
88
|
+
*/
|
|
89
|
+
export function resetConcurrentSessionBindRollupCounts() {
|
|
90
|
+
const counts = bindRollupCounts();
|
|
91
|
+
counts["concurrent-secondary"] = 0;
|
|
92
|
+
counts["secondary-root"] = 0;
|
|
93
|
+
counts.unclassified = 0;
|
|
94
|
+
}
|
|
@@ -1,10 +1,19 @@
|
|
|
1
1
|
import * as path from "node:path";
|
|
2
2
|
import { isTestMode } from "./env-utils.js";
|
|
3
|
-
import {
|
|
3
|
+
import { getGlobalPiLensLogDir } from "./probe-home-state.js";
|
|
4
|
+
import { getMaxLogSizeMB } from "./log-cleanup.js";
|
|
4
5
|
import { createNdjsonLogger } from "./ndjson-logger.js";
|
|
5
|
-
export const SESSIONSTART_LOG_FILE = path.join(
|
|
6
|
+
export const SESSIONSTART_LOG_FILE = path.join(getGlobalPiLensLogDir(), "sessionstart.log");
|
|
6
7
|
// All ordinary writers share this queue, preserving their in-process order.
|
|
7
|
-
|
|
8
|
+
// Bounded like every other global sink (#2505): an unbounded sink has no
|
|
9
|
+
// size check on the write path at all, so it grows until the
|
|
10
|
+
// once-per-process session-start sweep happens to look at it — which, in a
|
|
11
|
+
// long-lived process (the warm MCP server), may be never.
|
|
12
|
+
const writer = createNdjsonLogger({
|
|
13
|
+
filePath: SESSIONSTART_LOG_FILE,
|
|
14
|
+
maxBytes: getMaxLogSizeMB() * 1024 * 1024,
|
|
15
|
+
backupPath: `${SESSIONSTART_LOG_FILE}.1`,
|
|
16
|
+
});
|
|
8
17
|
export function logSessionStart(message) {
|
|
9
18
|
if (isTestMode())
|
|
10
19
|
return;
|
|
@@ -9,7 +9,12 @@ import { findLocalToolConfig } from "./path-utils.js";
|
|
|
9
9
|
// it only operates in a project that has an `sgconfig.y[a]ml` at (or above) the
|
|
10
10
|
// file. These are the names ast-grep itself looks for as root markers.
|
|
11
11
|
export const SGCONFIG_NAMES = ["sgconfig.yml", "sgconfig.yaml"];
|
|
12
|
-
/**
|
|
12
|
+
/**
|
|
13
|
+
* Nearest `sgconfig.y[a]ml` walking up from `startDir`, or undefined if none.
|
|
14
|
+
* Deliberately UNCEILINGED at $HOME (refs #2472 review round 3, F1): ast-grep
|
|
15
|
+
* itself resolves `~/sgconfig.yml` as a legitimate global root config, not an
|
|
16
|
+
* escaped-workspace accident.
|
|
17
|
+
*/
|
|
13
18
|
export function findLocalSgconfig(startDir) {
|
|
14
19
|
return findLocalToolConfig(startDir, SGCONFIG_NAMES);
|
|
15
20
|
}
|
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Resolves the skills directory the `resources_discover` handler (#205)
|
|
3
|
+
* registers, and reports the one condition that pi previously loaded with NO
|
|
4
|
+
* visible signal: `<packageRoot>/skills` is absent, unreadable, or holds no
|
|
5
|
+
* skill pi's own loader would find (#2626).
|
|
6
|
+
*
|
|
7
|
+
* `resolvePackagePath(import.meta.url, "skills")`-equivalent resolution
|
|
8
|
+
* (`clients/package-root.ts`'s `getPackageRoot`) is correct for both the
|
|
9
|
+
* source and compiled `dist/` layouts — it walks up from the loaded entry
|
|
10
|
+
* file to the nearest `package.json`. It goes wrong silently, not loudly,
|
|
11
|
+
* when that walk lands somewhere with no `skills/` beside it: `skills/`
|
|
12
|
+
* missing from an installed package, or the entry file copied out of the
|
|
13
|
+
* package tree by a managed extension cache so the nearest `package.json`
|
|
14
|
+
* is the cache's own. Either way `resources_discover` used to hand pi a
|
|
15
|
+
* path that does not exist, `pi` registered zero skills, and nothing — no
|
|
16
|
+
* extension error, no stderr line — said so (investigated on #2587).
|
|
17
|
+
*
|
|
18
|
+
* #2626 review round 2, F1: the FIRST version of this fix inverted the
|
|
19
|
+
* acceptance criterion — it returned `[]` (no skills registered) whenever
|
|
20
|
+
* its own predicate disagreed with pi's real loader, which is worse than
|
|
21
|
+
* the bug it fixed on every layout the predicate got wrong (dropping skills
|
|
22
|
+
* pi WOULD have loaded, a regression vs. pre-fix `master`). The acceptance
|
|
23
|
+
* criteria ask for a RECORD, never a changed return value: this module
|
|
24
|
+
* returns `[skillsDir]` UNCONDITIONALLY, exactly like the pre-fix handler —
|
|
25
|
+
* pi's own `loadSkills`/`collectSkillEntries` already treat a nonexistent
|
|
26
|
+
* path as zero skills from that entry, gracefully, so handing it a path
|
|
27
|
+
* that turns out to be empty is exactly as safe as `master`'s behavior
|
|
28
|
+
* always was. The health check below is PURELY observational.
|
|
29
|
+
*
|
|
30
|
+
* #2636 review F4: the ENOENT/EACCES classification shell below used to be
|
|
31
|
+
* hand-rolled here, character-identical to the ast-grep/tree-sitter sites
|
|
32
|
+
* #2636 fixed for the same silent-zero shape — now shared via
|
|
33
|
+
* `bundled-resource-health.ts`, with `scanEntriesForSkills` supplied as this
|
|
34
|
+
* module's own "what counts as found" predicate.
|
|
35
|
+
*/
|
|
36
|
+
import * as path from "node:path";
|
|
37
|
+
import { fileURLToPath } from "node:url";
|
|
38
|
+
import * as fs from "node:fs";
|
|
39
|
+
import { scanEntriesForSkills } from "../scripts/lib/skills-predicate.mjs";
|
|
40
|
+
import { classifyBundledResourceDir, describeBundledResourceHealth, reportBundledResourceDirHealth, } from "./bundled-resource-health.js";
|
|
41
|
+
import { logLatency } from "./latency-logger.js";
|
|
42
|
+
import { getPackageRoot } from "./package-root.js";
|
|
43
|
+
/** The ledger kind this module records under (`clients/degradation-ledger.ts`). */
|
|
44
|
+
const SKILLS_DIR_MISSING_KIND = "skills-dir-missing";
|
|
45
|
+
/**
|
|
46
|
+
* Read `skillsDir` and classify it, sharing `classifyBundledResourceDir`'s
|
|
47
|
+
* ENOENT/EACCES/empty shell but counting pi-LOADABLE skill entry points
|
|
48
|
+
* (`scanEntriesForSkills`), not a bare directory listing — a `skills/`
|
|
49
|
+
* holding only a stray `.gitkeep` must read "empty", not "healthy".
|
|
50
|
+
*/
|
|
51
|
+
function checkSkillsHealth(skillsDir) {
|
|
52
|
+
return classifyBundledResourceDir(skillsDir, (dir) => {
|
|
53
|
+
const entries = fs.readdirSync(dir, { withFileTypes: true });
|
|
54
|
+
return scanEntriesForSkills(dir, entries, true).length;
|
|
55
|
+
});
|
|
56
|
+
}
|
|
57
|
+
/**
|
|
58
|
+
* Resolve the skill path for `resources_discover`. ALWAYS returns
|
|
59
|
+
* `[skillsDir]` (see the module doc for why — F1). When `skillsDir` is
|
|
60
|
+
* absent, unreadable, or holds no skill pi's loader would find, records ONE
|
|
61
|
+
* bounded `skills-dir-missing` degradation and a single `notifyUserDegradation`
|
|
62
|
+
* warning, both naming the resolved path and the entry file's directory.
|
|
63
|
+
*
|
|
64
|
+
* Either way, one `skills_resolved` phase/latency record is written so an
|
|
65
|
+
* empty ledger (no `skills-dir-missing` row) is distinguishable from
|
|
66
|
+
* "`resources_discover` never ran at all" (#2626 review F5) — the SAME
|
|
67
|
+
* silent-zero shape one level up the call stack.
|
|
68
|
+
*/
|
|
69
|
+
export function resolveSkillPaths(importMetaUrl) {
|
|
70
|
+
const packageRoot = getPackageRoot(importMetaUrl);
|
|
71
|
+
const skillsDir = path.join(packageRoot, "skills");
|
|
72
|
+
const health = checkSkillsHealth(skillsDir);
|
|
73
|
+
logLatency({
|
|
74
|
+
type: "phase",
|
|
75
|
+
phase: "skills_resolved",
|
|
76
|
+
filePath: skillsDir,
|
|
77
|
+
durationMs: 0,
|
|
78
|
+
metadata: {
|
|
79
|
+
status: health.status,
|
|
80
|
+
entryCount: health.status === "healthy" ? health.entryCount : 0,
|
|
81
|
+
},
|
|
82
|
+
});
|
|
83
|
+
if (health.status !== "healthy") {
|
|
84
|
+
const entryDir = path.dirname(fileURLToPath(importMetaUrl));
|
|
85
|
+
const reason = `${describeBundledResourceHealth(health, skillsDir, `no SKILL.md (or loadable .md) found under ${skillsDir}`)} (entry loaded from ${entryDir})`;
|
|
86
|
+
// #2626 review F3: the notify-once gate previously re-derived "have we
|
|
87
|
+
// already recorded this" by scanning `getDegradationSummary()` and
|
|
88
|
+
// comparing the RAW `skillsDir` against subjects the ledger stores
|
|
89
|
+
// `truncateForLedger`-ed — a mismatch on any subject over
|
|
90
|
+
// `LEDGER_FIELD_MAX` (200 chars, an ordinary length for a managed-cache
|
|
91
|
+
// path) renotified on every call. `reportBundledResourceDirHealth`
|
|
92
|
+
// reads `incrementDegradationCount`'s own return value for the rising
|
|
93
|
+
// edge, computed after the SAME truncation the ledger stores by, so
|
|
94
|
+
// there is no separate key to keep in sync.
|
|
95
|
+
// #2636 review round 2, F1: the shipped notify sentence ("registers
|
|
96
|
+
// zero skills") is user-visible product text #2626 chose deliberately
|
|
97
|
+
// — it names the exact SYMPTOM this whole issue exists to surface, so
|
|
98
|
+
// the shared helper's generic "<label> unavailable" template must
|
|
99
|
+
// never silently replace it. Passed explicitly rather than inferred
|
|
100
|
+
// from `label` so this stays a per-caller decision, not a convention
|
|
101
|
+
// the next caller has to remember.
|
|
102
|
+
reportBundledResourceDirHealth(SKILLS_DIR_MISSING_KIND, skillsDir, health, "skills", reason, `pi-lens: registers zero skills — ${reason}.`);
|
|
103
|
+
}
|
|
104
|
+
return [skillsDir];
|
|
105
|
+
}
|
|
@@ -55,7 +55,7 @@
|
|
|
55
55
|
*/
|
|
56
56
|
import * as fs from "node:fs";
|
|
57
57
|
import * as path from "node:path";
|
|
58
|
-
import {
|
|
58
|
+
import { getGlobalPiLensLogDir } from "./probe-home-state.js";
|
|
59
59
|
/** Bounded tail-read budget PER source log file — never a full-file scan. */
|
|
60
60
|
export const SMELLS_TAIL_BYTES_PER_FILE = 64 * 1024;
|
|
61
61
|
export const SMELLS_ROLLING_WINDOW_MS = 24 * 60 * 60_000;
|
|
@@ -159,7 +159,7 @@ function isOpengrepRespawn(entry) {
|
|
|
159
159
|
* `2 * SMELLS_TAIL_BYTES_PER_FILE` regardless of how large the (size-rotated,
|
|
160
160
|
* up to ~10MB) source files are. `root` is injectable for tests.
|
|
161
161
|
*/
|
|
162
|
-
export function countRecentSmells(root =
|
|
162
|
+
export function countRecentSmells(root = getGlobalPiLensLogDir(), sessionStartMs) {
|
|
163
163
|
const sinceMs = sessionStartMs ?? Date.now() - SMELLS_ROLLING_WINDOW_MS;
|
|
164
164
|
const busTail = tailReadText(path.join(root, "bus-events.log"), SMELLS_TAIL_BYTES_PER_FILE);
|
|
165
165
|
const latencyTail = tailReadText(path.join(root, "latency.log"), SMELLS_TAIL_BYTES_PER_FILE);
|
|
@@ -18,3 +18,16 @@
|
|
|
18
18
|
export function compareOrdinal(a, b) {
|
|
19
19
|
return a < b ? -1 : a > b ? 1 : 0;
|
|
20
20
|
}
|
|
21
|
+
/**
|
|
22
|
+
* Escape a string for safe interpolation into a `RegExp` source, so every
|
|
23
|
+
* regex metacharacter it contains is matched literally instead of taking on
|
|
24
|
+
* its regex meaning. This is the ONE runtime copy (#2558) — string-utils.ts
|
|
25
|
+
* is a leaf (no imports of its own), so importing it never creates a cycle.
|
|
26
|
+
* Before #2558 this same body was hand-copied under this name (and as
|
|
27
|
+
* `escapeRegExpChar`/`escapeRegExpLiteral`) into ~8 production modules and 3
|
|
28
|
+
* test helpers; fold new call sites onto this export instead of re-copying
|
|
29
|
+
* it.
|
|
30
|
+
*/
|
|
31
|
+
export function escapeRegExp(value) {
|
|
32
|
+
return value.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
33
|
+
}
|
|
@@ -4,8 +4,16 @@
|
|
|
4
4
|
* Two known subagent-spawning ecosystems set different env vocabularies in
|
|
5
5
|
* every spawned child's environment:
|
|
6
6
|
*
|
|
7
|
-
* - nicobailon/pi-subagents sets `PI_SUBAGENT_CHILD=1` unconditionally
|
|
8
|
-
*
|
|
7
|
+
* - nicobailon/pi-subagents sets `PI_SUBAGENT_CHILD=1` unconditionally on
|
|
8
|
+
* every process that hosts a child session — the only var light mode keys
|
|
9
|
+
* on for this vocabulary. It ALSO used to set `PI_SUBAGENT_RUN_ID` /
|
|
10
|
+
* `PI_SUBAGENT_CHILD_AGENT` alongside it for best-effort identity, but
|
|
11
|
+
* removed both entirely in `pi-subagents@0.65.0`'s native-AgentSession
|
|
12
|
+
* rewrite (grep-verified absent from the whole 0.66.0 source tree, #2581/
|
|
13
|
+
* #2680) — child identity now travels through an in-process object, not
|
|
14
|
+
* env vars. `getSubagentIdentity()` below already treats identity as
|
|
15
|
+
* optional best-effort metadata, so this permanent absence for the
|
|
16
|
+
* nicobailon vocabulary needed no behavior change, only the doc update.
|
|
9
17
|
* - avtc-pi-subagent (the spawn engine under avtc-pi-feature-flow) is the same
|
|
10
18
|
* execution model — real child-process `pi --mode rpc` / `--mode json -p`
|
|
11
19
|
* spawns, full env inheritance — but never sets `PI_SUBAGENT_CHILD`. It sets
|
|
@@ -63,8 +71,13 @@ export function isSubagentSession() {
|
|
|
63
71
|
/**
|
|
64
72
|
* Best-effort identity of the current subagent, read from the env vars the
|
|
65
73
|
* detected extension sets alongside its subagent marker. Returns `undefined`
|
|
66
|
-
* when neither identity var is present
|
|
67
|
-
*
|
|
74
|
+
* when neither identity var is present — not a subagent session, an
|
|
75
|
+
* extension that never set them, OR nicobailon/pi-subagents@0.65.0+, which
|
|
76
|
+
* removed both identity vars upstream while still setting `PI_SUBAGENT_CHILD`
|
|
77
|
+
* (#2581/#2680): light mode still engages via `isSubagentSession()` alone,
|
|
78
|
+
* `marker` is still populated, only `runId`/`agentName` degrade to
|
|
79
|
+
* `undefined`. Identity is metadata for observability, never a light-mode
|
|
80
|
+
* gate — callers must not treat its absence as "not a subagent".
|
|
68
81
|
*/
|
|
69
82
|
export function getSubagentIdentity() {
|
|
70
83
|
const runId = process.env.PI_SUBAGENT_RUN_ID || undefined;
|