@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
|
@@ -221,6 +221,35 @@ function createState(files) {
|
|
|
221
221
|
progress: [],
|
|
222
222
|
},
|
|
223
223
|
},
|
|
224
|
+
// #2526: the config stack's positive-observability rows. `resolved`
|
|
225
|
+
// counts `config_resolved` phase records; `legacyWithoutRecords` counts
|
|
226
|
+
// the rows that carry a deprecated document but produced no
|
|
227
|
+
// migration/notice record — the deprecation machinery gone silent.
|
|
228
|
+
//
|
|
229
|
+
// Round 2, F2: the session->row relation is a JOIN on the session id both
|
|
230
|
+
// sides carry, not a subtraction of two counts.
|
|
231
|
+
//
|
|
232
|
+
// Round 3, S1: the session-side half of the join is no longer a
|
|
233
|
+
// PREDICTION. `pendingSessions` holds every session id that published a
|
|
234
|
+
// `config_resolution_pending` mark — written by `loadLSPConfig` itself,
|
|
235
|
+
// at the instant a resolution is actually attempted, never by a
|
|
236
|
+
// `runtime-session.ts` handler guessing from `no-lsp`/subagent/warm-attach
|
|
237
|
+
// flags ahead of time. A session that never reaches that call (quick or
|
|
238
|
+
// minimal mode's second-and-later session in a process, for the same
|
|
239
|
+
// root) never gets a mark, so it is silently excluded rather than
|
|
240
|
+
// counted against. `resolvedSessions` holds every session id a
|
|
241
|
+
// resolution actually reported, from EITHER sink (the latency row or the
|
|
242
|
+
// sessionstart line — one call writes both, so this is one fact
|
|
243
|
+
// surviving an independent rotation of either log, not a second source
|
|
244
|
+
// of truth).
|
|
245
|
+
config: {
|
|
246
|
+
resolved: 0,
|
|
247
|
+
pendingSessions: new Map(),
|
|
248
|
+
resolvedSessions: new Set(),
|
|
249
|
+
legacyDocuments: 0,
|
|
250
|
+
legacyWithoutRecords: 0,
|
|
251
|
+
examples: [],
|
|
252
|
+
},
|
|
224
253
|
diagnostics: {
|
|
225
254
|
bySeverity: counter(),
|
|
226
255
|
byTool: counter(),
|
|
@@ -351,7 +380,44 @@ async function analyzeLatency(files, state) {
|
|
|
351
380
|
} else if (entry.type === "phase") {
|
|
352
381
|
const phase = entry.phase ?? "unknown";
|
|
353
382
|
state.latency.phaseCounts.inc(phase);
|
|
354
|
-
if (
|
|
383
|
+
if (phase.endsWith("_timeout")) state.latency.phaseTimeouts.inc(phase);
|
|
384
|
+
if (phase === "config_resolved") {
|
|
385
|
+
// #2526. Counted here rather than derived from phaseCounts so the
|
|
386
|
+
// legacy/record cross-check reads the same row it counts.
|
|
387
|
+
state.config.resolved += 1;
|
|
388
|
+
const md = entry.metadata ?? {};
|
|
389
|
+
// #2526 R2 F2 / #2552 R4: the join key is (session, root), not
|
|
390
|
+
// session alone — see `configJoinKey`'s doc comment. `entry.filePath`
|
|
391
|
+
// is this row's root (the same `configResolutionKey(cwd)` value the
|
|
392
|
+
// pending mark's `root=` carries); a row from a build that predates
|
|
393
|
+
// the session id carries none, and simply joins to nothing.
|
|
394
|
+
if (
|
|
395
|
+
typeof md.sessionId === "string" &&
|
|
396
|
+
md.sessionId.length > 0 &&
|
|
397
|
+
typeof entry.filePath === "string" &&
|
|
398
|
+
entry.filePath.length > 0
|
|
399
|
+
) {
|
|
400
|
+
state.config.resolvedSessions.add(
|
|
401
|
+
configJoinKey(md.sessionId, entry.filePath),
|
|
402
|
+
);
|
|
403
|
+
}
|
|
404
|
+
const documents = Array.isArray(md.documents) ? md.documents : [];
|
|
405
|
+
const legacy = documents.filter((doc) => doc?.legacy === true);
|
|
406
|
+
state.config.legacyDocuments += legacy.length;
|
|
407
|
+
// A deprecated document that produced NO record means the
|
|
408
|
+
// migration notices went silent — the user is on a removal
|
|
409
|
+
// schedule and is never told. Zero records with zero legacy
|
|
410
|
+
// documents is the correct canonical-only answer, not a smell.
|
|
411
|
+
if (legacy.length > 0 && Number(md.recordCount ?? 0) === 0) {
|
|
412
|
+
state.config.legacyWithoutRecords += 1;
|
|
413
|
+
pushTop(
|
|
414
|
+
state.config.examples,
|
|
415
|
+
summarizeConfigResolved(entry, "legacy document with 0 records"),
|
|
416
|
+
limit * 3,
|
|
417
|
+
byDuration,
|
|
418
|
+
);
|
|
419
|
+
}
|
|
420
|
+
}
|
|
355
421
|
if (
|
|
356
422
|
phase === "total" &&
|
|
357
423
|
(entry.durationMs ?? 0) >= thresholds.totalSlowMs
|
|
@@ -636,6 +702,40 @@ async function analyzeSessionStart(files, state) {
|
|
|
636
702
|
trackProject(state, cwd);
|
|
637
703
|
}
|
|
638
704
|
|
|
705
|
+
// #2526 R3 S1: this session's config-resolution PENDING mark, published
|
|
706
|
+
// by `loadLSPConfig` itself at the instant a resolution is actually
|
|
707
|
+
// attempted — never a start-line prediction from `no-lsp`/subagent/
|
|
708
|
+
// warm-attach flags. A session that never calls `loadLSPConfig` (quick
|
|
709
|
+
// or minimal mode's second-and-later session in a process, for the
|
|
710
|
+
// same root) never writes this line, and is correctly absent from the
|
|
711
|
+
// join rather than counted against.
|
|
712
|
+
//
|
|
713
|
+
// #2552 R4: `root=` is REQUIRED in the match — a warm MCP process keeps
|
|
714
|
+
// one session id for its whole life but marks once per served root
|
|
715
|
+
// (`configJoinKey`'s doc comment), so a line missing it cannot be
|
|
716
|
+
// attributed to a specific root and is left out of the join rather than
|
|
717
|
+
// guessed into a wrong one.
|
|
718
|
+
const pending =
|
|
719
|
+
/session_start config_resolution_pending session=(\S+) root=(.*)$/.exec(
|
|
720
|
+
message,
|
|
721
|
+
);
|
|
722
|
+
if (pending) {
|
|
723
|
+
const [, sessionId, root] = pending;
|
|
724
|
+
state.config.pendingSessions.set(configJoinKey(sessionId, root), {
|
|
725
|
+
ts: iso(ts),
|
|
726
|
+
sessionId,
|
|
727
|
+
root,
|
|
728
|
+
});
|
|
729
|
+
}
|
|
730
|
+
// The loader's own line is the second half of the join, so a rotated
|
|
731
|
+
// latency.log cannot manufacture a deficit on its own.
|
|
732
|
+
const resolvedSession =
|
|
733
|
+
/config resolved .*\bsession=(\S+) root=(.*)$/.exec(message);
|
|
734
|
+
if (resolvedSession) {
|
|
735
|
+
const [, sessionId, root] = resolvedSession;
|
|
736
|
+
state.config.resolvedSessions.add(configJoinKey(sessionId, root));
|
|
737
|
+
}
|
|
738
|
+
|
|
639
739
|
const total = /session_start total:\s*(\d+)ms/.exec(message);
|
|
640
740
|
if (total && Number(total[1]) >= thresholds.startupSlowMs) {
|
|
641
741
|
state.smellTotals.inc("slow-session-start");
|
|
@@ -899,6 +999,23 @@ function iso(date) {
|
|
|
899
999
|
return date?.toISOString?.() ?? "unknown";
|
|
900
1000
|
}
|
|
901
1001
|
|
|
1002
|
+
/**
|
|
1003
|
+
* The config-resolution join key (#2552 review round 4). A warm MCP process
|
|
1004
|
+
* keeps ONE session id for its entire life but calls `loadLSPConfig` once per
|
|
1005
|
+
* SERVED ROOT (#2526 review round 2, F3's premise, reintroduced one layer up
|
|
1006
|
+
* here) — joining on session id alone let one root's row silently clear every
|
|
1007
|
+
* OTHER root's deficit under the same session id. `root` is whatever string
|
|
1008
|
+
* the producer already wrote (the pending mark's `root=`, or the row's own
|
|
1009
|
+
* `filePath` — both come from the SAME `configResolutionKey(cwd)` call in
|
|
1010
|
+
* `clients/lsp/config.ts`, which folds separators, canonicalizes, then folds
|
|
1011
|
+
* again — `normalizeFilePath(path.resolve(normalizeFilePath(cwd)))`, in that
|
|
1012
|
+
* order (#2518 review F6; resolving first breaks POSIX backslash names), so they compare equal without this script re-deriving any
|
|
1013
|
+
* path normalization of its own).
|
|
1014
|
+
*/
|
|
1015
|
+
function configJoinKey(sessionId, root) {
|
|
1016
|
+
return `${sessionId} ${root}`;
|
|
1017
|
+
}
|
|
1018
|
+
|
|
902
1019
|
function counter() {
|
|
903
1020
|
const map = new Map();
|
|
904
1021
|
return {
|
|
@@ -985,6 +1102,33 @@ function summarizeLatency(entry) {
|
|
|
985
1102
|
};
|
|
986
1103
|
}
|
|
987
1104
|
|
|
1105
|
+
/**
|
|
1106
|
+
* A `config_resolved` row (#2526), summarised for a smell example.
|
|
1107
|
+
*
|
|
1108
|
+
* Deliberately NOT `summarizeLatency`: that helper's metadata whitelist would
|
|
1109
|
+
* drop every field this row carries, so the example would print a phase name
|
|
1110
|
+
* and nothing a reader could act on.
|
|
1111
|
+
*/
|
|
1112
|
+
function summarizeConfigResolved(entry, note) {
|
|
1113
|
+
const md = entry.metadata ?? {};
|
|
1114
|
+
const documents = Array.isArray(md.documents) ? md.documents : [];
|
|
1115
|
+
return {
|
|
1116
|
+
ts: entry.ts,
|
|
1117
|
+
durationMs: entry.durationMs,
|
|
1118
|
+
phase: entry.phase,
|
|
1119
|
+
project: projectOf(entry.filePath),
|
|
1120
|
+
note,
|
|
1121
|
+
documents: documents
|
|
1122
|
+
.map(
|
|
1123
|
+
(doc) =>
|
|
1124
|
+
`${doc?.tier ?? "?"}:${doc?.file ?? "?"}${doc?.legacy ? " (legacy)" : ""}`,
|
|
1125
|
+
)
|
|
1126
|
+
.slice(0, 8),
|
|
1127
|
+
recordCount: md.recordCount,
|
|
1128
|
+
deniedServers: md.deniedServers,
|
|
1129
|
+
};
|
|
1130
|
+
}
|
|
1131
|
+
|
|
988
1132
|
function summarizeWorkspaceSweep(entry) {
|
|
989
1133
|
const md = entry.metadata ?? {};
|
|
990
1134
|
const bits = [];
|
|
@@ -1193,6 +1337,43 @@ function buildReport(state) {
|
|
|
1193
1337
|
`session_start background tasks >= ${thresholds.backgroundSlowMs}ms`,
|
|
1194
1338
|
state.session.slowTasks.slice(0, limit),
|
|
1195
1339
|
);
|
|
1340
|
+
// #2526: config resolution has to prove it HAPPENED. Two shapes, one smell:
|
|
1341
|
+
//
|
|
1342
|
+
// (a) a session that has a `config_resolution_pending` mark and produced no
|
|
1343
|
+
// `config_resolved` row. Round 3, S1: the pending mark is written by
|
|
1344
|
+
// `loadLSPConfig` itself, at the instant a resolution is actually
|
|
1345
|
+
// attempted — never predicted from a handler's own flags ahead of time.
|
|
1346
|
+
// Round 2, F2 established the JOIN itself: on the session id both sides
|
|
1347
|
+
// carry, never a subtraction of two counts (subtracting counted quick
|
|
1348
|
+
// sessions' rows against full sessions' start lines — different
|
|
1349
|
+
// populations — which both masked total silence and charged
|
|
1350
|
+
// `--no-lsp`/subagent sessions with a permanent deficit they could never
|
|
1351
|
+
// clear).
|
|
1352
|
+
// Round 4, #2552 review: the join is on (session, root), not session
|
|
1353
|
+
// alone — a warm MCP process keeps one session id for its whole life but
|
|
1354
|
+
// marks once per SERVED ROOT (`configJoinKey`'s doc comment), so one
|
|
1355
|
+
// root's row must not clear another root's deficit under the same id.
|
|
1356
|
+
// (b) a legacy document present with zero records — the deprecation
|
|
1357
|
+
// machinery went silent while the user is on a removal schedule.
|
|
1358
|
+
const pendingConfigResolution = [...state.config.pendingSessions.entries()];
|
|
1359
|
+
const unresolvedSessions = pendingConfigResolution.filter(
|
|
1360
|
+
([key]) => !state.config.resolvedSessions.has(key),
|
|
1361
|
+
);
|
|
1362
|
+
for (const [, value] of unresolvedSessions.slice(0, limit * 3)) {
|
|
1363
|
+
state.config.examples.push({
|
|
1364
|
+
ts: value.ts,
|
|
1365
|
+
session: value.sessionId,
|
|
1366
|
+
root: value.root,
|
|
1367
|
+
note: "session had a config_resolution_pending mark and produced no config_resolved row",
|
|
1368
|
+
});
|
|
1369
|
+
}
|
|
1370
|
+
addSmell(
|
|
1371
|
+
smells,
|
|
1372
|
+
"config-resolution",
|
|
1373
|
+
unresolvedSessions.length + state.config.legacyWithoutRecords,
|
|
1374
|
+
`Sessions with a config_resolution_pending mark but no config_resolved row (${unresolvedSessions.length} of ${pendingConfigResolution.length}) or a legacy config document that produced no migration record (${state.config.legacyWithoutRecords})`,
|
|
1375
|
+
state.config.examples.slice(0, limit),
|
|
1376
|
+
);
|
|
1196
1377
|
addSmell(
|
|
1197
1378
|
smells,
|
|
1198
1379
|
"cascade-fallbacks",
|
|
@@ -1352,6 +1533,16 @@ function buildReport(state) {
|
|
|
1352
1533
|
rotations: state.session.rotations.toJSON(),
|
|
1353
1534
|
errors: state.session.errors.slice(0, limit),
|
|
1354
1535
|
},
|
|
1536
|
+
// #2526: the positive-observability counters behind the
|
|
1537
|
+
// `config-resolution` smell, so a reader can see WHY it fired (or that
|
|
1538
|
+
// it correctly did not) without re-deriving the deficit.
|
|
1539
|
+
config: {
|
|
1540
|
+
resolved: state.config.resolved,
|
|
1541
|
+
sessionsPendingResolution: pendingConfigResolution.length,
|
|
1542
|
+
sessionsWithoutResolution: unresolvedSessions.length,
|
|
1543
|
+
legacyDocuments: state.config.legacyDocuments,
|
|
1544
|
+
legacyWithoutRecords: state.config.legacyWithoutRecords,
|
|
1545
|
+
},
|
|
1355
1546
|
actionable: {
|
|
1356
1547
|
events: state.actionable.events.toJSON(),
|
|
1357
1548
|
reports: state.actionable.reports,
|
|
@@ -17,7 +17,9 @@
|
|
|
17
17
|
* Force-imports the modules whose TOP-LEVEL bare imports are the documented
|
|
18
18
|
* failure points, plus the bare specifiers directly, and checks the two
|
|
19
19
|
* build-script-provided assets (ast-grep CLI binary + tree-sitter grammars)
|
|
20
|
-
* that pnpm/bun skip by default. It
|
|
20
|
+
* that pnpm/bun skip by default. It also resolves the `pi.skills` manifest
|
|
21
|
+
* entries the way pi does, from the installed package root (#2587). It runs no
|
|
22
|
+
* model and needs no credentials.
|
|
21
23
|
*
|
|
22
24
|
* WHAT IT NO LONGER COVERS (#1926)
|
|
23
25
|
* pi supplies `typebox` and `@earendil-works/pi-tui` from its own runtime, so
|
|
@@ -47,6 +49,7 @@ import { createRequire } from "node:module";
|
|
|
47
49
|
import * as path from "node:path";
|
|
48
50
|
import { fileURLToPath } from "node:url";
|
|
49
51
|
import { HOST_PROVIDED_PACKAGES } from "./lib/host-provided-deps.mjs";
|
|
52
|
+
import { collectSkillEntryPaths } from "./lib/skills-predicate.mjs";
|
|
50
53
|
|
|
51
54
|
const here = path.dirname(fileURLToPath(import.meta.url));
|
|
52
55
|
const pkgRoot = path.resolve(here, "..");
|
|
@@ -242,6 +245,56 @@ try {
|
|
|
242
245
|
}
|
|
243
246
|
record("tree-sitter grammars", "asset", hasCoreGrammar, grammarDetail);
|
|
244
247
|
|
|
248
|
+
// --- 4. pi.skills manifest resolution, AS INSTALLED (#2587) ----------------
|
|
249
|
+
// Guards the recurrence of #2587: a `pi.skills` entry that resolves outside the
|
|
250
|
+
// installed package, so pi registers none of the shipped skills. This probe runs
|
|
251
|
+
// from the INSTALLED package (`require.resolve("pi-lens/scripts/…")`), so it sees
|
|
252
|
+
// the real layout — hoisted node_modules, pnpm's symlink store, bun, yarn — which
|
|
253
|
+
// is exactly where `../../skills` escaped and where a static check on the source
|
|
254
|
+
// tree cannot look. Replicates pi's own resolver, `PackageManager#collectFiles\
|
|
255
|
+
// FromManifestEntries` in `@earendil-works/pi-coding-agent`
|
|
256
|
+
// `dist/core/package-manager.js`: a non-glob entry is `resolve(packageRoot, entry)`
|
|
257
|
+
// (verified identical in 0.78.1 / 0.84.1 / 0.85.1).
|
|
258
|
+
//
|
|
259
|
+
// #2626 review round 2 (F2): the "does this dir have a skill" walk used to be
|
|
260
|
+
// a hand-rolled `countSkillFiles` here AND a second, differently-wrong one in
|
|
261
|
+
// `clients/skills-resolver.ts`. Both now derive from the ONE structural
|
|
262
|
+
// predicate in `./lib/skills-predicate.mjs`, which replicates pi's actual
|
|
263
|
+
// `loadSkillsFromDirInternal` walk (see that module's header for the exact
|
|
264
|
+
// discovery rules and the two documented scope gaps).
|
|
265
|
+
{
|
|
266
|
+
const pkgJson = JSON.parse(
|
|
267
|
+
fs.readFileSync(path.join(pkgRoot, "package.json"), "utf8"),
|
|
268
|
+
);
|
|
269
|
+
const entries = pkgJson.pi?.skills ?? [];
|
|
270
|
+
if (entries.length === 0) {
|
|
271
|
+
record("pi.skills declared", "manifest", false, "pi.skills is empty");
|
|
272
|
+
}
|
|
273
|
+
for (const entry of entries) {
|
|
274
|
+
const label = `pi.skills "${entry}"`;
|
|
275
|
+
// pi globs entries containing * or ? through a different branch; this
|
|
276
|
+
// probe only replicates the non-glob one.
|
|
277
|
+
if (/[*?]/.test(entry)) {
|
|
278
|
+
record(label, "manifest", true, "glob entry — not probed");
|
|
279
|
+
continue;
|
|
280
|
+
}
|
|
281
|
+
const resolved = path.resolve(pkgRoot, entry);
|
|
282
|
+
if (resolved !== pkgRoot && !resolved.startsWith(pkgRoot + path.sep)) {
|
|
283
|
+
record(label, "manifest", false, `escapes the package: ${resolved}`);
|
|
284
|
+
continue;
|
|
285
|
+
}
|
|
286
|
+
const found = collectSkillEntryPaths(resolved).length;
|
|
287
|
+
record(
|
|
288
|
+
label,
|
|
289
|
+
"manifest",
|
|
290
|
+
found > 0,
|
|
291
|
+
found > 0
|
|
292
|
+
? `${found} SKILL.md under ${resolved}`
|
|
293
|
+
: `no SKILL.md under ${resolved}`,
|
|
294
|
+
);
|
|
295
|
+
}
|
|
296
|
+
}
|
|
297
|
+
|
|
245
298
|
// --- Report ----------------------------------------------------------------
|
|
246
299
|
const pad = Math.max(...results.map((r) => r.name.length));
|
|
247
300
|
let hardFail = 0;
|
|
@@ -249,7 +302,10 @@ let softFail = 0;
|
|
|
249
302
|
for (const r of results) {
|
|
250
303
|
const soft = (r.kind === "asset" || r.kind === "tool") && allowSoft;
|
|
251
304
|
const status = r.ok ? "PASS" : soft ? "WARN" : "FAIL";
|
|
252
|
-
if (!r.ok)
|
|
305
|
+
if (!r.ok) {
|
|
306
|
+
if (soft) softFail++;
|
|
307
|
+
else hardFail++;
|
|
308
|
+
}
|
|
253
309
|
console.log(
|
|
254
310
|
` [${status}] ${r.name.padEnd(pad)} ${r.detail ? "— " + r.detail : ""}`,
|
|
255
311
|
);
|
|
@@ -0,0 +1,129 @@
|
|
|
1
|
+
// The ONE structural replica of pi's own skill-loading walk (#2626 review
|
|
2
|
+
// round 2, F1/F2).
|
|
3
|
+
//
|
|
4
|
+
// Two independent detectors used to answer "does this directory tree hold a
|
|
5
|
+
// skill pi would load" with two DIFFERENT, hand-rolled heuristics that both
|
|
6
|
+
// diverged from pi's real resolver:
|
|
7
|
+
// - `clients/skills-resolver.ts` (a `SKILL.md` one level down only, no
|
|
8
|
+
// recursion, no root `.md` acceptance, no symlink-follow, no dot/
|
|
9
|
+
// node_modules skip)
|
|
10
|
+
// - `scripts/install-selftest.mjs`'s `countSkillFiles` (recursed
|
|
11
|
+
// UNBOUNDED — would double-count a `SKILL.md` sitting inside another
|
|
12
|
+
// skill's own resource subdirectory — with no dot/node_modules skip, no
|
|
13
|
+
// root `.md` acceptance, no symlink handling)
|
|
14
|
+
// Neither matched `loadSkillsFromDirInternal` in
|
|
15
|
+
// `@earendil-works/pi-coding-agent` `dist/core/skills.js` (mirrored by
|
|
16
|
+
// `collectSkillEntries` in `dist/core/package-manager.js`, byte-identical
|
|
17
|
+
// walk, confirmed against the 0.85.1 tarball). This module is the fold: BOTH
|
|
18
|
+
// consumers now derive from `collectSkillEntryPaths` below.
|
|
19
|
+
//
|
|
20
|
+
// Discovery rules, replicated from `loadSkillsFromDirInternal` (verified
|
|
21
|
+
// against the extracted 0.85.1 `skills.js`):
|
|
22
|
+
// 1. If `dir` directly contains a (non-symlink-broken) `SKILL.md`, `dir` IS
|
|
23
|
+
// one skill root — return immediately, do NOT look at `dir`'s other
|
|
24
|
+
// entries or recurse into its subdirectories (a `SKILL.md` inside a
|
|
25
|
+
// skill's own reference/ subfolder is the skill's OWN resource, not a
|
|
26
|
+
// second skill).
|
|
27
|
+
// 2. Otherwise, skip dot-prefixed entries and `node_modules`; recurse into
|
|
28
|
+
// every remaining subdirectory (same two rules, one level down); at the
|
|
29
|
+
// OUTERMOST call only (`isRoot`), a loose `*.md` file directly in `dir`
|
|
30
|
+
// also counts (pi's `includeRootFiles`, true only for the top call).
|
|
31
|
+
// 3. A symlink is followed via `statSync` (broken symlink = skip) for BOTH
|
|
32
|
+
// the `SKILL.md` check and the directory/file classification in step 2.
|
|
33
|
+
//
|
|
34
|
+
// Deliberately NOT replicated (out of #2626's scope — packaging/path
|
|
35
|
+
// resolution, not skill-content validation):
|
|
36
|
+
// - `.gitignore`/`.ignore`/`.fdignore` matching inside the skills tree.
|
|
37
|
+
// - frontmatter parsing: pi additionally requires a non-empty `description`
|
|
38
|
+
// field before a discovered file becomes a loaded skill. A `SKILL.md`
|
|
39
|
+
// file that exists but fails THAT validation is a content-authoring
|
|
40
|
+
// defect a maintainer would see in normal use, not a silent zero.
|
|
41
|
+
// Both gaps mean this predicate can be a bit more OPTIMISTIC than pi's true
|
|
42
|
+
// count in a pathological case (an ignored or description-less file still
|
|
43
|
+
// counts as "found" here); it is never more PESSIMISTIC — every real skill
|
|
44
|
+
// pi loads is found by this walk too — which is the direction #2626 cares
|
|
45
|
+
// about (never claim "no skills" when pi would load one).
|
|
46
|
+
|
|
47
|
+
import * as fs from "node:fs";
|
|
48
|
+
import * as path from "node:path";
|
|
49
|
+
|
|
50
|
+
/**
|
|
51
|
+
* Symlink-aware entry classification, mirroring `loadSkillsFromDirInternal`'s
|
|
52
|
+
* own `entry.isSymbolicLink() ? statSync(fullPath) : entry`.
|
|
53
|
+
* @param {string} fullPath
|
|
54
|
+
* @param {import("node:fs").Dirent} entry
|
|
55
|
+
* @returns {"file" | "dir" | "other"}
|
|
56
|
+
*/
|
|
57
|
+
export function resolvedEntryKind(fullPath, entry) {
|
|
58
|
+
if (entry.isSymbolicLink()) {
|
|
59
|
+
try {
|
|
60
|
+
const stats = fs.statSync(fullPath);
|
|
61
|
+
if (stats.isDirectory()) return "dir";
|
|
62
|
+
if (stats.isFile()) return "file";
|
|
63
|
+
return "other";
|
|
64
|
+
} catch {
|
|
65
|
+
return "other"; // broken symlink
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
if (entry.isDirectory()) return "dir";
|
|
69
|
+
if (entry.isFile()) return "file";
|
|
70
|
+
return "other";
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
/**
|
|
74
|
+
* The structural walk over an ALREADY-READ directory listing — split out
|
|
75
|
+
* from `collectSkillEntryPaths` so a caller that already has `entries` (a
|
|
76
|
+
* top-level ENOENT/EACCES distinction, say) is not forced into a second
|
|
77
|
+
* `readdirSync`.
|
|
78
|
+
* @param {string} dir
|
|
79
|
+
* @param {import("node:fs").Dirent[]} entries
|
|
80
|
+
* @param {boolean} isRoot
|
|
81
|
+
* @returns {string[]} absolute paths of every `SKILL.md` (or, at the root,
|
|
82
|
+
* loose `.md`) file pi's own resolver would treat as a skill entry point.
|
|
83
|
+
*/
|
|
84
|
+
export function scanEntriesForSkills(dir, entries, isRoot) {
|
|
85
|
+
for (const entry of entries) {
|
|
86
|
+
if (
|
|
87
|
+
entry.name === "SKILL.md" &&
|
|
88
|
+
resolvedEntryKind(path.join(dir, entry.name), entry) === "file"
|
|
89
|
+
) {
|
|
90
|
+
return [path.join(dir, entry.name)];
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
const found = [];
|
|
94
|
+
for (const entry of entries) {
|
|
95
|
+
if (entry.name.startsWith(".") || entry.name === "node_modules") {
|
|
96
|
+
continue;
|
|
97
|
+
}
|
|
98
|
+
const fullPath = path.join(dir, entry.name);
|
|
99
|
+
const kind = resolvedEntryKind(fullPath, entry);
|
|
100
|
+
if (kind === "dir") {
|
|
101
|
+
found.push(...collectSkillEntryPaths(fullPath, false));
|
|
102
|
+
continue;
|
|
103
|
+
}
|
|
104
|
+
if (isRoot && kind === "file" && entry.name.endsWith(".md")) {
|
|
105
|
+
found.push(fullPath);
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
return found;
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
/**
|
|
112
|
+
* Every skill entry point under `dir`, recursively, per pi's discovery
|
|
113
|
+
* rules. Fail-closed: a `readdirSync` error at `dir` (absent, unreadable) or
|
|
114
|
+
* any recursed-into subdirectory returns `[]` for that branch rather than
|
|
115
|
+
* throwing — matching `loadSkillsFromDirInternal`'s own bare `try { … }
|
|
116
|
+
* catch {}` per directory.
|
|
117
|
+
* @param {string} dir
|
|
118
|
+
* @param {boolean} [isRoot]
|
|
119
|
+
* @returns {string[]}
|
|
120
|
+
*/
|
|
121
|
+
export function collectSkillEntryPaths(dir, isRoot = true) {
|
|
122
|
+
let entries;
|
|
123
|
+
try {
|
|
124
|
+
entries = fs.readdirSync(dir, { withFileTypes: true });
|
|
125
|
+
} catch {
|
|
126
|
+
return [];
|
|
127
|
+
}
|
|
128
|
+
return scanEntriesForSkills(dir, entries, isRoot);
|
|
129
|
+
}
|
|
@@ -61,7 +61,9 @@ function handle(line) {
|
|
|
61
61
|
if (m.type === "response" && m.command === "get_commands") {
|
|
62
62
|
const cmds = (m.data && m.data.commands) || [];
|
|
63
63
|
const lens = cmds.filter(
|
|
64
|
-
(c) =>
|
|
64
|
+
(c) =>
|
|
65
|
+
String(c.name || "").startsWith("lens-") ||
|
|
66
|
+
String(c.path || "").includes("pi-lens"),
|
|
65
67
|
);
|
|
66
68
|
console.log(
|
|
67
69
|
`total commands: ${cmds.length}; pi-lens commands: ${lens.map((c) => c.name).join(", ") || "(none)"}`,
|
|
@@ -4,6 +4,34 @@ All notable changes to this project will be documented in this file.
|
|
|
4
4
|
|
|
5
5
|
## [Unreleased]
|
|
6
6
|
|
|
7
|
+
## [0.28.0] - 2026-09-04
|
|
8
|
+
|
|
9
|
+
### Highlights
|
|
10
|
+
|
|
11
|
+
- Search X posts through xAI or choose Mistral for web searches.
|
|
12
|
+
- Batch searches run in parallel for faster multi-query research.
|
|
13
|
+
- Follow-up retrieval can access stored search results, and Perplexity keeps all cited sources.
|
|
14
|
+
- Web-tool proxy settings no longer affect unrelated Pi requests.
|
|
15
|
+
|
|
16
|
+
### Added
|
|
17
|
+
|
|
18
|
+
- Documented the Linux `xdg-utils` dependency for automatic curator browser launch and the manual URL fallback. Thanks to [@wickedTangent](https://github.com/wickedTangent) for issue #336 and PR #337.
|
|
19
|
+
- Added opt-in X post search through xAI alongside web search, configured with `xaiSearchTools`. Thanks to [@Jerry2003sky](https://github.com/Jerry2003sky) for issue #342.
|
|
20
|
+
- Added Mistral web search with `provider: "mistral"`, using `mistralApiKey` / `MISTRAL_API_KEY` credentials. Premium web search is available as a separate opt-in. Thanks to [@jaudiger](https://github.com/jaudiger) for issue #346.
|
|
21
|
+
|
|
22
|
+
### Changed
|
|
23
|
+
|
|
24
|
+
- Run batch searches in parallel with a concurrency limit, keeping results in query order and preserving provider fallback. Thanks to [@Noir-Lime](https://github.com/Noir-Lime) for PR #345.
|
|
25
|
+
|
|
26
|
+
### Fixed
|
|
27
|
+
|
|
28
|
+
- Included `responseId` in search output so the model can retrieve stored results with `get_search_content`. Thanks to [@axelbaumlisto](https://github.com/axelbaumlisto) for PR #354.
|
|
29
|
+
- Fixed flaky tests on slower Node startups. Thanks to [@axelbaumlisto](https://github.com/axelbaumlisto) for PR #353.
|
|
30
|
+
- Kept all sources cited in Perplexity answers, even beyond `numResults`. Answers without citations still respect the result limit. Thanks to [@schlessera](https://github.com/schlessera) for issue #340 and PR #341.
|
|
31
|
+
- Limited configured proxies to web-tool requests so unrelated Pi requests are unaffected. Thanks to [@alexei-ciobanu](https://github.com/alexei-ciobanu) for PR #339 and [@mystery4f](https://github.com/mystery4f) for PR #343.
|
|
32
|
+
- Cleaned up abandoned GitHub clone directories after crashes, only when their owning process is confirmed dead. Thanks to [@yazanabuashour](https://github.com/yazanabuashour) for issue #331.
|
|
33
|
+
- Kept using an existing `~/.pi/web-search.json` when `XDG_CONFIG_HOME` is set but no config file exists there. Thanks to [@hu3rror](https://github.com/hu3rror) for issue #333.
|
|
34
|
+
|
|
7
35
|
## [0.27.0] - 2026-08-28
|
|
8
36
|
|
|
9
37
|
### Highlights
|