@herbertgao/pi-extensions 2026.9.1 → 2026.9.3
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/README.md +3 -2
- package/THIRD_PARTY_NOTICES.md +24 -0
- package/node_modules/@herbertgao/sol-pi/LICENSE +19 -0
- package/node_modules/@herbertgao/sol-pi/README.md +159 -0
- package/node_modules/@herbertgao/sol-pi/SECURITY.md +26 -0
- package/node_modules/@herbertgao/sol-pi/THIRD_PARTY_NOTICES.md +19 -0
- package/node_modules/@herbertgao/sol-pi/agents-install.md +150 -0
- package/node_modules/@herbertgao/sol-pi/assets/sol-pi-hero.png +0 -0
- package/node_modules/@herbertgao/sol-pi/docs/compatibility.md +69 -0
- package/node_modules/@herbertgao/sol-pi/docs/configuration.md +75 -0
- package/node_modules/@herbertgao/sol-pi/package.json +76 -0
- package/node_modules/@herbertgao/sol-pi/scripts/check-pi-compat.mjs +32 -0
- package/node_modules/@herbertgao/sol-pi/scripts/check-sol-pi-config.mjs +120 -0
- package/node_modules/@herbertgao/sol-pi/sol-pi.example.json +10 -0
- package/node_modules/@herbertgao/sol-pi/src/sol-pi/config.ts +135 -0
- package/node_modules/@herbertgao/sol-pi/src/sol-pi/extensions/action-fusion/file-queue.ts +74 -0
- package/node_modules/@herbertgao/sol-pi/src/sol-pi/extensions/action-fusion/index.ts +185 -0
- package/node_modules/@herbertgao/sol-pi/src/sol-pi/extensions/action-fusion/then-run.ts +128 -0
- package/node_modules/@herbertgao/sol-pi/src/sol-pi/extensions/evidence-preserving-reducer/archive.ts +53 -0
- package/node_modules/@herbertgao/sol-pi/src/sol-pi/extensions/evidence-preserving-reducer/candidate.ts +101 -0
- package/node_modules/@herbertgao/sol-pi/src/sol-pi/extensions/evidence-preserving-reducer/config.ts +71 -0
- package/node_modules/@herbertgao/sol-pi/src/sol-pi/extensions/evidence-preserving-reducer/index.ts +220 -0
- package/node_modules/@herbertgao/sol-pi/src/sol-pi/extensions/evidence-preserving-reducer/journal.ts +25 -0
- package/node_modules/@herbertgao/sol-pi/src/sol-pi/extensions/evidence-preserving-reducer/provider.ts +164 -0
- package/node_modules/@herbertgao/sol-pi/src/sol-pi/extensions/evidence-preserving-reducer/receipt.ts +177 -0
- package/node_modules/@herbertgao/sol-pi/src/sol-pi/extensions/observation-pack/index.ts +227 -0
- package/node_modules/@herbertgao/sol-pi/src/sol-pi/extensions/observation-pack/ledger.ts +20 -0
- package/node_modules/@herbertgao/sol-pi/src/sol-pi/extensions/observation-pack/observation.ts +252 -0
- package/node_modules/@herbertgao/sol-pi/src/sol-pi/extensions/online-context-compact/economics.ts +237 -0
- package/node_modules/@herbertgao/sol-pi/src/sol-pi/extensions/online-context-compact/extension.ts +455 -0
- package/node_modules/@herbertgao/sol-pi/src/sol-pi/extensions/online-context-compact/index.ts +49 -0
- package/node_modules/@herbertgao/sol-pi/src/sol-pi/extensions/online-context-compact/plan.ts +79 -0
- package/node_modules/@herbertgao/sol-pi/src/sol-pi/extensions/online-context-compact/state.ts +208 -0
- package/node_modules/@herbertgao/sol-pi/src/sol-pi/extensions/online-context-compact/tools.ts +100 -0
- package/node_modules/@herbertgao/sol-pi/src/sol-pi/index.ts +42 -0
- package/node_modules/@herbertgao/sol-pi/src/sol-pi/runtime-paths.ts +17 -0
- package/node_modules/@herbertgao/sol-pi/src/sol-pi/tui.ts +71 -0
- package/node_modules/@narumitw/pi-btw/README.md +57 -141
- package/node_modules/@narumitw/pi-btw/dist/index.ts +478 -43
- package/node_modules/@narumitw/pi-btw/dist/index.ts.map +4 -4
- package/node_modules/@narumitw/pi-btw/docs/workflows.md +74 -0
- package/node_modules/@narumitw/pi-btw/package.json +2 -1
- package/node_modules/@narumitw/pi-btw/src/btw.ts +28 -3
- package/node_modules/@narumitw/pi-btw/src/fullscreen-ui.ts +32 -2
- package/node_modules/@narumitw/pi-btw/src/keybindings.ts +330 -0
- package/node_modules/@narumitw/pi-btw/src/menu.ts +136 -19
- package/node_modules/@narumitw/pi-btw/src/settings.ts +32 -0
- package/node_modules/@narumitw/pi-btw/src/side-thread.ts +57 -5
- package/node_modules/@narumitw/pi-btw/src/transcript-pager.ts +52 -30
- package/node_modules/pi-lens/CHANGELOG.md +260 -0
- package/node_modules/pi-lens/README.md +13 -8
- package/node_modules/pi-lens/config/dependency-cruiser-eager-allowlist.json +3 -1
- package/node_modules/pi-lens/dist/clients/actionable-warnings-logger.js +0 -7
- package/node_modules/pi-lens/dist/clients/advisory-provenance.js +1 -1
- package/node_modules/pi-lens/dist/clients/analysed-root.js +1 -0
- package/node_modules/pi-lens/dist/clients/ast-grep-client.js +1 -1
- package/node_modules/pi-lens/dist/clients/ast-grep-tool-logger.js +1 -8
- package/node_modules/pi-lens/dist/clients/ast-grep-types.js +2 -0
- package/node_modules/pi-lens/dist/clients/bash-file-access.js +133 -1
- package/node_modules/pi-lens/dist/clients/biome-client.js +13 -2
- package/node_modules/pi-lens/dist/clients/blocker-freshness.js +0 -6
- package/node_modules/pi-lens/dist/clients/bootstrap.js +4 -4
- package/node_modules/pi-lens/dist/clients/bounded-pid-file-lock.js +1 -1
- package/node_modules/pi-lens/dist/clients/bounded-telemetry.js +2 -5
- package/node_modules/pi-lens/dist/clients/bus-events-logger.js +1 -9
- package/node_modules/pi-lens/dist/clients/cache-observability.js +122 -6
- package/node_modules/pi-lens/dist/clients/cargo-manifest.js +2 -2
- package/node_modules/pi-lens/dist/clients/cascade-logger.js +0 -7
- package/node_modules/pi-lens/dist/clients/child-unref.js +1 -19
- package/node_modules/pi-lens/dist/clients/complexity-client.js +5 -0
- package/node_modules/pi-lens/dist/clients/config-core/index.js +11 -8
- package/node_modules/pi-lens/dist/clients/config-core/process-spec.js +1 -1
- package/node_modules/pi-lens/dist/clients/config-core/provenance.js +2 -9
- package/node_modules/pi-lens/dist/clients/config-core/records.js +1 -1
- package/node_modules/pi-lens/dist/clients/config-core/schema.js +3 -5
- package/node_modules/pi-lens/dist/clients/config-diagnostic-codes.js +3 -1
- package/node_modules/pi-lens/dist/clients/config-resolve.js +10 -7
- package/node_modules/pi-lens/dist/clients/config-schema.js +56 -2
- package/node_modules/pi-lens/dist/clients/config-warn.js +2 -2
- package/node_modules/pi-lens/dist/clients/dead-code-client.js +8 -1
- package/node_modules/pi-lens/dist/clients/dead-code-logger.js +0 -4
- package/node_modules/pi-lens/dist/clients/dependency-checker.js +5 -1
- package/node_modules/pi-lens/dist/clients/diagnostic-dispositions.js +1 -1
- package/node_modules/pi-lens/dist/clients/diagnostic-logger.js +1 -1
- package/node_modules/pi-lens/dist/clients/dispatch/collect-later-tier.js +0 -4
- package/node_modules/pi-lens/dist/clients/dispatch/dispatcher.js +38 -41
- package/node_modules/pi-lens/dist/clients/dispatch/facts/function-facts.js +1 -1
- package/node_modules/pi-lens/dist/clients/dispatch/facts/import-facts.js +5 -1
- package/node_modules/pi-lens/dist/clients/dispatch/integration.js +18 -1
- package/node_modules/pi-lens/dist/clients/dispatch/lazy.js +0 -6
- package/node_modules/pi-lens/dist/clients/dispatch/pending-runner-findings.js +1 -1
- package/node_modules/pi-lens/dist/clients/dispatch/plan.js +0 -3
- package/node_modules/pi-lens/dist/clients/dispatch/rules/high-complexity.js +2 -2
- package/node_modules/pi-lens/dist/clients/dispatch/rules/high-fan-out.js +1 -1
- package/node_modules/pi-lens/dist/clients/dispatch/runners/actionlint.js +2 -1
- package/node_modules/pi-lens/dist/clients/dispatch/runners/ast-grep-napi.js +3 -1
- package/node_modules/pi-lens/dist/clients/dispatch/runners/biome-check.js +2 -3
- package/node_modules/pi-lens/dist/clients/dispatch/runners/cpp-check.js +7 -2
- package/node_modules/pi-lens/dist/clients/dispatch/runners/credo.js +2 -1
- package/node_modules/pi-lens/dist/clients/dispatch/runners/cue-vet.js +2 -1
- package/node_modules/pi-lens/dist/clients/dispatch/runners/dart-analyze.js +2 -1
- package/node_modules/pi-lens/dist/clients/dispatch/runners/detekt.js +2 -1
- package/node_modules/pi-lens/dist/clients/dispatch/runners/dotnet-build.js +2 -1
- package/node_modules/pi-lens/dist/clients/dispatch/runners/elixir-check.js +2 -1
- package/node_modules/pi-lens/dist/clients/dispatch/runners/eslint.js +2 -1
- package/node_modules/pi-lens/dist/clients/dispatch/runners/fish-indent.js +2 -1
- package/node_modules/pi-lens/dist/clients/dispatch/runners/gleam-check.js +2 -1
- package/node_modules/pi-lens/dist/clients/dispatch/runners/go-vet.js +2 -1
- package/node_modules/pi-lens/dist/clients/dispatch/runners/golangci-lint.js +2 -1
- package/node_modules/pi-lens/dist/clients/dispatch/runners/hadolint.js +2 -1
- package/node_modules/pi-lens/dist/clients/dispatch/runners/helm-lint.js +3 -1
- package/node_modules/pi-lens/dist/clients/dispatch/runners/helm-render.js +3 -2
- package/node_modules/pi-lens/dist/clients/dispatch/runners/htmlhint.js +2 -1
- package/node_modules/pi-lens/dist/clients/dispatch/runners/javac.js +2 -1
- package/node_modules/pi-lens/dist/clients/dispatch/runners/ktlint.js +2 -1
- package/node_modules/pi-lens/dist/clients/dispatch/runners/lsp.js +19 -1
- package/node_modules/pi-lens/dist/clients/dispatch/runners/markdownlint.js +3 -2
- package/node_modules/pi-lens/dist/clients/dispatch/runners/mypy.js +2 -1
- package/node_modules/pi-lens/dist/clients/dispatch/runners/oxlint.js +3 -1
- package/node_modules/pi-lens/dist/clients/dispatch/runners/php-lint.js +2 -1
- package/node_modules/pi-lens/dist/clients/dispatch/runners/phpstan.js +2 -1
- package/node_modules/pi-lens/dist/clients/dispatch/runners/prisma-validate.js +2 -1
- package/node_modules/pi-lens/dist/clients/dispatch/runners/psscriptanalyzer.js +15 -11
- package/node_modules/pi-lens/dist/clients/dispatch/runners/pyright.js +2 -1
- package/node_modules/pi-lens/dist/clients/dispatch/runners/rubocop.js +2 -1
- package/node_modules/pi-lens/dist/clients/dispatch/runners/ruff.js +3 -3
- package/node_modules/pi-lens/dist/clients/dispatch/runners/rust-clippy.js +12 -11
- package/node_modules/pi-lens/dist/clients/dispatch/runners/shellcheck.js +3 -2
- package/node_modules/pi-lens/dist/clients/dispatch/runners/shfmt.js +2 -1
- package/node_modules/pi-lens/dist/clients/dispatch/runners/spellcheck.js +5 -3
- package/node_modules/pi-lens/dist/clients/dispatch/runners/spotbugs.js +2 -1
- package/node_modules/pi-lens/dist/clients/dispatch/runners/sqlfluff.js +3 -2
- package/node_modules/pi-lens/dist/clients/dispatch/runners/stylelint.js +3 -2
- package/node_modules/pi-lens/dist/clients/dispatch/runners/swiftlint.js +2 -1
- package/node_modules/pi-lens/dist/clients/dispatch/runners/taplo.js +2 -1
- package/node_modules/pi-lens/dist/clients/dispatch/runners/terragrunt.js +2 -1
- package/node_modules/pi-lens/dist/clients/dispatch/runners/tflint.js +2 -1
- package/node_modules/pi-lens/dist/clients/dispatch/runners/trivy-config.js +2 -1
- package/node_modules/pi-lens/dist/clients/dispatch/runners/utils/availability-policy.js +5 -0
- package/node_modules/pi-lens/dist/clients/dispatch/runners/utils/candidate-probe.js +2 -2
- package/node_modules/pi-lens/dist/clients/dispatch/runners/utils/diagnostic-parsers.js +1 -64
- package/node_modules/pi-lens/dist/clients/dispatch/runners/utils/runner-helpers.js +8 -2
- package/node_modules/pi-lens/dist/clients/dispatch/runners/utils.js +0 -21
- package/node_modules/pi-lens/dist/clients/dispatch/runners/vale.js +2 -1
- package/node_modules/pi-lens/dist/clients/dispatch/runners/yaml-rule-parser.js +2 -20
- package/node_modules/pi-lens/dist/clients/dispatch/runners/yamllint.js +5 -3
- package/node_modules/pi-lens/dist/clients/dispatch/runners/zig-check.js +2 -1
- package/node_modules/pi-lens/dist/clients/dispatch/utils/format-utils.js +2 -2
- package/node_modules/pi-lens/dist/clients/disposition-logger.js +0 -7
- package/node_modules/pi-lens/dist/clients/effective-config.js +12 -2
- package/node_modules/pi-lens/dist/clients/event-loop-monitor.js +2 -2
- package/node_modules/pi-lens/dist/clients/extension-log.js +2 -0
- package/node_modules/pi-lens/dist/clients/file-kinds.js +1 -38
- package/node_modules/pi-lens/dist/clients/file-role.js +18 -1
- package/node_modules/pi-lens/dist/clients/file-time.js +1 -1
- package/node_modules/pi-lens/dist/clients/file-utils.js +5 -1
- package/node_modules/pi-lens/dist/clients/finding-delivery-gate.js +4 -0
- package/node_modules/pi-lens/dist/clients/format-service.js +0 -1
- package/node_modules/pi-lens/dist/clients/formatters.js +66 -93
- package/node_modules/pi-lens/dist/clients/generated-artifacts.js +3 -4
- package/node_modules/pi-lens/dist/clients/generation-guard.js +4 -0
- package/node_modules/pi-lens/dist/clients/git-guard.js +5 -0
- package/node_modules/pi-lens/dist/clients/gitleaks-client.js +42 -6
- package/node_modules/pi-lens/dist/clients/govulncheck-client.js +48 -7
- package/node_modules/pi-lens/dist/clients/grammar-source.js +3 -3
- package/node_modules/pi-lens/dist/clients/installer/index.js +416 -61
- package/node_modules/pi-lens/dist/clients/installer/managed-tool-refresh.js +84 -18
- package/node_modules/pi-lens/dist/clients/instance-reaper.js +6 -6
- package/node_modules/pi-lens/dist/clients/jscpd-client.js +9 -1
- package/node_modules/pi-lens/dist/clients/knip-client.js +9 -2
- package/node_modules/pi-lens/dist/clients/language-profile.js +12 -11
- package/node_modules/pi-lens/dist/clients/language-registry.js +5 -1
- package/node_modules/pi-lens/dist/clients/latency-logger.js +7 -7
- package/node_modules/pi-lens/dist/clients/ledger-bounds.js +21 -1
- package/node_modules/pi-lens/dist/clients/lens-config.js +23 -0
- package/node_modules/pi-lens/dist/clients/lens-engine.js +3 -4
- package/node_modules/pi-lens/dist/clients/lens-events.js +1 -1
- package/node_modules/pi-lens/dist/clients/lens-flag-registry.js +18 -0
- package/node_modules/pi-lens/dist/clients/lens-map.js +1 -1
- package/node_modules/pi-lens/dist/clients/log-cleanup.js +0 -36
- package/node_modules/pi-lens/dist/clients/lsp/client.js +4 -3
- package/node_modules/pi-lens/dist/clients/lsp/config.js +37 -7
- package/node_modules/pi-lens/dist/clients/lsp/diagnostic-binding.js +24 -1
- package/node_modules/pi-lens/dist/clients/lsp/document-drift.js +79 -1
- package/node_modules/pi-lens/dist/clients/lsp/edits.js +3 -3
- package/node_modules/pi-lens/dist/clients/lsp/index.js +491 -64
- package/node_modules/pi-lens/dist/clients/lsp/inferred-project.js +1 -1
- package/node_modules/pi-lens/dist/clients/lsp/language.js +0 -8
- package/node_modules/pi-lens/dist/clients/lsp/path-utils.js +1 -1
- package/node_modules/pi-lens/dist/clients/lsp/pending-aux-coverage.js +0 -2
- package/node_modules/pi-lens/dist/clients/lsp/server.js +62 -15
- package/node_modules/pi-lens/dist/clients/lsp/sync-kind.js +0 -1
- package/node_modules/pi-lens/dist/clients/lsp/tsserver-sync.js +5 -5
- package/node_modules/pi-lens/dist/clients/lsp/wait-policy/classification.js +6 -0
- package/node_modules/pi-lens/dist/clients/lsp/wait-policy/strategies.js +2 -1
- package/node_modules/pi-lens/dist/clients/lsp/workspace-diagnostics-cache.js +37 -4
- package/node_modules/pi-lens/dist/clients/lsp-document-symbols.js +1 -1
- package/node_modules/pi-lens/dist/clients/mcp/analyze.js +3 -0
- package/node_modules/pi-lens/dist/clients/mcp/session.js +2 -0
- package/node_modules/pi-lens/dist/clients/metrics-history.js +28 -107
- package/node_modules/pi-lens/dist/clients/middle-man-analysis.js +1 -1
- package/node_modules/pi-lens/dist/clients/module-report.js +1 -1
- package/node_modules/pi-lens/dist/clients/mutating-tool.js +3 -3
- package/node_modules/pi-lens/dist/clients/mutation-attribution.js +3 -3
- package/node_modules/pi-lens/dist/clients/ndjson-logger.js +0 -4
- package/node_modules/pi-lens/dist/clients/observed-mutation.js +9 -9
- package/node_modules/pi-lens/dist/clients/opaque-mutation-scan.js +2 -6
- package/node_modules/pi-lens/dist/clients/opengrep-client.js +2 -0
- package/node_modules/pi-lens/dist/clients/opengrep-config.js +1 -1
- package/node_modules/pi-lens/dist/clients/package-manager.js +2 -1
- package/node_modules/pi-lens/dist/clients/path-utils.js +23 -2
- package/node_modules/pi-lens/dist/clients/performance-report.js +2 -2
- package/node_modules/pi-lens/dist/clients/php-cs-fixer-config.js +9 -4
- package/node_modules/pi-lens/dist/clients/pipeline.js +5 -4
- package/node_modules/pi-lens/dist/clients/project-changes.js +1 -1
- package/node_modules/pi-lens/dist/clients/project-diagnostics/extractors.js +1 -1
- package/node_modules/pi-lens/dist/clients/project-diagnostics/fresh-fetch.js +38 -10
- package/node_modules/pi-lens/dist/clients/project-diagnostics/runner-adapters/gitleaks.js +10 -9
- package/node_modules/pi-lens/dist/clients/project-diagnostics/runner-adapters/jscpd.js +1 -1
- package/node_modules/pi-lens/dist/clients/project-diagnostics/runner-adapters/knip.js +1 -1
- package/node_modules/pi-lens/dist/clients/project-diagnostics/runner-adapters/madge.js +1 -1
- package/node_modules/pi-lens/dist/clients/project-diagnostics/runner-adapters/opengrep.js +1 -1
- package/node_modules/pi-lens/dist/clients/project-diagnostics/runner-adapters/runner-findings.js +1 -1
- package/node_modules/pi-lens/dist/clients/project-lens-config.js +49 -1
- package/node_modules/pi-lens/dist/clients/project-scan-policy.js +3 -51
- package/node_modules/pi-lens/dist/clients/python-provenance.js +1 -1
- package/node_modules/pi-lens/dist/clients/read-guard-logger.js +3 -1
- package/node_modules/pi-lens/dist/clients/read-guard.js +5 -2
- package/node_modules/pi-lens/dist/clients/recent-touches.js +2 -2
- package/node_modules/pi-lens/dist/clients/review-graph/builder.js +3 -5
- package/node_modules/pi-lens/dist/clients/review-graph/import-resolvers.js +1 -1
- package/node_modules/pi-lens/dist/clients/review-graph-logger.js +2 -0
- package/node_modules/pi-lens/dist/clients/ruff-client.js +18 -9
- package/node_modules/pi-lens/dist/clients/runtime-agent-end.js +10 -1
- package/node_modules/pi-lens/dist/clients/runtime-coordinator.js +5 -0
- package/node_modules/pi-lens/dist/clients/runtime-session.js +58 -14
- package/node_modules/pi-lens/dist/clients/runtime-tool-call.js +11 -1
- package/node_modules/pi-lens/dist/clients/runtime-tool-result.js +4 -1
- package/node_modules/pi-lens/dist/clients/runtime-turn.js +48 -1
- package/node_modules/pi-lens/dist/clients/sanitize.js +0 -11
- package/node_modules/pi-lens/dist/clients/scan-utils.js +1 -56
- package/node_modules/pi-lens/dist/clients/security-scan-client.js +2 -2
- package/node_modules/pi-lens/dist/clients/session-event-guard.js +69 -1
- package/node_modules/pi-lens/dist/clients/session-summary.js +0 -24
- package/node_modules/pi-lens/dist/clients/sg-runner.js +2 -1
- package/node_modules/pi-lens/dist/clients/sgconfig.js +1 -5
- package/node_modules/pi-lens/dist/clients/shared-checkout-guard.js +1 -1
- package/node_modules/pi-lens/dist/clients/situational-tool-telemetry.js +108 -0
- package/node_modules/pi-lens/dist/clients/smells-rollup.js +2 -2
- package/node_modules/pi-lens/dist/clients/startup-scan.js +2 -10
- package/node_modules/pi-lens/dist/clients/test-runner-client.js +291 -76
- package/node_modules/pi-lens/dist/clients/test-runner-delivery.js +77 -72
- package/node_modules/pi-lens/dist/clients/tool-config.js +199 -0
- package/node_modules/pi-lens/dist/clients/tool-cwd.js +299 -0
- package/node_modules/pi-lens/dist/clients/tool-policy.js +1 -1
- package/node_modules/pi-lens/dist/clients/tool-probe.js +53 -0
- package/node_modules/pi-lens/dist/clients/tool-set-policy.js +42 -0
- package/node_modules/pi-lens/dist/clients/tree-sitter-client.js +1 -52
- package/node_modules/pi-lens/dist/clients/trivy-client.js +9 -1
- package/node_modules/pi-lens/dist/clients/tui-fit.js +0 -4
- package/node_modules/pi-lens/dist/clients/turn-context.js +52 -0
- package/node_modules/pi-lens/dist/clients/user-notify.js +0 -4
- package/node_modules/pi-lens/dist/clients/widget-state.js +4 -3
- package/node_modules/pi-lens/dist/clients/word-index-logger.js +0 -7
- package/node_modules/pi-lens/dist/clients/word-index-store.js +3 -7
- package/node_modules/pi-lens/dist/clients/word-index.js +9 -16
- package/node_modules/pi-lens/dist/clients/zizmor-config.js +1 -1
- package/node_modules/pi-lens/dist/index.js +19969 -17481
- package/node_modules/pi-lens/dist/mcp/analyze-cli.js +3 -2
- package/node_modules/pi-lens/dist/mcp/build-staleness.js +1 -1
- package/node_modules/pi-lens/dist/mcp/server.js +135 -159
- package/node_modules/pi-lens/dist/scripts/lib/process-scan.mjs +1 -1
- package/node_modules/pi-lens/dist/scripts/lib/skills-predicate.mjs +1 -1
- package/node_modules/pi-lens/dist/tools/activate-tools.js +10 -7
- package/node_modules/pi-lens/dist/tools/ast-grep-outline.js +2 -13
- package/node_modules/pi-lens/dist/tools/ast-grep-replace.js +8 -13
- package/node_modules/pi-lens/dist/tools/ast-grep-search.js +83 -39
- package/node_modules/pi-lens/dist/tools/effective-config.js +4 -3
- package/node_modules/pi-lens/dist/tools/lens-diagnostic-mark.js +1 -10
- package/node_modules/pi-lens/dist/tools/lens-diagnostics.js +354 -86
- package/node_modules/pi-lens/dist/tools/lsp-diagnostics.js +54 -112
- package/node_modules/pi-lens/dist/tools/lsp-navigation.js +20 -44
- package/node_modules/pi-lens/dist/tools/lsp-structured-output.js +3 -3
- package/node_modules/pi-lens/dist/tools/module-report.js +5 -9
- package/node_modules/pi-lens/dist/tools/project-report.js +9 -17
- package/node_modules/pi-lens/dist/tools/render-compact.js +281 -2
- package/node_modules/pi-lens/dist/tools/symbol-search.js +3 -4
- package/node_modules/pi-lens/docs/agent-guide.md +3 -4
- package/node_modules/pi-lens/docs/agent-tools.md +46 -22
- package/node_modules/pi-lens/docs/configuration.md +9 -0
- package/node_modules/pi-lens/docs/environment-variables.md +0 -5
- package/node_modules/pi-lens/docs/features.md +5 -5
- package/node_modules/pi-lens/docs/globalconfig.md +31 -1
- package/node_modules/pi-lens/docs/lsp-capability-matrix.md +9 -1
- package/node_modules/pi-lens/docs/mcp.md +13 -1
- package/node_modules/pi-lens/docs/pi-lens-fixer.md +71 -0
- package/node_modules/pi-lens/docs/pi-lens-investigator.md +15 -0
- package/node_modules/pi-lens/docs/pi-lens-monitor.md +88 -0
- package/node_modules/pi-lens/docs/pi-lens-reviewer.md +41 -0
- package/node_modules/pi-lens/docs/pi-lens-subagent.md +21 -2
- package/node_modules/pi-lens/docs/public-api-stability.md +1 -0
- package/node_modules/pi-lens/docs/real-harness.md +46 -0
- package/node_modules/pi-lens/docs/release-qa-baseline.md +17 -5
- package/node_modules/pi-lens/docs/servercapabilities.md +2 -3
- package/node_modules/pi-lens/docs/settings.md +37 -2
- package/node_modules/pi-lens/docs/tools_improvement2.md +4 -4
- package/node_modules/pi-lens/docs/tree-sitter_rules_catalog.md +1 -1
- package/node_modules/pi-lens/docs/usage.md +13 -3
- package/node_modules/pi-lens/docs/word-index.md +1 -1
- package/node_modules/pi-lens/package.json +15 -15
- package/node_modules/pi-lens/rules/tree-sitter-queries/typescript/sql-injection.yml +7 -3
- package/node_modules/pi-lens/rules/typos/_typos.toml +4 -2
- package/node_modules/pi-lens/scripts/lib/skills-predicate.mjs +1 -1
- package/node_modules/pi-lens/scripts/lib/warm-loader-cache.mjs +1 -1
- package/node_modules/pi-lens/scripts/warm-loader-cache.mjs +4 -2
- package/node_modules/pi-lens/skills/pi-lens-ast-grep/SKILL.md +8 -6
- package/node_modules/pi-lens/skills/pi-lens-lsp-navigation/SKILL.md +19 -9
- package/node_modules/pi-web-access/CHANGELOG.md +29 -0
- package/node_modules/pi-web-access/README.md +33 -22
- package/node_modules/pi-web-access/abortable.ts +17 -0
- package/node_modules/pi-web-access/crawl4ai.ts +204 -0
- package/node_modules/pi-web-access/credential-source.ts +1 -0
- package/node_modules/pi-web-access/curator-page.ts +20 -2
- package/node_modules/pi-web-access/curator-run.ts +44 -0
- package/node_modules/pi-web-access/curator-server.ts +3 -1
- package/node_modules/pi-web-access/duckduckgo.ts +1 -1
- package/node_modules/pi-web-access/extract.ts +57 -12
- package/node_modules/pi-web-access/fetch-params.ts +1 -1
- package/node_modules/pi-web-access/gemini-search.ts +9 -5
- package/node_modules/pi-web-access/index.ts +25 -18
- package/node_modules/pi-web-access/openai-search.ts +35 -13
- package/node_modules/pi-web-access/package.json +2 -2
- package/node_modules/pi-web-access/page-query.ts +5 -2
- package/node_modules/pi-web-access/query-rewrite.ts +5 -2
- package/node_modules/pi-web-access/serpapi.ts +220 -0
- package/node_modules/pi-web-access/ssrf-protection.ts +5 -1
- package/node_modules/pi-web-access/storage.ts +10 -0
- package/node_modules/pi-web-access/summary-review.ts +34 -21
- package/node_modules/pi-web-access/utils.ts +6 -4
- package/package.json +7 -4
- package/node_modules/pi-lens/dist/tools/ast-dump.js +0 -103
|
@@ -66,6 +66,7 @@ import { commitDurableStoreAsync } from "../durable-store.js";
|
|
|
66
66
|
import { getGlobalPiLensDir } from "../file-utils.js";
|
|
67
67
|
import { allAvailableGlobalBinDirs, installArgs, pmBinary, resolveNodePackageManager, } from "../package-manager.js";
|
|
68
68
|
import { resetSafeSpawnWindowsCommandCache, safeSpawnAsync, } from "../safe-spawn.js";
|
|
69
|
+
import { probeToolAsync } from "../tool-probe.js";
|
|
69
70
|
import { logSessionStart } from "../sessionstart-logger.js";
|
|
70
71
|
// Global installation directory for pi-lens tools
|
|
71
72
|
const TOOLS_DIR = path.join(getGlobalPiLensDir(), "tools");
|
|
@@ -227,6 +228,114 @@ const OS_ARCH_ZIP_ASSETS = {
|
|
|
227
228
|
darwin: { x64: "darwin_amd64.zip", arm64: "darwin_arm64.zip" },
|
|
228
229
|
win32: { x64: "windows_amd64.zip", arm64: "windows_arm64.zip" },
|
|
229
230
|
};
|
|
231
|
+
function managedPackageFormatterTool(spec) {
|
|
232
|
+
return {
|
|
233
|
+
id: spec.id,
|
|
234
|
+
name: spec.name,
|
|
235
|
+
checkCommand: spec.id,
|
|
236
|
+
checkArgs: ["--version"],
|
|
237
|
+
installStrategy: spec.installStrategy,
|
|
238
|
+
packageName: spec.packageName,
|
|
239
|
+
binaryName: spec.id,
|
|
240
|
+
};
|
|
241
|
+
}
|
|
242
|
+
const MANAGED_PACKAGE_FORMATTERS = [
|
|
243
|
+
{ id: "black", name: "Black", installStrategy: "pip", packageName: "black" },
|
|
244
|
+
{
|
|
245
|
+
id: "cmake-format",
|
|
246
|
+
name: "cmake-format",
|
|
247
|
+
installStrategy: "pip",
|
|
248
|
+
packageName: "cmakelang",
|
|
249
|
+
},
|
|
250
|
+
{ id: "oxfmt", name: "oxfmt", installStrategy: "npm", packageName: "oxfmt" },
|
|
251
|
+
];
|
|
252
|
+
function managedGitHubFormatterTool(spec) {
|
|
253
|
+
return {
|
|
254
|
+
id: spec.id,
|
|
255
|
+
name: spec.name,
|
|
256
|
+
checkCommand: spec.id,
|
|
257
|
+
checkArgs: ["--version"],
|
|
258
|
+
installStrategy: "github",
|
|
259
|
+
binaryName: spec.id,
|
|
260
|
+
github: {
|
|
261
|
+
repo: `${spec.owner}/${spec.repo}`,
|
|
262
|
+
assetMatch: spec.assetPattern,
|
|
263
|
+
...(spec.binaryInArchive && { binaryInArchive: spec.binaryInArchive }),
|
|
264
|
+
...(spec.kind === "phar" && { launcher: "php" }),
|
|
265
|
+
...(spec.kind === "jar" && { launcher: "java" }),
|
|
266
|
+
},
|
|
267
|
+
};
|
|
268
|
+
}
|
|
269
|
+
const MANAGED_GITHUB_FORMATTERS = [
|
|
270
|
+
{
|
|
271
|
+
id: "stylua",
|
|
272
|
+
name: "StyLua",
|
|
273
|
+
owner: "JohnnyMorganz",
|
|
274
|
+
repo: "StyLua",
|
|
275
|
+
assetPattern: archAssetMatch({
|
|
276
|
+
linux: { x64: "linux-x86_64.zip", arm64: "linux-aarch64.zip" },
|
|
277
|
+
darwin: { x64: "macos-x86_64.zip", arm64: "macos-aarch64.zip" },
|
|
278
|
+
win32: { x64: "windows-x86_64.zip" },
|
|
279
|
+
}),
|
|
280
|
+
kind: "binary",
|
|
281
|
+
binaryInArchive: "stylua",
|
|
282
|
+
},
|
|
283
|
+
{
|
|
284
|
+
id: "php-cs-fixer",
|
|
285
|
+
name: "PHP CS Fixer",
|
|
286
|
+
owner: "PHP-CS-Fixer",
|
|
287
|
+
repo: "PHP-CS-Fixer",
|
|
288
|
+
assetPattern: (platform) => platform === "linux" || platform === "darwin" || platform === "win32"
|
|
289
|
+
? "php-cs-fixer.phar"
|
|
290
|
+
: undefined,
|
|
291
|
+
kind: "phar",
|
|
292
|
+
},
|
|
293
|
+
{
|
|
294
|
+
id: "cljfmt",
|
|
295
|
+
name: "cljfmt",
|
|
296
|
+
owner: "weavejester",
|
|
297
|
+
repo: "cljfmt",
|
|
298
|
+
assetPattern: (platform, arch) => {
|
|
299
|
+
if (platform === "linux")
|
|
300
|
+
return arch === "arm64"
|
|
301
|
+
? "standalone.jar"
|
|
302
|
+
: "linux-amd64-static.tar.gz";
|
|
303
|
+
if (platform === "darwin")
|
|
304
|
+
return "standalone.jar";
|
|
305
|
+
if (platform === "win32")
|
|
306
|
+
return "win-amd64.zip";
|
|
307
|
+
return undefined;
|
|
308
|
+
},
|
|
309
|
+
kind: "jar",
|
|
310
|
+
binaryInArchive: "cljfmt",
|
|
311
|
+
},
|
|
312
|
+
];
|
|
313
|
+
const MANAGED_MAVEN_FORMATTERS = [
|
|
314
|
+
{
|
|
315
|
+
id: "google-java-format",
|
|
316
|
+
name: "google-java-format",
|
|
317
|
+
groupId: "com.google.googlejavaformat",
|
|
318
|
+
artifactId: "google-java-format",
|
|
319
|
+
version: "1.27.0",
|
|
320
|
+
classifier: "all-deps",
|
|
321
|
+
},
|
|
322
|
+
];
|
|
323
|
+
function managedMavenFormatterTool(spec) {
|
|
324
|
+
return {
|
|
325
|
+
id: spec.id,
|
|
326
|
+
name: spec.name,
|
|
327
|
+
checkCommand: spec.id,
|
|
328
|
+
checkArgs: ["--version"],
|
|
329
|
+
installStrategy: "maven",
|
|
330
|
+
binaryName: spec.id,
|
|
331
|
+
maven: {
|
|
332
|
+
groupId: spec.groupId,
|
|
333
|
+
artifactId: spec.artifactId,
|
|
334
|
+
version: spec.version,
|
|
335
|
+
classifier: spec.classifier,
|
|
336
|
+
},
|
|
337
|
+
};
|
|
338
|
+
}
|
|
230
339
|
export const TOOLS = [
|
|
231
340
|
// Core LSP servers
|
|
232
341
|
{
|
|
@@ -275,6 +384,7 @@ export const TOOLS = [
|
|
|
275
384
|
packageName: "prettier",
|
|
276
385
|
binaryName: "prettier",
|
|
277
386
|
},
|
|
387
|
+
...MANAGED_PACKAGE_FORMATTERS.map(managedPackageFormatterTool),
|
|
278
388
|
{
|
|
279
389
|
id: "ruff",
|
|
280
390
|
name: "Ruff",
|
|
@@ -548,10 +658,27 @@ export const TOOLS = [
|
|
|
548
658
|
binaryName: "docker-langserver",
|
|
549
659
|
},
|
|
550
660
|
{
|
|
661
|
+
// #2722: intelephense has no CLI — its entry calls createConnection()
|
|
662
|
+
// unconditionally — and Node prints the offending source line before the
|
|
663
|
+
// error. The bundle is one ~4 MB minified line, so the transport-required
|
|
664
|
+
// marker #208 rescues on lands at byte 4,154,741 of a 4,423,356-byte
|
|
665
|
+
// stderr while Node truncates piped stderr at 1 MiB on exit. Measured on
|
|
666
|
+
// intelephense@1.18.5, linux, Node v22.22.1:
|
|
667
|
+
// $ intelephense --version 2>&1 | wc -c -> 1048576
|
|
668
|
+
// $ intelephense --version 2>&1 | grep -c "Connection input stream is not set" -> 0
|
|
669
|
+
// $ intelephense --version 2>err.txt; wc -c < err.txt -> 4423356
|
|
670
|
+
// Same run over the alternatives, each with stdin closed the way
|
|
671
|
+
// verifyToolBinary closes it (`input: ""`):
|
|
672
|
+
// --help, -v, --socket=0 -> identical dump (exit 1, 4423356 bytes,
|
|
673
|
+
// marker at 4154741, 1048576 through a pipe, marker absent)
|
|
674
|
+
// --stdio -> exit 1 with ZERO bytes on either stream,
|
|
675
|
+
// so it carries no marker to rescue on either.
|
|
676
|
+
// No checkArgs value produces a verdict. Verified spawn-free instead.
|
|
551
677
|
id: "intelephense",
|
|
552
678
|
name: "Intelephense",
|
|
553
679
|
checkCommand: "intelephense",
|
|
554
680
|
checkArgs: ["--version"],
|
|
681
|
+
verification: "package-entry",
|
|
555
682
|
installStrategy: "npm",
|
|
556
683
|
packageName: "intelephense",
|
|
557
684
|
binaryName: "intelephense",
|
|
@@ -690,6 +817,8 @@ export const TOOLS = [
|
|
|
690
817
|
// bare binary, no archive
|
|
691
818
|
},
|
|
692
819
|
},
|
|
820
|
+
...MANAGED_GITHUB_FORMATTERS.map(managedGitHubFormatterTool),
|
|
821
|
+
...MANAGED_MAVEN_FORMATTERS.map(managedMavenFormatterTool),
|
|
693
822
|
{
|
|
694
823
|
id: "rust-analyzer",
|
|
695
824
|
name: "rust-analyzer",
|
|
@@ -1616,29 +1745,16 @@ function isAstGrepVersionOutput(output) {
|
|
|
1616
1745
|
return /\bast[- ]grep\b/i.test(output);
|
|
1617
1746
|
}
|
|
1618
1747
|
async function verifyAstGrepProbePath(binPath) {
|
|
1619
|
-
|
|
1620
|
-
|
|
1621
|
-
|
|
1622
|
-
|
|
1623
|
-
|
|
1624
|
-
|
|
1625
|
-
timeout: 5000,
|
|
1626
|
-
});
|
|
1627
|
-
}
|
|
1628
|
-
catch {
|
|
1629
|
-
// SYNCHRONOUS spawn throw (Windows `spawn UNKNOWN`/EINVAL, the pidusage
|
|
1630
|
-
// bug class, #533) — best-effort probe, resolve rather than reject.
|
|
1631
|
-
resolve(false);
|
|
1632
|
-
return;
|
|
1633
|
-
}
|
|
1634
|
-
let output = "";
|
|
1635
|
-
proc.stdout?.on("data", (data) => (output += data));
|
|
1636
|
-
proc.stderr?.on("data", (data) => (output += data));
|
|
1637
|
-
proc.on("exit", (code) => {
|
|
1638
|
-
resolve(code === 0 && isAstGrepVersionOutput(output));
|
|
1639
|
-
});
|
|
1640
|
-
proc.on("error", () => resolve(false));
|
|
1748
|
+
// #2894: through the probe seam rather than a hand-rolled `spawn` promise.
|
|
1749
|
+
// `probeToolAsync` already owns the synchronous-throw case (#533), the
|
|
1750
|
+
// Windows `.cmd`/`.bat` resolution this used `shell: true` for, and the
|
|
1751
|
+
// timeout tree-kill a bare `spawn({ timeout })` does not do.
|
|
1752
|
+
const result = await probeToolAsync(binPath, ["--version"], {
|
|
1753
|
+
timeout: 5000,
|
|
1641
1754
|
});
|
|
1755
|
+
return (!result.error &&
|
|
1756
|
+
result.status === 0 &&
|
|
1757
|
+
isAstGrepVersionOutput(`${result.stdout}${result.stderr}`));
|
|
1642
1758
|
}
|
|
1643
1759
|
// Exported for testing only.
|
|
1644
1760
|
export async function checkProbeCache(toolId) {
|
|
@@ -1851,6 +1967,111 @@ function extractVersionToken(output) {
|
|
|
1851
1967
|
* maven/archive) never populate or read this map.
|
|
1852
1968
|
*/
|
|
1853
1969
|
const lastManagedInstallVersion = new Map();
|
|
1970
|
+
/**
|
|
1971
|
+
* The package whose entry module verifies `tool`'s managed install spawn-free,
|
|
1972
|
+
* or undefined when the tool is verified by spawning `checkArgs` (#2722).
|
|
1973
|
+
* Registry-declared per tool — never inferred from the strategy: a spawn probe
|
|
1974
|
+
* is the stronger check everywhere it can actually return a verdict.
|
|
1975
|
+
*/
|
|
1976
|
+
export function packageEntryVerification(tool) {
|
|
1977
|
+
return tool.verification === "package-entry" ? tool.packageName : undefined;
|
|
1978
|
+
}
|
|
1979
|
+
/**
|
|
1980
|
+
* Spawn-free verification of a managed npm install (#2722).
|
|
1981
|
+
*
|
|
1982
|
+
* For an stdio LSP server with no CLI surface, every `checkArgs` value is a
|
|
1983
|
+
* throw, and #208's transport-required rescue is output-ORDER dependent: Node
|
|
1984
|
+
* prints the offending source line ahead of the error, so a server whose bundle
|
|
1985
|
+
* is megabytes of minified JS pushes the marker past both our retained window
|
|
1986
|
+
* and Node's own 1 MiB pipe truncation. The bytes never leave the child, so no
|
|
1987
|
+
* spawn can answer "is this install intact".
|
|
1988
|
+
*
|
|
1989
|
+
* The evidence used instead is the same class the `archive` strategy already
|
|
1990
|
+
* accepts through `treeMarker`: the installed tree is inspected on disk. The
|
|
1991
|
+
* install verifies when the package directory beside the `.bin` shim carries a
|
|
1992
|
+
* readable `package.json` with a `version`, and the entry module that
|
|
1993
|
+
* package.json itself names — `bin[<shim name>]` or a bare `bin` string —
|
|
1994
|
+
* exists as a non-empty file. `main` is deliberately NOT a fallback: npm
|
|
1995
|
+
* creates the `node_modules/.bin/<shim>` this function is given only from a
|
|
1996
|
+
* `bin` field, so a manifest without one cannot be the manifest behind this
|
|
1997
|
+
* shim. That is exactly what `verifyToolBinary` was documented to catch here —
|
|
1998
|
+
* broken symlinks and partial installs — and it is strictly more than the
|
|
1999
|
+
* `--version` spawn can report for this class.
|
|
2000
|
+
*/
|
|
2001
|
+
export async function verifyNpmPackageEntry(binPath, packageName) {
|
|
2002
|
+
// `<...>/node_modules/.bin/<shim>` → `<...>/node_modules`.
|
|
2003
|
+
const nodeModulesDir = path.dirname(path.dirname(binPath));
|
|
2004
|
+
const pinned = parsePinnedVersion(packageName);
|
|
2005
|
+
const bareName = pinned
|
|
2006
|
+
? packageName.slice(0, -(pinned.length + 1))
|
|
2007
|
+
: packageName;
|
|
2008
|
+
const packageDir = path.join(nodeModulesDir, ...bareName.split("/"));
|
|
2009
|
+
const shimName = path
|
|
2010
|
+
.basename(binPath)
|
|
2011
|
+
.replace(/\.(cmd|exe|ps1|bat)$/i, "")
|
|
2012
|
+
.toLowerCase();
|
|
2013
|
+
const fail = (reason) => {
|
|
2014
|
+
logSessionStart(`auto-install verify: failed for ${binPath} (check=package-entry, kind=${reason})`);
|
|
2015
|
+
return false;
|
|
2016
|
+
};
|
|
2017
|
+
// R2-F1: the shim ITSELF, before anything else. Every path below is DERIVED
|
|
2018
|
+
// from `binPath`, so without this a partial install — npm never wrote the
|
|
2019
|
+
// `.bin` entry, or wrote one that is empty, a directory, or a symlink
|
|
2020
|
+
// dangling at a deleted target — verified `true` on the strength of a
|
|
2021
|
+
// package tree that nothing can execute, and `installNpmTool` then recorded
|
|
2022
|
+
// the install as SUCCEEDED. `classifyInstallOutcome` grades any non-"failed"
|
|
2023
|
+
// outcome as `⚠ unavailable (succeeded)`, so that answer re-hid exactly the
|
|
2024
|
+
// nightly row #2722 exists to expose. `statSync` FOLLOWS the link, which is
|
|
2025
|
+
// what makes missing and dangling one branch.
|
|
2026
|
+
try {
|
|
2027
|
+
const shim = statSync(binPath);
|
|
2028
|
+
if (!shim.isFile() || shim.size === 0)
|
|
2029
|
+
return fail("shim-not-a-file");
|
|
2030
|
+
}
|
|
2031
|
+
catch {
|
|
2032
|
+
return fail("shim-missing");
|
|
2033
|
+
}
|
|
2034
|
+
let manifest;
|
|
2035
|
+
try {
|
|
2036
|
+
manifest = JSON.parse(await fs.readFile(path.join(packageDir, "package.json"), "utf8"));
|
|
2037
|
+
}
|
|
2038
|
+
catch {
|
|
2039
|
+
return fail("package-json-unreadable");
|
|
2040
|
+
}
|
|
2041
|
+
if (typeof manifest.version !== "string" || !manifest.version) {
|
|
2042
|
+
return fail("package-json-no-version");
|
|
2043
|
+
}
|
|
2044
|
+
const bin = manifest.bin;
|
|
2045
|
+
const entry = typeof bin === "string"
|
|
2046
|
+
? bin
|
|
2047
|
+
: bin && typeof bin === "object"
|
|
2048
|
+
? Object.entries(bin).find(
|
|
2049
|
+
// Case-folded on purpose: on a case-insensitive filesystem the
|
|
2050
|
+
// shim on disk can differ in case from the manifest key npm
|
|
2051
|
+
// wrote it from, and `path.basename` reads the disk name.
|
|
2052
|
+
([name]) => name.toLowerCase() === shimName)?.[1]
|
|
2053
|
+
: undefined;
|
|
2054
|
+
if (typeof entry !== "string" || !entry) {
|
|
2055
|
+
return fail("package-json-no-entry");
|
|
2056
|
+
}
|
|
2057
|
+
try {
|
|
2058
|
+
const stat = statSync(path.join(packageDir, entry));
|
|
2059
|
+
if (!stat.isFile() || stat.size === 0)
|
|
2060
|
+
return fail("entry-not-a-file");
|
|
2061
|
+
}
|
|
2062
|
+
catch {
|
|
2063
|
+
return fail("entry-missing");
|
|
2064
|
+
}
|
|
2065
|
+
// R2-F3 (catalog shape 31): "did the new verifier run at all, and on what"
|
|
2066
|
+
// has to be answerable from sessionstart.log, not only from a debug build —
|
|
2067
|
+
// the failure branches above already log there. Measured volume on a real
|
|
2068
|
+
// intelephense install, scratch PI_LENS_HOME: TWO rows on the session that
|
|
2069
|
+
// installs (installNpmTool's verify, then the post-install resolution), and
|
|
2070
|
+
// ZERO on every later session — the probe cache answers before any verify
|
|
2071
|
+
// runs (`auto-install ensure intelephense: probe cache hit`).
|
|
2072
|
+
logSessionStart(`auto-install verify: succeeded for ${binPath} (check=package-entry, version=${manifest.version}, entry=${entry})`);
|
|
2073
|
+
return true;
|
|
2074
|
+
}
|
|
1854
2075
|
/**
|
|
1855
2076
|
* Verify a tool binary actually works by running its configured checkArgs.
|
|
1856
2077
|
* This catches broken symlinks, partial installs, and corrupted binaries.
|
|
@@ -1878,7 +2099,26 @@ onTransient,
|
|
|
1878
2099
|
* sensitive caller on the dispatch hot path passes a shorter one and treats
|
|
1879
2100
|
* the expiry as transient rather than as a verdict (#1657).
|
|
1880
2101
|
*/
|
|
1881
|
-
timeoutMs = 10000, verificationArgs = ["--version"]
|
|
2102
|
+
timeoutMs = 10000, verificationArgs = ["--version"],
|
|
2103
|
+
/**
|
|
2104
|
+
* Package name from {@link packageEntryVerification} — present only for a
|
|
2105
|
+
* registry entry declaring `verification: "package-entry"`. When present the
|
|
2106
|
+
* spawn is skipped entirely and {@link verifyNpmPackageEntry} answers (#2722).
|
|
2107
|
+
*/
|
|
2108
|
+
packageEntryOf,
|
|
2109
|
+
/**
|
|
2110
|
+
* Called when a `false` verdict is INCONCLUSIVE rather than a verdict: the
|
|
2111
|
+
* transport-required matcher was armed, never matched, and the child's
|
|
2112
|
+
* output was cut off before the tail arrived, so the #208 rescue could not
|
|
2113
|
+
* be evaluated at all (#2722). Distinct from `onTransient` on purpose — the
|
|
2114
|
+
* prober DID run to completion and re-probing reproduces it exactly, so this
|
|
2115
|
+
* is a durable "cannot be verified", not a stall (catalog shape 13). A
|
|
2116
|
+
* caller must not treat it as "broken" and delete the installation.
|
|
2117
|
+
*/
|
|
2118
|
+
onInconclusive) {
|
|
2119
|
+
if (packageEntryOf !== undefined) {
|
|
2120
|
+
return verifyNpmPackageEntry(binPath, packageEntryOf);
|
|
2121
|
+
}
|
|
1882
2122
|
// #2015: safeSpawnAsync instead of raw spawn. Raw spawn's timeout
|
|
1883
2123
|
// SIGTERMed only cmd.exe on Windows (.cmd shims run shell:true), orphaning
|
|
1884
2124
|
// the grandchild node process - which kept scanning, held handles against
|
|
@@ -1937,6 +2177,31 @@ timeoutMs = 10000, verificationArgs = ["--version"]) {
|
|
|
1937
2177
|
// verdict from the binary (#1569 transient semantics).
|
|
1938
2178
|
if (result.signal !== undefined || result.spawnFailure)
|
|
1939
2179
|
onTransient?.();
|
|
2180
|
+
if (result.outputTruncated &&
|
|
2181
|
+
result.signal === undefined &&
|
|
2182
|
+
!result.spawnFailure) {
|
|
2183
|
+
// #2722: the transport-required matcher above is armed on EVERY probe,
|
|
2184
|
+
// and it never matched — but the output we kept is a prefix, so the
|
|
2185
|
+
// marker may simply sit past it (intelephense emits ~4 MB of bundle
|
|
2186
|
+
// ahead of its own diagnostic). "Unmatched within a truncated prefix"
|
|
2187
|
+
// is not "this binary is broken"; callers must not delete the install
|
|
2188
|
+
// on it. Recorded as its own kind so a monitor can tell an unreadable
|
|
2189
|
+
// probe apart from a rejected binary.
|
|
2190
|
+
//
|
|
2191
|
+
// R2-F4: gated on the probe having actually FINISHED. A verbose child
|
|
2192
|
+
// that is SIGTERMed at the timeout also arrives here truncated, and
|
|
2193
|
+
// that is the #1569 transient class one line above, not this one —
|
|
2194
|
+
// ungated, the two overlapped and `installNpmTool` (which tests
|
|
2195
|
+
// inconclusive first) replaced the #2015 transient message with this
|
|
2196
|
+
// one. The doc comment's "the prober DID run to completion" is now
|
|
2197
|
+
// true rather than aspirational.
|
|
2198
|
+
onInconclusive?.();
|
|
2199
|
+
recordDegradationOnce({
|
|
2200
|
+
kind: "installer-verification-inconclusive",
|
|
2201
|
+
subject: binPath,
|
|
2202
|
+
reason: `transport-required marker unresolved in truncated output (${verificationArgs.join(" ")})`,
|
|
2203
|
+
});
|
|
2204
|
+
}
|
|
1940
2205
|
const kind = result.spawnFailure?.kind ??
|
|
1941
2206
|
(result.signal
|
|
1942
2207
|
? `killed-signal=${result.signal}`
|
|
@@ -1985,29 +2250,15 @@ export async function getAllToolStatuses() {
|
|
|
1985
2250
|
status.installed = true;
|
|
1986
2251
|
status.source = "global-path";
|
|
1987
2252
|
status.path = tool.checkCommand;
|
|
1988
|
-
// Try to get version
|
|
1989
|
-
|
|
1990
|
-
|
|
1991
|
-
|
|
1992
|
-
|
|
1993
|
-
stdio: ["ignore", "pipe", "pipe"],
|
|
1994
|
-
shell: process.platform === "win32",
|
|
1995
|
-
timeout: 5000,
|
|
1996
|
-
});
|
|
1997
|
-
}
|
|
1998
|
-
catch {
|
|
1999
|
-
// SYNCHRONOUS spawn throw (Windows `spawn UNKNOWN`/EINVAL, the
|
|
2000
|
-
// pidusage bug class, #533) — best-effort, resolve empty version.
|
|
2001
|
-
resolve("");
|
|
2002
|
-
return;
|
|
2003
|
-
}
|
|
2004
|
-
let out = "";
|
|
2005
|
-
proc.stdout?.on("data", (d) => (out += d));
|
|
2006
|
-
proc.stderr?.on("data", (d) => (out += d));
|
|
2007
|
-
proc.on("exit", () => resolve(out.trim().split("\n")[0]?.slice(0, 30) || ""));
|
|
2008
|
-
proc.on("error", () => resolve(""));
|
|
2253
|
+
// Try to get version — through the probe seam (#2894), which owns the
|
|
2254
|
+
// synchronous-throw case (#533) and the timeout tree-kill that a bare
|
|
2255
|
+
// `spawn({ timeout })` promise did not do.
|
|
2256
|
+
const probe = await probeToolAsync(tool.checkCommand, ["--version"], {
|
|
2257
|
+
timeout: 5000,
|
|
2009
2258
|
});
|
|
2010
|
-
status.version =
|
|
2259
|
+
status.version =
|
|
2260
|
+
`${probe.stdout}${probe.stderr}`.trim().split("\n")[0]?.slice(0, 30) ||
|
|
2261
|
+
undefined;
|
|
2011
2262
|
statuses.push(status);
|
|
2012
2263
|
continue;
|
|
2013
2264
|
}
|
|
@@ -2056,7 +2307,7 @@ export async function getAllToolStatuses() {
|
|
|
2056
2307
|
const localPath = installerPlatform() === "win32" ? `${localBase}.cmd` : localBase;
|
|
2057
2308
|
try {
|
|
2058
2309
|
await fs.access(localPath);
|
|
2059
|
-
if (await verifyToolBinary(localPath, undefined, undefined, getToolVerificationTimeout(tool), tool.checkArgs)) {
|
|
2310
|
+
if (await verifyToolBinary(localPath, undefined, undefined, getToolVerificationTimeout(tool), tool.checkArgs, packageEntryVerification(tool))) {
|
|
2060
2311
|
status.installed = true;
|
|
2061
2312
|
status.source = "pi-lens-auto";
|
|
2062
2313
|
status.path = localPath;
|
|
@@ -2225,7 +2476,7 @@ async function getToolPathResolved(toolId, onTransient) {
|
|
|
2225
2476
|
const cmdPath = `${localBase}.cmd`;
|
|
2226
2477
|
try {
|
|
2227
2478
|
await fs.access(cmdPath);
|
|
2228
|
-
if (await verifyToolBinary(cmdPath, recordVersion, onTransient, getToolVerificationTimeout(tool), tool.checkArgs)) {
|
|
2479
|
+
if (await verifyToolBinary(cmdPath, recordVersion, onTransient, getToolVerificationTimeout(tool), tool.checkArgs, packageEntryVerification(tool))) {
|
|
2229
2480
|
return cmdPath;
|
|
2230
2481
|
}
|
|
2231
2482
|
logSessionStart(`auto-install verify: ${cmdPath} exists but is broken, will reinstall`);
|
|
@@ -2238,7 +2489,7 @@ async function getToolPathResolved(toolId, onTransient) {
|
|
|
2238
2489
|
const exePath = `${localBase}.exe`;
|
|
2239
2490
|
try {
|
|
2240
2491
|
await fs.access(exePath);
|
|
2241
|
-
if (await verifyToolBinary(exePath, recordVersion, onTransient, getToolVerificationTimeout(tool), tool.checkArgs)) {
|
|
2492
|
+
if (await verifyToolBinary(exePath, recordVersion, onTransient, getToolVerificationTimeout(tool), tool.checkArgs, packageEntryVerification(tool))) {
|
|
2242
2493
|
return exePath;
|
|
2243
2494
|
}
|
|
2244
2495
|
logSessionStart(`auto-install verify: ${exePath} exists but is broken, will reinstall`);
|
|
@@ -2250,7 +2501,7 @@ async function getToolPathResolved(toolId, onTransient) {
|
|
|
2250
2501
|
if (installerPlatform() !== "win32") {
|
|
2251
2502
|
try {
|
|
2252
2503
|
await fs.access(localBase);
|
|
2253
|
-
if (await verifyToolBinary(localBase, recordVersion, onTransient, getToolVerificationTimeout(tool), tool.checkArgs)) {
|
|
2504
|
+
if (await verifyToolBinary(localBase, recordVersion, onTransient, getToolVerificationTimeout(tool), tool.checkArgs, packageEntryVerification(tool))) {
|
|
2254
2505
|
return localBase;
|
|
2255
2506
|
}
|
|
2256
2507
|
logSessionStart(`auto-install verify: ${localBase} exists but is broken, will reinstall`);
|
|
@@ -2349,6 +2600,13 @@ function getGitHubInstalledBinaryName(binaryName, platform, assetName) {
|
|
|
2349
2600
|
return `${binaryName}.cmd`;
|
|
2350
2601
|
return `${binaryName}.exe`;
|
|
2351
2602
|
}
|
|
2603
|
+
function launcherForGitHubAsset(spec, assetName) {
|
|
2604
|
+
if (spec.launcher === "php" && assetName.endsWith(".phar"))
|
|
2605
|
+
return "php";
|
|
2606
|
+
if (spec.launcher === "java" && assetName.endsWith(".jar"))
|
|
2607
|
+
return "java";
|
|
2608
|
+
return undefined;
|
|
2609
|
+
}
|
|
2352
2610
|
function getArchiveBinaryCandidates(binaryName, platform, assetName) {
|
|
2353
2611
|
if (platform !== "win32")
|
|
2354
2612
|
return [binaryName];
|
|
@@ -2701,10 +2959,35 @@ prefetchedRelease) {
|
|
|
2701
2959
|
const binaryName = tool.binaryName ?? tool.id;
|
|
2702
2960
|
const isWindows = platform === "win32";
|
|
2703
2961
|
const finalBinaryName = getGitHubInstalledBinaryName(binaryName, platform, asset.name);
|
|
2704
|
-
|
|
2962
|
+
let destPath = path.join(GITHUB_BIN_DIR, finalBinaryName);
|
|
2705
2963
|
const assetName = asset.name;
|
|
2964
|
+
const launcherRuntime = launcherForGitHubAsset(spec, assetName);
|
|
2965
|
+
if (launcherRuntime &&
|
|
2966
|
+
!(await isCommandAvailable(launcherRuntime, ["--version"]))) {
|
|
2967
|
+
logSessionStart(`github-install ${tool.id}: ${launcherRuntime} not found — asset requires a runtime launcher`);
|
|
2968
|
+
return undefined;
|
|
2969
|
+
}
|
|
2706
2970
|
try {
|
|
2707
|
-
if (
|
|
2971
|
+
if (launcherRuntime) {
|
|
2972
|
+
const assetPath = path.join(GITHUB_BIN_DIR, `${tool.id}${assetName.endsWith(".phar") ? ".phar" : ".jar"}`);
|
|
2973
|
+
await writeFileAtomicAsync(assetPath, assetBuffer, {
|
|
2974
|
+
bestEffort: false,
|
|
2975
|
+
mode: 0o750,
|
|
2976
|
+
});
|
|
2977
|
+
const launcherName = isWindows ? `${binaryName}.bat` : binaryName;
|
|
2978
|
+
destPath = path.join(GITHUB_BIN_DIR, launcherName);
|
|
2979
|
+
const runtimeTarget = assetName.endsWith(".phar")
|
|
2980
|
+
? `${tool.id}.phar`
|
|
2981
|
+
: `${tool.id}.jar`;
|
|
2982
|
+
const command = isWindows
|
|
2983
|
+
? `@echo off\r\n${launcherRuntime} "%~dp0${runtimeTarget}" %*\r\n`
|
|
2984
|
+
: `#!/bin/sh\nexec ${launcherRuntime} "$(dirname "$0")/${runtimeTarget}" "$@"\n`;
|
|
2985
|
+
await writeFileAtomicAsync(destPath, command, {
|
|
2986
|
+
bestEffort: false,
|
|
2987
|
+
mode: isWindows ? undefined : 0o750,
|
|
2988
|
+
});
|
|
2989
|
+
}
|
|
2990
|
+
else if (assetName.endsWith(".gz") && !assetName.endsWith(".tar.gz")) {
|
|
2708
2991
|
// Bare gzip (e.g. rust-analyzer-x86_64-unknown-linux-gnu.gz) — decompress directly
|
|
2709
2992
|
const decompressed = await new Promise((resolve, reject) => {
|
|
2710
2993
|
const gunzip = createGunzip();
|
|
@@ -2873,6 +3156,7 @@ export function npmToolNeedsPostinstall(packageName) {
|
|
|
2873
3156
|
* that wanders off it.
|
|
2874
3157
|
*/
|
|
2875
3158
|
export function getRefreshableManagedNpmTools() {
|
|
3159
|
+
const seenPackages = new Set();
|
|
2876
3160
|
return getRefreshableManagedTools()
|
|
2877
3161
|
.filter((candidate) => candidate.strategy === "npm")
|
|
2878
3162
|
.map((candidate) => ({
|
|
@@ -2881,7 +3165,13 @@ export function getRefreshableManagedNpmTools() {
|
|
|
2881
3165
|
// have both, so these are total.
|
|
2882
3166
|
packageName: candidate.packageName,
|
|
2883
3167
|
binaryName: candidate.binaryName,
|
|
2884
|
-
}))
|
|
3168
|
+
}))
|
|
3169
|
+
.filter((candidate) => {
|
|
3170
|
+
if (seenPackages.has(candidate.packageName))
|
|
3171
|
+
return false;
|
|
3172
|
+
seenPackages.add(candidate.packageName);
|
|
3173
|
+
return true;
|
|
3174
|
+
});
|
|
2885
3175
|
}
|
|
2886
3176
|
/** The Maven GAV a `maven` entry pins, as a stable identity string. */
|
|
2887
3177
|
function mavenCoordinate(spec) {
|
|
@@ -2928,6 +3218,7 @@ export function getRefreshableManagedTools() {
|
|
|
2928
3218
|
packageName: tool.packageName,
|
|
2929
3219
|
binaryName: tool.binaryName,
|
|
2930
3220
|
verificationTimeoutMs: tool.verificationTimeoutMs,
|
|
3221
|
+
packageEntryOf: packageEntryVerification(tool),
|
|
2931
3222
|
});
|
|
2932
3223
|
break;
|
|
2933
3224
|
}
|
|
@@ -3046,7 +3337,7 @@ async function probeManagedToolVersion(tool) {
|
|
|
3046
3337
|
if (!cached?.path || !existsSync(cached.path))
|
|
3047
3338
|
return undefined;
|
|
3048
3339
|
try {
|
|
3049
|
-
const result = await
|
|
3340
|
+
const result = await probeToolAsync(cached.path, tool.checkArgs, {
|
|
3050
3341
|
timeout: getToolVerificationTimeout(tool),
|
|
3051
3342
|
input: "",
|
|
3052
3343
|
ignoreAmbientSignal: true,
|
|
@@ -3752,12 +4043,20 @@ async function installArchiveTool(tool) {
|
|
|
3752
4043
|
* generic fallback `finishInstallAttempt` uses when nothing set it.
|
|
3753
4044
|
*/
|
|
3754
4045
|
function recordPackageManagerInstallException(toolId, strategyLabel, packageName, err) {
|
|
3755
|
-
const message = err.message;
|
|
4046
|
+
const message = boundInstallError(err.message);
|
|
3756
4047
|
logSessionStart(`auto-install ${strategyLabel} ${packageName}: exception: ${message}`);
|
|
3757
4048
|
installFailureReasons.set(toolId, message);
|
|
3758
4049
|
return undefined;
|
|
3759
4050
|
}
|
|
3760
|
-
|
|
4051
|
+
const INSTALL_ERROR_LINE_LIMIT = 1000;
|
|
4052
|
+
const INSTALL_CANDIDATE_ERROR_LIMIT = 200;
|
|
4053
|
+
function boundInstallError(value, limit = INSTALL_ERROR_LINE_LIMIT) {
|
|
4054
|
+
const line = value.replace(/[\r\n]+/g, " ").trim();
|
|
4055
|
+
return line.length > limit ? `${line.slice(0, limit - 3)}...` : line;
|
|
4056
|
+
}
|
|
4057
|
+
async function installNpmTool(toolId, packageName, binaryName, verificationArgs = ["--version"], verificationTimeoutMs = 10_000,
|
|
4058
|
+
/** See {@link packageEntryVerification} — spawn-free verification (#2722). */
|
|
4059
|
+
packageEntryOf) {
|
|
3761
4060
|
try {
|
|
3762
4061
|
// Ensure tools directory exists
|
|
3763
4062
|
await fs.mkdir(TOOLS_DIR, { recursive: true });
|
|
@@ -3837,11 +4136,15 @@ async function installNpmTool(toolId, packageName, binaryName, verificationArgs
|
|
|
3837
4136
|
debugLog(`Verifying ${binaryName}...`);
|
|
3838
4137
|
let isValid = false;
|
|
3839
4138
|
let lastAttemptTransient = false;
|
|
4139
|
+
let lastAttemptInconclusive = false;
|
|
3840
4140
|
for (let attempt = 1; attempt <= 3; attempt++) {
|
|
3841
4141
|
lastAttemptTransient = false;
|
|
4142
|
+
lastAttemptInconclusive = false;
|
|
3842
4143
|
isValid = await verifyToolBinary(binPath, undefined, () => {
|
|
3843
4144
|
lastAttemptTransient = true;
|
|
3844
|
-
}, verificationTimeoutMs, verificationArgs)
|
|
4145
|
+
}, verificationTimeoutMs, verificationArgs, packageEntryOf, () => {
|
|
4146
|
+
lastAttemptInconclusive = true;
|
|
4147
|
+
});
|
|
3845
4148
|
if (isValid)
|
|
3846
4149
|
break;
|
|
3847
4150
|
if (attempt < 3) {
|
|
@@ -3849,6 +4152,37 @@ async function installNpmTool(toolId, packageName, binaryName, verificationArgs
|
|
|
3849
4152
|
await new Promise((r) => setTimeout(r, 1000 * attempt));
|
|
3850
4153
|
}
|
|
3851
4154
|
}
|
|
4155
|
+
if (!isValid && lastAttemptInconclusive) {
|
|
4156
|
+
// #2722: the probe ran to completion but could not decide — the #208
|
|
4157
|
+
// transport-required matcher was armed, never matched, and the kept
|
|
4158
|
+
// output is a truncated prefix, so the marker may sit past it (the
|
|
4159
|
+
// class intelephense fell into: ~4 MB of bundle ahead of the marker,
|
|
4160
|
+
// unreachable through any pipe). Same rule as the transient branch
|
|
4161
|
+
// below (#2015): a non-verdict must not delete a freshly installed
|
|
4162
|
+
// package. Deliberately NOT folded into `lastAttemptTransient` —
|
|
4163
|
+
// re-probing reproduces this exactly, so it is durable, and a
|
|
4164
|
+
// transient verdict would keep re-arming the reinstall path
|
|
4165
|
+
// (catalog shape 13).
|
|
4166
|
+
// R2-F2: a non-verdict is a reason to keep ONLY while the tree on disk
|
|
4167
|
+
// still looks like a complete install. With intelephense verified
|
|
4168
|
+
// spawn-free, no registry entry reaches this branch healthy (measured:
|
|
4169
|
+
// no other npm-strategy LSP server emits more than 1,527 bytes), so
|
|
4170
|
+
// its live population is BROKEN servers that spew past the retained
|
|
4171
|
+
// window and die — and for those the delete was the only repair that
|
|
4172
|
+
// existed. Measured on npm 9.2.0 against a real managed prefix: a
|
|
4173
|
+
// package file corrupted IN PLACE is not repaired by re-installing
|
|
4174
|
+
// (`up to date`, the zeroed file stays zeroed), while a package
|
|
4175
|
+
// directory, a `.bin` shim or a nested dependency that is GONE is
|
|
4176
|
+
// reinstalled. So the same on-disk evidence `verification:
|
|
4177
|
+
// "package-entry"` uses decides keep-vs-delete here — strictly as a
|
|
4178
|
+
// gate, never as a verdict: the install is still recorded as failed,
|
|
4179
|
+
// so the tool still reads `✗` and nothing is re-hidden.
|
|
4180
|
+
if (await verifyNpmPackageEntry(binPath, packageName)) {
|
|
4181
|
+
logSessionStart(`auto-install ${packageName}: verification inconclusive (output truncated before the transport-required marker) but the installed tree is intact; keeping installation for re-probe`);
|
|
4182
|
+
return undefined;
|
|
4183
|
+
}
|
|
4184
|
+
logSessionStart(`auto-install ${packageName}: verification inconclusive AND the installed tree is incomplete; cleaning up so the next install can repair it`);
|
|
4185
|
+
}
|
|
3852
4186
|
if (!isValid && lastAttemptTransient) {
|
|
3853
4187
|
// #2015: a killed/spawn-failed prober is NOT a verdict about the
|
|
3854
4188
|
// binary (#1569 semantics). Cold-start verifies on fresh installs
|
|
@@ -3925,7 +4259,7 @@ options = {}) {
|
|
|
3925
4259
|
? [...verb, packageName]
|
|
3926
4260
|
: ["-m", "pip", ...verb, packageName],
|
|
3927
4261
|
}));
|
|
3928
|
-
|
|
4262
|
+
const errors = [];
|
|
3929
4263
|
for (const candidate of pipCandidates) {
|
|
3930
4264
|
const pipResult = await safeSpawnAsync(candidate.command, candidate.args, {
|
|
3931
4265
|
timeout: 120_000,
|
|
@@ -4015,10 +4349,11 @@ options = {}) {
|
|
|
4015
4349
|
}
|
|
4016
4350
|
return packageName;
|
|
4017
4351
|
}
|
|
4018
|
-
|
|
4019
|
-
|
|
4352
|
+
const candidateError = `${candidate.command} ${candidate.args.join(" ")}: ${boundInstallError(outcome.error, INSTALL_CANDIDATE_ERROR_LIMIT)}`;
|
|
4353
|
+
errors.push(candidateError);
|
|
4354
|
+
debugLog(`[pip-fallback] ${candidateError}`);
|
|
4020
4355
|
}
|
|
4021
|
-
throw new Error(`Failed to install ${packageName}: no usable pip command found (${
|
|
4356
|
+
throw new Error(`Failed to install ${packageName}: no usable pip command found (${errors.join(" | ") || "unknown error"})`);
|
|
4022
4357
|
}
|
|
4023
4358
|
catch (err) {
|
|
4024
4359
|
return recordPackageManagerInstallException(toolId, "pip", packageName, err);
|
|
@@ -4132,7 +4467,7 @@ export async function installTool(toolId) {
|
|
|
4132
4467
|
case "npm": {
|
|
4133
4468
|
if (!tool.packageName || !tool.binaryName)
|
|
4134
4469
|
return false;
|
|
4135
|
-
const npmPath = await installNpmTool(tool.id, tool.packageName, tool.binaryName, tool.checkArgs, getToolVerificationTimeout(tool));
|
|
4470
|
+
const npmPath = await installNpmTool(tool.id, tool.packageName, tool.binaryName, tool.checkArgs, getToolVerificationTimeout(tool), packageEntryVerification(tool));
|
|
4136
4471
|
if (npmPath !== undefined) {
|
|
4137
4472
|
// #1746 review F4: an install just resolved this package's range
|
|
4138
4473
|
// against the registry, so record it as freshly checked. Otherwise a
|
|
@@ -4170,6 +4505,12 @@ export async function installTool(toolId) {
|
|
|
4170
4505
|
case "github": {
|
|
4171
4506
|
if (!tool.github)
|
|
4172
4507
|
return false;
|
|
4508
|
+
if (!tool.github.assetMatch(process.platform, process.arch)) {
|
|
4509
|
+
const reason = `unsupported platform=${process.platform} arch=${process.arch}`;
|
|
4510
|
+
noteInstallAttempt(tool.id, "unavailable", reason);
|
|
4511
|
+
logSessionStart(`auto-install ${tool.id}: ${reason}`);
|
|
4512
|
+
return false;
|
|
4513
|
+
}
|
|
4173
4514
|
const ghPath = await installGitHubTool(tool);
|
|
4174
4515
|
return finishInstallAttempt(tool.id, ghPath !== undefined, startedAt);
|
|
4175
4516
|
}
|
|
@@ -4182,6 +4523,12 @@ export async function installTool(toolId) {
|
|
|
4182
4523
|
case "archive": {
|
|
4183
4524
|
if (!tool.archive)
|
|
4184
4525
|
return false;
|
|
4526
|
+
if (!resolveArchiveUrl(tool.archive)) {
|
|
4527
|
+
const reason = `unsupported platform=${process.platform} arch=${process.arch}`;
|
|
4528
|
+
noteInstallAttempt(tool.id, "unavailable", reason);
|
|
4529
|
+
logSessionStart(`auto-install ${tool.id}: ${reason}`);
|
|
4530
|
+
return false;
|
|
4531
|
+
}
|
|
4185
4532
|
const archivePath = await installArchiveTool(tool);
|
|
4186
4533
|
return finishInstallAttempt(tool.id, archivePath !== undefined, startedAt);
|
|
4187
4534
|
}
|
|
@@ -4500,6 +4847,8 @@ export function getToolInstallStrategy(toolId) {
|
|
|
4500
4847
|
* "at least one platform" guard instead.
|
|
4501
4848
|
*/
|
|
4502
4849
|
export const GITHUB_TOOLS = [
|
|
4850
|
+
"cljfmt",
|
|
4851
|
+
"php-cs-fixer",
|
|
4503
4852
|
"shellcheck",
|
|
4504
4853
|
"shfmt",
|
|
4505
4854
|
"rust-analyzer",
|
|
@@ -4534,6 +4883,12 @@ export function resolveGitHubAsset(toolId, platform, arch) {
|
|
|
4534
4883
|
const tool = TOOLS.find((t) => t.id === toolId);
|
|
4535
4884
|
return tool?.github?.assetMatch(platform, arch);
|
|
4536
4885
|
}
|
|
4886
|
+
export function resolveGitHubAssetLauncher(toolId, _platform, assetName) {
|
|
4887
|
+
const tool = TOOLS.find((t) => t.id === toolId);
|
|
4888
|
+
return tool?.github
|
|
4889
|
+
? launcherForGitHubAsset(tool.github, assetName)
|
|
4890
|
+
: undefined;
|
|
4891
|
+
}
|
|
4537
4892
|
export function resolveGitHubInstalledBinaryName(toolId, platform, assetName) {
|
|
4538
4893
|
const tool = TOOLS.find((t) => t.id === toolId);
|
|
4539
4894
|
if (!tool)
|