@herbertgao/pi-extensions 2026.8.6 → 2026.8.7
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 +5 -5
- package/node_modules/@herbertgao/pi-cc-extensions/README.en.md +1 -1
- package/node_modules/@herbertgao/pi-cc-extensions/README.md +1 -1
- package/node_modules/@herbertgao/pi-cc-extensions/extensions/config/config.ts +19 -7
- package/node_modules/@herbertgao/pi-cc-extensions/extensions/config/panel.ts +30 -9
- package/node_modules/@herbertgao/pi-cc-extensions/extensions/feature/compact-thinking.ts +272 -22
- package/node_modules/@herbertgao/pi-cc-extensions/extensions/renderer/compact-mode.ts +94 -77
- package/node_modules/@herbertgao/pi-cc-extensions/extensions/renderer/message-display.ts +1 -1
- package/node_modules/@herbertgao/pi-cc-extensions/extensions/renderer/mouse/hover.ts +14 -0
- package/node_modules/@herbertgao/pi-cc-extensions/extensions/renderer/mouse/interaction.ts +55 -17
- package/node_modules/@herbertgao/pi-cc-extensions/extensions/renderer/mouse/layout.ts +41 -2
- package/node_modules/@herbertgao/pi-cc-extensions/extensions/renderer/tool/diff/diff-renderer.ts +75 -6
- package/node_modules/@herbertgao/pi-cc-extensions/extensions/renderer/tool/diff/types.ts +7 -3
- package/node_modules/@herbertgao/pi-cc-extensions/extensions/renderer/tool/grouping.ts +64 -1
- package/node_modules/@herbertgao/pi-cc-extensions/package.json +3 -3
- package/node_modules/@herbertgao/pi-subagents/CHANGELOG.md +6 -0
- package/node_modules/@herbertgao/pi-subagents/README.md +30 -22
- package/node_modules/@herbertgao/pi-subagents/examples/agent-tool-description.md +5 -5
- package/node_modules/@herbertgao/pi-subagents/package.json +7 -7
- package/node_modules/@herbertgao/pi-subagents/src/agent-file-toggle.ts +7 -1
- package/node_modules/@herbertgao/pi-subagents/src/agent-manager.ts +48 -19
- package/node_modules/@herbertgao/pi-subagents/src/agent-runner.ts +17 -13
- package/node_modules/@herbertgao/pi-subagents/src/custom-agents.ts +26 -2
- package/node_modules/@herbertgao/pi-subagents/src/index.ts +219 -40
- package/node_modules/@herbertgao/pi-subagents/src/invocation-config.ts +101 -3
- package/node_modules/@herbertgao/pi-subagents/src/nested-tools.ts +18 -4
- package/node_modules/@herbertgao/pi-subagents/src/settings.ts +99 -0
- package/node_modules/@herbertgao/pi-subagents/src/types.ts +22 -3
- package/node_modules/@herbertgao/pi-subagents/src/ui/agent-widget.ts +51 -3
- package/node_modules/@herbertgao/pi-subagents/src/ui/conversation-viewer.ts +20 -2
- package/node_modules/@herbertgao/pi-subagents/src/ui/fleet-list.ts +21 -6
- package/node_modules/@herbertgao/pi-subagents/src/usage.ts +129 -1
- package/node_modules/@herbertgao/pi-subagents/src/worktree.ts +20 -0
- package/node_modules/@juicesharp/rpiv-ask-user-question/README.md +1 -0
- package/node_modules/@juicesharp/rpiv-ask-user-question/ask-user-question.ts +26 -10
- package/node_modules/@juicesharp/rpiv-ask-user-question/config.ts +25 -0
- package/node_modules/@juicesharp/rpiv-ask-user-question/docs/configuration.md +13 -4
- package/node_modules/@juicesharp/rpiv-ask-user-question/docs/hosts.md +2 -1
- package/node_modules/@juicesharp/rpiv-ask-user-question/docs/localization.md +3 -1
- package/node_modules/@juicesharp/rpiv-ask-user-question/locales/en.json +2 -2
- package/node_modules/@juicesharp/rpiv-ask-user-question/locales/zh.json +2 -2
- package/node_modules/@juicesharp/rpiv-ask-user-question/package.json +3 -2
- package/node_modules/@juicesharp/rpiv-ask-user-question/state/build-questionnaire.ts +10 -0
- package/node_modules/@juicesharp/rpiv-ask-user-question/state/key-router.ts +3 -1
- package/node_modules/@juicesharp/rpiv-ask-user-question/state/questionnaire-session.ts +30 -7
- package/node_modules/@juicesharp/rpiv-ask-user-question/state/state.ts +14 -6
- package/node_modules/@juicesharp/rpiv-ask-user-question/view/dialog-builder.ts +30 -4
- package/node_modules/@juicesharp/rpiv-ask-user-question/view/tab-content-strategy.ts +26 -5
- package/node_modules/@narumitw/pi-btw/README.md +120 -111
- package/node_modules/@narumitw/pi-btw/dist/index.ts +2898 -0
- package/node_modules/@narumitw/pi-btw/dist/index.ts.map +7 -0
- package/node_modules/@narumitw/pi-btw/package.json +10 -6
- package/node_modules/@narumitw/pi-btw/src/btw.ts +36 -40
- package/node_modules/@narumitw/pi-btw/src/fullscreen-ui.ts +55 -10
- package/node_modules/@narumitw/pi-btw/src/main-tree-picker.ts +390 -0
- package/node_modules/@narumitw/pi-btw/src/menu.ts +45 -2
- package/node_modules/@narumitw/pi-btw/src/transcript-pager.ts +136 -45
- package/node_modules/pi-lens/CHANGELOG.md +909 -0
- package/node_modules/pi-lens/README.md +11 -3
- package/node_modules/pi-lens/config/ruff/core.toml +42 -0
- package/node_modules/pi-lens/dist/clients/actionable-warnings.js +130 -27
- package/node_modules/pi-lens/dist/clients/advisory-provenance.js +126 -13
- package/node_modules/pi-lens/dist/clients/agent-nudge.js +67 -11
- package/node_modules/pi-lens/dist/clients/ast-grep-client.js +9 -3
- package/node_modules/pi-lens/dist/clients/atomic-write.js +9 -3
- package/node_modules/pi-lens/dist/clients/bash-file-access.js +285 -8
- package/node_modules/pi-lens/dist/clients/biome-client.js +61 -30
- package/node_modules/pi-lens/dist/clients/blocker-freshness.js +428 -0
- package/node_modules/pi-lens/dist/clients/blocker-past-eof.js +119 -0
- package/node_modules/pi-lens/dist/clients/bootstrap.js +12 -1
- package/node_modules/pi-lens/dist/clients/bounded-pid-file-lock.js +12 -3
- package/node_modules/pi-lens/dist/clients/bounded-telemetry.js +192 -0
- package/node_modules/pi-lens/dist/clients/cascade-budget.js +196 -0
- package/node_modules/pi-lens/dist/clients/cascade-format.js +20 -1
- package/node_modules/pi-lens/dist/clients/cascade-types.js +9 -1
- package/node_modules/pi-lens/dist/clients/child-unref.js +54 -6
- package/node_modules/pi-lens/dist/clients/code-quality-warnings.js +76 -24
- package/node_modules/pi-lens/dist/clients/dead-code-client.js +123 -31
- package/node_modules/pi-lens/dist/clients/deadline-utils.js +8 -1
- package/node_modules/pi-lens/dist/clients/debug-handles.js +5 -0
- package/node_modules/pi-lens/dist/clients/degradation-ledger.js +62 -13
- package/node_modules/pi-lens/dist/clients/dependency-checker.js +25 -3
- package/node_modules/pi-lens/dist/clients/diagnostic-dispositions.js +147 -33
- package/node_modules/pi-lens/dist/clients/diagnostic-line-freshness.js +298 -0
- package/node_modules/pi-lens/dist/clients/dispatch/dispatcher.js +52 -2
- package/node_modules/pi-lens/dist/clients/dispatch/integration.js +256 -88
- package/node_modules/pi-lens/dist/clients/dispatch/lazy.js +7 -4
- package/node_modules/pi-lens/dist/clients/dispatch/plan.js +5 -0
- package/node_modules/pi-lens/dist/clients/dispatch/runners/ast-grep-napi.js +234 -18
- package/node_modules/pi-lens/dist/clients/dispatch/runners/biome-check.js +187 -19
- package/node_modules/pi-lens/dist/clients/dispatch/runners/cpp-check.js +6 -3
- package/node_modules/pi-lens/dist/clients/dispatch/runners/credo.js +11 -9
- package/node_modules/pi-lens/dist/clients/dispatch/runners/cue-vet.js +398 -0
- package/node_modules/pi-lens/dist/clients/dispatch/runners/elixir-check.js +11 -3
- package/node_modules/pi-lens/dist/clients/dispatch/runners/eslint.js +12 -7
- package/node_modules/pi-lens/dist/clients/dispatch/runners/go-vet.js +18 -0
- package/node_modules/pi-lens/dist/clients/dispatch/runners/helm-render.js +895 -0
- package/node_modules/pi-lens/dist/clients/dispatch/runners/index.js +4 -0
- package/node_modules/pi-lens/dist/clients/dispatch/runners/javac.js +16 -3
- package/node_modules/pi-lens/dist/clients/dispatch/runners/lsp.js +60 -53
- package/node_modules/pi-lens/dist/clients/dispatch/runners/markdownlint.js +16 -0
- package/node_modules/pi-lens/dist/clients/dispatch/runners/mypy.js +23 -0
- package/node_modules/pi-lens/dist/clients/dispatch/runners/psscriptanalyzer.js +331 -55
- package/node_modules/pi-lens/dist/clients/dispatch/runners/pyright.js +38 -5
- package/node_modules/pi-lens/dist/clients/dispatch/runners/rust-clippy.js +97 -19
- package/node_modules/pi-lens/dist/clients/dispatch/runners/spellcheck.js +14 -0
- package/node_modules/pi-lens/dist/clients/dispatch/runners/sqlfluff.js +20 -0
- package/node_modules/pi-lens/dist/clients/dispatch/runners/stylelint.js +22 -0
- package/node_modules/pi-lens/dist/clients/dispatch/runners/swiftlint.js +10 -0
- package/node_modules/pi-lens/dist/clients/dispatch/runners/taplo.js +18 -6
- package/node_modules/pi-lens/dist/clients/dispatch/runners/trivy-config.js +73 -12
- package/node_modules/pi-lens/dist/clients/dispatch/runners/utils/availability-policy.js +275 -13
- package/node_modules/pi-lens/dist/clients/dispatch/runners/utils/candidate-probe.js +21 -6
- package/node_modules/pi-lens/dist/clients/dispatch/runners/utils/lazy-installer.js +260 -27
- package/node_modules/pi-lens/dist/clients/dispatch/runners/utils/runner-helpers.js +734 -64
- package/node_modules/pi-lens/dist/clients/dispatch/runners/utils/spawn-outcome.js +86 -11
- package/node_modules/pi-lens/dist/clients/dispatch/runners/utils/tool-failure.js +72 -0
- package/node_modules/pi-lens/dist/clients/dispatch/runners/utils/toolchain-availability.js +9 -0
- package/node_modules/pi-lens/dist/clients/dispatch/runners/vale.js +9 -0
- package/node_modules/pi-lens/dist/clients/dispatch/runners/yamllint.js +18 -1
- package/node_modules/pi-lens/dist/clients/dispatch/runners/zig-check.js +4 -2
- package/node_modules/pi-lens/dist/clients/event-loop-monitor.js +28 -5
- package/node_modules/pi-lens/dist/clients/extension-log.js +22 -1
- package/node_modules/pi-lens/dist/clients/file-kinds.js +8 -2
- package/node_modules/pi-lens/dist/clients/finding-delivery-gate.js +294 -0
- package/node_modules/pi-lens/dist/clients/finding-identity.js +88 -0
- package/node_modules/pi-lens/dist/clients/formatters-lazy.js +3 -2
- package/node_modules/pi-lens/dist/clients/formatters.js +500 -115
- package/node_modules/pi-lens/dist/clients/generation-guard.js +216 -0
- package/node_modules/pi-lens/dist/clients/git-guard.js +31 -0
- package/node_modules/pi-lens/dist/clients/gitleaks-client.js +181 -8
- package/node_modules/pi-lens/dist/clients/govulncheck-client.js +109 -9
- package/node_modules/pi-lens/dist/clients/grammar-source.js +333 -10
- package/node_modules/pi-lens/dist/clients/host-ports.js +8 -0
- package/node_modules/pi-lens/dist/clients/installer/index.js +1114 -100
- package/node_modules/pi-lens/dist/clients/installer/managed-tool-refresh-session.js +58 -0
- package/node_modules/pi-lens/dist/clients/installer/managed-tool-refresh.js +715 -0
- package/node_modules/pi-lens/dist/clients/instance-reaper.js +643 -97
- package/node_modules/pi-lens/dist/clients/instance-registry.js +87 -17
- package/node_modules/pi-lens/dist/clients/jscpd-client.js +82 -6
- package/node_modules/pi-lens/dist/clients/knip-client.js +310 -10
- package/node_modules/pi-lens/dist/clients/language-policy.js +8 -2
- package/node_modules/pi-lens/dist/clients/language-profile.js +2 -0
- package/node_modules/pi-lens/dist/clients/latency-logger.js +440 -11
- package/node_modules/pi-lens/dist/clients/lazy-import.js +21 -0
- package/node_modules/pi-lens/dist/clients/ledger-bounds.js +21 -0
- package/node_modules/pi-lens/dist/clients/lens-flag-registry.js +8 -0
- package/node_modules/pi-lens/dist/clients/lsp/cascade-tier.js +102 -7
- package/node_modules/pi-lens/dist/clients/lsp/client.js +1516 -159
- package/node_modules/pi-lens/dist/clients/lsp/diagnostic-binding.js +83 -1
- package/node_modules/pi-lens/dist/clients/lsp/document-drift.js +389 -0
- package/node_modules/pi-lens/dist/clients/lsp/index.js +2274 -147
- package/node_modules/pi-lens/dist/clients/lsp/inferred-project.js +215 -0
- package/node_modules/pi-lens/dist/clients/lsp/jvm-runtime.js +146 -14
- package/node_modules/pi-lens/dist/clients/lsp/language.js +48 -4
- package/node_modules/pi-lens/dist/clients/lsp/server.js +277 -16
- package/node_modules/pi-lens/dist/clients/lsp/spawn-history.js +22 -0
- package/node_modules/pi-lens/dist/clients/lsp/sync-kind.js +43 -0
- package/node_modules/pi-lens/dist/clients/lsp/tsserver-sync.js +79 -3
- package/node_modules/pi-lens/dist/clients/lsp/wait-policy/strategies.js +43 -0
- package/node_modules/pi-lens/dist/clients/lsp/workspace-diagnostics-cache.js +422 -28
- package/node_modules/pi-lens/dist/clients/lsp/workspace-diagnostics-session.js +30 -0
- package/node_modules/pi-lens/dist/clients/lsp/workspace-sweep-hold.js +175 -0
- package/node_modules/pi-lens/dist/clients/lsp-lazy.js +3 -2
- package/node_modules/pi-lens/dist/clients/mcp/session.js +10 -2
- package/node_modules/pi-lens/dist/clients/module-report.js +8 -0
- package/node_modules/pi-lens/dist/clients/opengrep-client.js +15 -1
- package/node_modules/pi-lens/dist/clients/package-manager.js +170 -14
- package/node_modules/pi-lens/dist/clients/path-attribution-telemetry.js +27 -0
- package/node_modules/pi-lens/dist/clients/path-utils.js +160 -0
- package/node_modules/pi-lens/dist/clients/pipeline.js +154 -33
- package/node_modules/pi-lens/dist/clients/post-autofix-notice.js +37 -0
- package/node_modules/pi-lens/dist/clients/project-diagnostics/cache.js +17 -3
- package/node_modules/pi-lens/dist/clients/project-diagnostics/extractors.js +89 -22
- package/node_modules/pi-lens/dist/clients/project-diagnostics/fresh-fetch.js +84 -14
- package/node_modules/pi-lens/dist/clients/project-diagnostics/runner-adapters/gitleaks.js +15 -3
- package/node_modules/pi-lens/dist/clients/project-diagnostics/runner-adapters/trivy.js +50 -2
- package/node_modules/pi-lens/dist/clients/project-diagnostics/scanner.js +5 -0
- package/node_modules/pi-lens/dist/clients/project-lens-config.js +3 -0
- package/node_modules/pi-lens/dist/clients/project-snapshot.js +299 -0
- package/node_modules/pi-lens/dist/clients/quiet-window-config.js +47 -0
- package/node_modules/pi-lens/dist/clients/quiet-window.js +11 -25
- package/node_modules/pi-lens/dist/clients/read-guard-logger.js +1 -1
- package/node_modules/pi-lens/dist/clients/read-guard.js +184 -10
- package/node_modules/pi-lens/dist/clients/resource-sampler.js +49 -17
- package/node_modules/pi-lens/dist/clients/reverse-deps.js +50 -11
- package/node_modules/pi-lens/dist/clients/review-graph/query.js +52 -4
- package/node_modules/pi-lens/dist/clients/runtime-agent-end.js +96 -7
- package/node_modules/pi-lens/dist/clients/runtime-context.js +8 -1
- package/node_modules/pi-lens/dist/clients/runtime-coordinator.js +308 -45
- package/node_modules/pi-lens/dist/clients/runtime-session.js +332 -9
- package/node_modules/pi-lens/dist/clients/runtime-tool-call.js +217 -22
- package/node_modules/pi-lens/dist/clients/runtime-tool-result.js +212 -79
- package/node_modules/pi-lens/dist/clients/runtime-turn.js +575 -67
- package/node_modules/pi-lens/dist/clients/safe-spawn.js +220 -7
- package/node_modules/pi-lens/dist/clients/scratch-tree-policy.js +161 -0
- package/node_modules/pi-lens/dist/clients/search-read-registration.js +34 -6
- package/node_modules/pi-lens/dist/clients/security-scan-client.js +157 -24
- package/node_modules/pi-lens/dist/clients/sg-runner.js +116 -22
- package/node_modules/pi-lens/dist/clients/single-flight.js +158 -0
- package/node_modules/pi-lens/dist/clients/stale-marker.js +17 -0
- package/node_modules/pi-lens/dist/clients/startup-timing.js +19 -1
- package/node_modules/pi-lens/dist/clients/test-runner-client.js +151 -16
- package/node_modules/pi-lens/dist/clients/tool-event.js +56 -5
- package/node_modules/pi-lens/dist/clients/tool-policy.js +125 -20
- package/node_modules/pi-lens/dist/clients/tree-sitter-cache.js +75 -1
- package/node_modules/pi-lens/dist/clients/tree-sitter-client.js +769 -64
- package/node_modules/pi-lens/dist/clients/tree-sitter-shared.js +11 -0
- package/node_modules/pi-lens/dist/clients/tree-sitter-symbol-extractor.js +90 -0
- package/node_modules/pi-lens/dist/clients/trivy-client.js +19 -1
- package/node_modules/pi-lens/dist/clients/widget-state.js +336 -36
- package/node_modules/pi-lens/dist/clients/zizmor-config.js +214 -14
- package/node_modules/pi-lens/dist/index.js +67738 -55739
- package/node_modules/pi-lens/dist/tools/lens-diagnostics.js +466 -54
- package/node_modules/pi-lens/dist/tools/lsp-diagnostics.js +132 -43
- package/node_modules/pi-lens/dist/tools/lsp-navigation.js +46 -7
- package/node_modules/pi-lens/docs/agent-guide.md +6 -1
- package/node_modules/pi-lens/docs/ast-grep_rules_catalog.md +515 -506
- package/node_modules/pi-lens/docs/dispositions.md +21 -0
- package/node_modules/pi-lens/docs/features.md +19 -5
- package/node_modules/pi-lens/docs/globalconfig.md +3 -0
- package/node_modules/pi-lens/docs/language-coverage.md +71 -5
- package/node_modules/pi-lens/docs/mcp.md +2 -2
- package/node_modules/pi-lens/docs/servercapabilities.md +4 -1
- package/node_modules/pi-lens/docs/settings.md +19 -1
- package/node_modules/pi-lens/docs/usage.md +1 -0
- package/node_modules/pi-lens/package.json +10 -6
- package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/__snapshots__/no-reflect-get-js-snapshot.yml +23 -0
- package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/__snapshots__/no-reflect-get-snapshot.yml +23 -0
- package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/__snapshots__/ts-void-zero-snapshot.yml +23 -0
- package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/no-bare-object-param-test.yml +16 -0
- package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/no-chained-type-assertions-test.yml +15 -1
- package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/no-compile-call-test.yml +29 -1
- package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/no-dupe-class-members-test.yml +33 -0
- package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/no-inner-html-js-test.yml +7 -1
- package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/no-inner-html-test.yml +7 -1
- package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/no-known-value-widening-test.yml +9 -0
- package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/no-non-null-assertion-test.yml +216 -0
- package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/no-reflect-apply-js-test.yml +2 -0
- package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/no-reflect-apply-test.yml +2 -0
- package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/no-reflect-get-js-test.yml +2 -1
- package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/no-reflect-get-test.yml +2 -1
- package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/no-return-value-in-generator-test.yml +12 -0
- package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/no-runtime-typeof-test.yml +33 -0
- package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/no-server-bind-wildcard-test.yml +9 -0
- package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/no-shape-in-symbol-names-test.yml +13 -0
- package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/no-sql-in-code-js-test.yml +5 -1
- package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/no-sql-in-code-test.yml +5 -1
- package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/no-unknown-parameters-test.yml +12 -0
- package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/no-unknown-returns-test.yml +16 -0
- package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/no-unsafe-dictionary-any-test.yml +10 -0
- package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/no-unsafe-dictionary-unknown-test.yml +8 -0
- package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/redundant-unsafe-function-test.yml +35 -0
- package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/require-safety-comment-for-as-unknown-as-test.yml +177 -0
- package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/ts-void-zero-test.yml +1 -0
- package/node_modules/pi-lens/rules/ast-grep-rules/rules/no-await-expression-member-js.yml +13 -2
- package/node_modules/pi-lens/rules/ast-grep-rules/rules/no-await-expression-member.yml +13 -2
- package/node_modules/pi-lens/rules/ast-grep-rules/rules/no-bare-host-path-in-win32-branch.yml +2 -0
- package/node_modules/pi-lens/rules/ast-grep-rules/rules/no-bare-object-param.yml +60 -0
- package/node_modules/pi-lens/rules/ast-grep-rules/rules/no-chained-type-assertions.yml +57 -12
- package/node_modules/pi-lens/rules/ast-grep-rules/rules/no-compile-call.yml +63 -5
- package/node_modules/pi-lens/rules/ast-grep-rules/rules/no-dupe-class-members.yml +52 -8
- package/node_modules/pi-lens/rules/ast-grep-rules/rules/no-inner-html-js.yml +27 -2
- package/node_modules/pi-lens/rules/ast-grep-rules/rules/no-inner-html.yml +27 -2
- package/node_modules/pi-lens/rules/ast-grep-rules/rules/no-known-value-widening.yml +71 -0
- package/node_modules/pi-lens/rules/ast-grep-rules/rules/no-non-null-assertion.yml +316 -0
- package/node_modules/pi-lens/rules/ast-grep-rules/rules/no-raw-json-store-write.yml +7 -0
- package/node_modules/pi-lens/rules/ast-grep-rules/rules/no-reflect-apply-js.yml +22 -2
- package/node_modules/pi-lens/rules/ast-grep-rules/rules/no-reflect-apply.yml +23 -2
- package/node_modules/pi-lens/rules/ast-grep-rules/rules/no-reflect-get-js.yml +33 -5
- package/node_modules/pi-lens/rules/ast-grep-rules/rules/no-reflect-get.yml +34 -8
- package/node_modules/pi-lens/rules/ast-grep-rules/rules/no-return-value-in-generator.yml +22 -5
- package/node_modules/pi-lens/rules/ast-grep-rules/rules/no-runtime-typeof.yml +121 -0
- package/node_modules/pi-lens/rules/ast-grep-rules/rules/no-server-bind-wildcard.yml +23 -7
- package/node_modules/pi-lens/rules/ast-grep-rules/rules/no-shape-in-symbol-names.yml +68 -0
- package/node_modules/pi-lens/rules/ast-grep-rules/rules/no-sql-in-code-js.yml +41 -2
- package/node_modules/pi-lens/rules/ast-grep-rules/rules/no-sql-in-code.yml +41 -2
- package/node_modules/pi-lens/rules/ast-grep-rules/rules/no-unknown-laundering.yml +6 -1
- package/node_modules/pi-lens/rules/ast-grep-rules/rules/no-unknown-parameters.yml +67 -0
- package/node_modules/pi-lens/rules/ast-grep-rules/rules/no-unknown-returns.yml +106 -0
- package/node_modules/pi-lens/rules/ast-grep-rules/rules/no-unsafe-dictionary-any.yml +50 -0
- package/node_modules/pi-lens/rules/ast-grep-rules/rules/no-unsafe-dictionary-unknown.yml +56 -0
- package/node_modules/pi-lens/rules/ast-grep-rules/rules/no-win32-isabsolute-for-qualification.yml +2 -0
- package/node_modules/pi-lens/rules/ast-grep-rules/rules/redundant-unsafe-function.yml +32 -0
- package/node_modules/pi-lens/rules/ast-grep-rules/rules/require-safety-comment-for-as-unknown-as.yml +184 -0
- package/node_modules/pi-lens/rules/ast-grep-rules/rules/ts-void-zero.yml +5 -0
- package/node_modules/pi-lens/rules/ast-grep-rules/self-scan-baseline.json +5 -0
- package/node_modules/pi-lens/scripts/analyze-pi-lens-logs.mjs +53 -1
- package/node_modules/pi-lens/scripts/download-grammars.js +25 -0
- package/node_modules/pi-lens/scripts/grammars.lock.json +9 -0
- package/node_modules/pi-lens/skills/pi-lens-ast-grep/SKILL.md +2 -0
- package/node_modules/pi-lens/skills/pi-lens-write-ast-grep-rule/SKILL.md +80 -3
- package/node_modules/pi-lens/skills/pi-lens-write-ast-grep-rule/reference.md +41 -0
- package/node_modules/pi-lens/vendor/grammars/tree-sitter-cue.wasm +0 -0
- package/node_modules/pi-mcp-adapter/CHANGELOG.md +36 -0
- package/node_modules/pi-mcp-adapter/README.md +47 -5
- package/node_modules/pi-mcp-adapter/cli.js +163 -1
- package/node_modules/pi-mcp-adapter/commands.ts +128 -22
- package/node_modules/pi-mcp-adapter/config.ts +25 -7
- package/node_modules/pi-mcp-adapter/direct-tools.ts +5 -4
- package/node_modules/pi-mcp-adapter/index.ts +219 -32
- package/node_modules/pi-mcp-adapter/init.ts +36 -4
- package/node_modules/pi-mcp-adapter/lifecycle.ts +315 -24
- package/node_modules/pi-mcp-adapter/mcp-auth-flow.ts +39 -6
- package/node_modules/pi-mcp-adapter/mcp-bearer-store.ts +387 -0
- package/node_modules/pi-mcp-adapter/mcp-callback-server.ts +27 -3
- package/node_modules/pi-mcp-adapter/mcp-code.ts +4 -0
- package/node_modules/pi-mcp-adapter/mcp-panel.ts +42 -13
- package/node_modules/pi-mcp-adapter/metadata-cache.ts +32 -21
- package/node_modules/pi-mcp-adapter/package-mcp-loader.ts +168 -0
- package/node_modules/pi-mcp-adapter/package.json +3 -1
- package/node_modules/pi-mcp-adapter/proxy-modes.ts +5 -4
- package/node_modules/pi-mcp-adapter/request-headers-command.ts +31 -37
- package/node_modules/pi-mcp-adapter/search-ranking.ts +92 -22
- package/node_modules/pi-mcp-adapter/server-manager.ts +140 -2
- package/node_modules/pi-mcp-adapter/session-recovery.ts +7 -0
- package/node_modules/pi-mcp-adapter/tool-approval.ts +15 -2
- package/node_modules/pi-mcp-adapter/tool-result-renderer.ts +44 -4
- package/node_modules/pi-mcp-adapter/types.ts +2 -0
- package/node_modules/pi-mcp-adapter/ui-server.ts +18 -16
- package/node_modules/pi-mcp-adapter/utils.ts +70 -0
- package/node_modules/pi-web-access/CHANGELOG.md +23 -0
- package/node_modules/pi-web-access/README.md +27 -9
- package/node_modules/pi-web-access/anysearch.ts +4 -2
- package/node_modules/pi-web-access/brave.ts +16 -4
- package/node_modules/pi-web-access/curator-page.ts +6 -3
- package/node_modules/pi-web-access/curator-server.ts +4 -1
- package/node_modules/pi-web-access/exa.ts +18 -7
- package/node_modules/pi-web-access/extract.ts +28 -3
- package/node_modules/pi-web-access/gemini-search.ts +16 -4
- package/node_modules/pi-web-access/index.ts +41 -57
- package/node_modules/pi-web-access/package.json +1 -1
- package/node_modules/pi-web-access/page-query.ts +4 -2
- package/node_modules/pi-web-access/parallel-mcp.ts +249 -0
- package/node_modules/pi-web-access/parallel.ts +2 -2
- package/node_modules/pi-web-access/query-rewrite.ts +51 -0
- package/node_modules/pi-web-access/serper.ts +211 -0
- package/node_modules/pi-web-access/summary-model-scope.ts +12 -4
- package/node_modules/pi-web-access/summary-review.ts +44 -22
- package/node_modules/pi-web-access/tavily.ts +16 -4
- package/node_modules/pi-web-access/utils.ts +87 -0
- package/node_modules/pi-web-access/valyu.ts +199 -0
- package/package.json +13 -13
|
@@ -0,0 +1,215 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* #1640: honest rendering for TypeScript diagnostics on files that belong to no
|
|
3
|
+
* tsconfig project.
|
|
4
|
+
*
|
|
5
|
+
* When a file matches no project's `include`/`files`, tsserver still checks it —
|
|
6
|
+
* in a synthetic INFERRED project with default compiler options, no `types`
|
|
7
|
+
* from the project's `tsconfig`, and different module resolution. The project's
|
|
8
|
+
* own `tsc --noEmit` never looks at those files, so the two answers legitimately
|
|
9
|
+
* disagree. Presenting the inferred answer at full blocking authority tells the
|
|
10
|
+
* agent that a gate failed when no gate ever ran.
|
|
11
|
+
*
|
|
12
|
+
* The fix is DEMOTE-WITH-LABEL, never suppress. The live #1640 triage found the
|
|
13
|
+
* inferred-project batch was a MIX: some diagnostics were provably phantom
|
|
14
|
+
* (missing test-runner globals, module resolution), and others were genuine type
|
|
15
|
+
* errors the project's `tsc` gate cannot see precisely BECAUSE the files sit
|
|
16
|
+
* outside every project. Suppression would hide the real ones. Blocking would
|
|
17
|
+
* overstate confidence in the phantom ones. Demoting to warning and naming the
|
|
18
|
+
* config gap preserves the signal and hands the verification burden to the
|
|
19
|
+
* person who can close it.
|
|
20
|
+
*
|
|
21
|
+
* Every "we do not know" path leaves the diagnostics untouched. An unanswered
|
|
22
|
+
* `projectInfo` probe is not a verdict (AGENTS.md shape 10).
|
|
23
|
+
*/
|
|
24
|
+
import * as path from "node:path";
|
|
25
|
+
import { fetchTsserverProjectIdentity, } from "./tsserver-sync.js";
|
|
26
|
+
import { toProjectRelativePath } from "../path-utils.js";
|
|
27
|
+
import { logLatency } from "../latency-logger.js";
|
|
28
|
+
/**
|
|
29
|
+
* The stable, greppable half of the label. Tests and renderers match on this;
|
|
30
|
+
* the actionable `add <glob>` half varies per file.
|
|
31
|
+
*
|
|
32
|
+
* Sibling of `STALE_LINE_MARKER` (`clients/runtime-turn.ts`) — same idea: a
|
|
33
|
+
* finding that survives at reduced authority says so in its own text, so no
|
|
34
|
+
* downstream renderer has to be taught about the demotion separately.
|
|
35
|
+
*/
|
|
36
|
+
export const INFERRED_PROJECT_MARKER = "not in any tsconfig project — checked with inferred settings";
|
|
37
|
+
/** Extensions tsserver owns. A file outside this set never reaches the probe. */
|
|
38
|
+
const TS_PROJECT_EXTENSIONS = new Set([
|
|
39
|
+
".ts",
|
|
40
|
+
".tsx",
|
|
41
|
+
".mts",
|
|
42
|
+
".cts",
|
|
43
|
+
".js",
|
|
44
|
+
".jsx",
|
|
45
|
+
".mjs",
|
|
46
|
+
".cjs",
|
|
47
|
+
]);
|
|
48
|
+
/**
|
|
49
|
+
* `source` values the classic typescript-language-server stamps on its own
|
|
50
|
+
* diagnostics. Auxiliary servers sharing the same result (opengrep, typos,
|
|
51
|
+
* zizmor, ast-grep) carry their own source and are NOT affected by a tsconfig
|
|
52
|
+
* gap, so they keep their severity.
|
|
53
|
+
*/
|
|
54
|
+
const TYPESCRIPT_DIAGNOSTIC_SOURCES = new Set(["typescript", "ts", "tsserver"]);
|
|
55
|
+
export function isTsProjectFile(filePath) {
|
|
56
|
+
return TS_PROJECT_EXTENSIONS.has(path.extname(filePath).toLowerCase());
|
|
57
|
+
}
|
|
58
|
+
export function isTypeScriptSourcedDiagnostic(d) {
|
|
59
|
+
return TYPESCRIPT_DIAGNOSTIC_SOURCES.has((d.source ?? "").toLowerCase());
|
|
60
|
+
}
|
|
61
|
+
/**
|
|
62
|
+
* The glob the user should add to a tsconfig `include`. A file at
|
|
63
|
+
* `tests/unit/a.test.ts` yields `tests/**` — the top-level directory is what a
|
|
64
|
+
* person actually adds, and it is what the #1640 report itself asked for. A
|
|
65
|
+
* file sitting directly in the project root yields its own relative path, since
|
|
66
|
+
* there is no containing directory to name.
|
|
67
|
+
*/
|
|
68
|
+
export function suggestTsconfigInclude(filePath, cwd) {
|
|
69
|
+
const relative = toProjectRelativePath(filePath, cwd);
|
|
70
|
+
if (path.posix.isAbsolute(relative) || /^[A-Za-z]:/.test(relative)) {
|
|
71
|
+
// Outside the project root: name the file's own directory instead of
|
|
72
|
+
// inventing a root-relative glob that would not match anything.
|
|
73
|
+
const dir = relative.slice(0, relative.lastIndexOf("/"));
|
|
74
|
+
return dir ? `${dir}/**` : relative;
|
|
75
|
+
}
|
|
76
|
+
const segments = relative.split("/").filter(Boolean);
|
|
77
|
+
return segments.length > 1 ? `${segments[0]}/**` : relative;
|
|
78
|
+
}
|
|
79
|
+
/** The full label appended to a demoted diagnostic's message. */
|
|
80
|
+
export function inferredProjectNotice(filePath, cwd) {
|
|
81
|
+
return `[${INFERRED_PROJECT_MARKER}; add ${suggestTsconfigInclude(filePath, cwd)} to a tsconfig for authoritative checking]`;
|
|
82
|
+
}
|
|
83
|
+
/**
|
|
84
|
+
* Pure transform: demote every TypeScript-sourced ERROR to a warning and append
|
|
85
|
+
* the label. Warnings, hints, and auxiliary-sourced findings are returned
|
|
86
|
+
* untouched — they were never blockers, so relabelling them would be noise.
|
|
87
|
+
*
|
|
88
|
+
* Returns the SAME array reference when nothing changed, so callers can cheaply
|
|
89
|
+
* skip rebuilding their result objects.
|
|
90
|
+
*/
|
|
91
|
+
export function applyInferredProjectDemotion(diagnostics, filePath, cwd) {
|
|
92
|
+
if (!diagnostics.some(isDemotableDiagnostic))
|
|
93
|
+
return diagnostics;
|
|
94
|
+
const notice = inferredProjectNotice(filePath, cwd);
|
|
95
|
+
return diagnostics.map((d) => isDemotableDiagnostic(d)
|
|
96
|
+
? { ...d, severity: 2, message: `${d.message} ${notice}` }
|
|
97
|
+
: d);
|
|
98
|
+
}
|
|
99
|
+
function isDemotableDiagnostic(d) {
|
|
100
|
+
return d.severity === 1 && isTypeScriptSourcedDiagnostic(d);
|
|
101
|
+
}
|
|
102
|
+
/**
|
|
103
|
+
* Probe project membership for `filePath` and demote its diagnostics when
|
|
104
|
+
* tsserver answers "inferred project".
|
|
105
|
+
*
|
|
106
|
+
* Short-circuits BEFORE any probe when there is nothing a demotion could change:
|
|
107
|
+
* a non-TypeScript file, or a diagnostic list with no TypeScript-sourced error
|
|
108
|
+
* in it. So a clean sweep pays nothing, and a sweep over 500 clean files issues
|
|
109
|
+
* zero extra requests.
|
|
110
|
+
*/
|
|
111
|
+
export async function demoteInferredProjectDiagnostics(diagnostics, options) {
|
|
112
|
+
const { filePath, cwd, service } = options;
|
|
113
|
+
if (!isTsProjectFile(filePath))
|
|
114
|
+
return diagnostics;
|
|
115
|
+
if (!diagnostics.some(isDemotableDiagnostic))
|
|
116
|
+
return diagnostics;
|
|
117
|
+
if (options.signal?.aborted)
|
|
118
|
+
return diagnostics;
|
|
119
|
+
const fetchIdentity = options.fetchIdentity ?? fetchTsserverProjectIdentity;
|
|
120
|
+
const cache = options.identityCache;
|
|
121
|
+
let identity;
|
|
122
|
+
if (cache?.has(filePath)) {
|
|
123
|
+
identity = cache.get(filePath);
|
|
124
|
+
}
|
|
125
|
+
else {
|
|
126
|
+
identity = await fetchIdentity(service, filePath);
|
|
127
|
+
cache?.set(filePath, identity);
|
|
128
|
+
}
|
|
129
|
+
// `undefined` (probe unavailable/failed) and "unassociated" (tsserver named
|
|
130
|
+
// no project at all) are both UNKNOWN, not "inferred". Demoting on either
|
|
131
|
+
// would downgrade real blockers on any server that does not speak the
|
|
132
|
+
// tsserverRequest escape hatch.
|
|
133
|
+
if (identity?.projectKind !== "inferred")
|
|
134
|
+
return diagnostics;
|
|
135
|
+
return applyInferredProjectDemotion(diagnostics, filePath, cwd);
|
|
136
|
+
}
|
|
137
|
+
/**
|
|
138
|
+
* Cap on how many `projectInfo` probes one sweep may issue. Only files that
|
|
139
|
+
* actually carry a TypeScript error probe at all, so on a healthy project this
|
|
140
|
+
* is never approached. Past the cap, membership stays UNKNOWN and nothing is
|
|
141
|
+
* demoted — the fail-safe direction is the pre-#1640 behavior, not a silent
|
|
142
|
+
* mass demotion.
|
|
143
|
+
*/
|
|
144
|
+
export const INFERRED_PROJECT_PROBE_BUDGET = 300;
|
|
145
|
+
/**
|
|
146
|
+
* Sweep-wide entry point: demote every result whose file tsserver owns only
|
|
147
|
+
* through an inferred project. Sequential on purpose — the probes run against a
|
|
148
|
+
* single-threaded tsserver, so fanning out would only queue behind itself.
|
|
149
|
+
*
|
|
150
|
+
* The identity memo is local to this call. A module-level cache would pin the
|
|
151
|
+
* first sweep's verdict for the life of the process, and editing a tsconfig is
|
|
152
|
+
* precisely what changes the answer.
|
|
153
|
+
*
|
|
154
|
+
* The loop honors the caller's abort signal between files. The sweep that
|
|
155
|
+
* produced these results is itself signal-bounded, so continuing to probe after
|
|
156
|
+
* an abort would spend budget on an answer nobody will read (#1645 review F1).
|
|
157
|
+
*/
|
|
158
|
+
export async function demoteInferredProjectSweepResults(results, cwd, service, signal) {
|
|
159
|
+
if (typeof service?.executeReadOnlyCommandOnLiveClient !== "function") {
|
|
160
|
+
return results;
|
|
161
|
+
}
|
|
162
|
+
const startedAt = Date.now();
|
|
163
|
+
const identityCache = new Map();
|
|
164
|
+
const out = [];
|
|
165
|
+
let demotedFiles = 0;
|
|
166
|
+
let demotedDiagnostics = 0;
|
|
167
|
+
let budgetExhausted = false;
|
|
168
|
+
let aborted = false;
|
|
169
|
+
for (const result of results) {
|
|
170
|
+
const diagnostics = result.diagnostics ?? [];
|
|
171
|
+
if (signal?.aborted) {
|
|
172
|
+
// Carry the remaining results through UNCHANGED rather than dropping
|
|
173
|
+
// them — an abort must cost the demotion, never a finding.
|
|
174
|
+
aborted = true;
|
|
175
|
+
out.push(result);
|
|
176
|
+
continue;
|
|
177
|
+
}
|
|
178
|
+
if (identityCache.size >= INFERRED_PROJECT_PROBE_BUDGET && !identityCache.has(result.filePath)) {
|
|
179
|
+
budgetExhausted = true;
|
|
180
|
+
out.push(result);
|
|
181
|
+
continue;
|
|
182
|
+
}
|
|
183
|
+
const demoted = await demoteInferredProjectDiagnostics(diagnostics, {
|
|
184
|
+
filePath: result.filePath,
|
|
185
|
+
cwd,
|
|
186
|
+
service,
|
|
187
|
+
identityCache,
|
|
188
|
+
signal,
|
|
189
|
+
});
|
|
190
|
+
if (demoted === diagnostics) {
|
|
191
|
+
out.push(result);
|
|
192
|
+
continue;
|
|
193
|
+
}
|
|
194
|
+
demotedFiles += 1;
|
|
195
|
+
demotedDiagnostics += demoted.filter((d, i) => d !== diagnostics[i]).length;
|
|
196
|
+
out.push({ ...result, diagnostics: demoted });
|
|
197
|
+
}
|
|
198
|
+
if (demotedFiles > 0 || budgetExhausted || aborted) {
|
|
199
|
+
logLatency({
|
|
200
|
+
type: "phase",
|
|
201
|
+
phase: "lsp_inferred_project_demote",
|
|
202
|
+
filePath: cwd,
|
|
203
|
+
durationMs: Date.now() - startedAt,
|
|
204
|
+
metadata: {
|
|
205
|
+
filesConsidered: results.length,
|
|
206
|
+
filesProbed: identityCache.size,
|
|
207
|
+
demotedFiles,
|
|
208
|
+
demotedDiagnostics,
|
|
209
|
+
budgetExhausted,
|
|
210
|
+
aborted,
|
|
211
|
+
},
|
|
212
|
+
});
|
|
213
|
+
}
|
|
214
|
+
return out;
|
|
215
|
+
}
|
|
@@ -15,9 +15,11 @@
|
|
|
15
15
|
import { existsSync, readdirSync } from "node:fs";
|
|
16
16
|
import os from "node:os";
|
|
17
17
|
import path from "node:path";
|
|
18
|
+
import { classifyProbeFailure, createAvailabilityLatch, logAvailabilityDecision, startHostStallSampler, } from "../dispatch/runners/utils/availability-policy.js";
|
|
18
19
|
import { getGlobalPiLensDir } from "../file-utils.js";
|
|
19
|
-
import {
|
|
20
|
+
import { safeSpawnAsync } from "../safe-spawn.js";
|
|
20
21
|
const JAVA_EXE = process.platform === "win32" ? "java.exe" : "java";
|
|
22
|
+
const JAVA_PROBE_TIMEOUT_MS = 5_000;
|
|
21
23
|
/** jdtls requires a JDK ≥ 17 to run; recent builds prefer 21. */
|
|
22
24
|
const MIN_JAVA_MAJOR = 17;
|
|
23
25
|
/**
|
|
@@ -124,35 +126,165 @@ export function discoverJdkHome(roots = candidateRoots(), javaHome = process.env
|
|
|
124
126
|
return usable[0].home;
|
|
125
127
|
}
|
|
126
128
|
let _cachedEnv;
|
|
129
|
+
/**
|
|
130
|
+
* Availability latch for the `java` PATH probe (#1538, the #1467 latch family's
|
|
131
|
+
* benign-direction sibling). A stalled probe is not evidence the tool is
|
|
132
|
+
* missing — only a genuine "not found" (or a genuinely resolvable `java`) is a
|
|
133
|
+
* durable fact worth caching for the session. A transient verdict (timeout,
|
|
134
|
+
* abort, host stall) expires on the shared cooldown and is re-probed on the
|
|
135
|
+
* next demand instead of pinning whatever `JAVA_HOME` happened to be ambient.
|
|
136
|
+
*/
|
|
137
|
+
const javaAvailabilityLatch = createAvailabilityLatch();
|
|
138
|
+
/**
|
|
139
|
+
* Shared spawn while a probe is in flight (#1538 follow-up). Without this, two
|
|
140
|
+
* concurrent `resolveJavaRuntimeEnv` calls — e.g. a multi-root Java project
|
|
141
|
+
* spawning jdtls per root — each fire their own 5 s `where`/`which java`, and
|
|
142
|
+
* every expired cooldown reopens that window for the process's whole
|
|
143
|
+
* lifetime, not just at startup.
|
|
144
|
+
*/
|
|
145
|
+
let inFlightJavaProbe = null;
|
|
127
146
|
export function _resetJvmRuntimeCacheForTests() {
|
|
128
147
|
_cachedEnv = undefined;
|
|
148
|
+
javaAvailabilityLatch.reset();
|
|
149
|
+
inFlightJavaProbe = null;
|
|
150
|
+
}
|
|
151
|
+
/**
|
|
152
|
+
* Probe `java` on PATH, distinguishing a durable verdict (found, or genuinely
|
|
153
|
+
* absent) from a transient probe failure. Returns `true`/`false` for a durable
|
|
154
|
+
* verdict; `undefined` when the probe was transient — including a memo served
|
|
155
|
+
* from mid-cooldown — so the caller must not treat this call as proof `java`
|
|
156
|
+
* is absent.
|
|
157
|
+
*
|
|
158
|
+
* `AvailabilityLatch.read()` returns `false` (not `null`) for BOTH a durable
|
|
159
|
+
* "not found" AND a transient verdict whose cooldown hasn't expired yet — the
|
|
160
|
+
* latch's own contract is "cache a safe fallback answer for this call", not
|
|
161
|
+
* "this is durable". Blindly forwarding that `false` as durable is exactly
|
|
162
|
+
* the #1538 bug moved one call deeper: jdtls's failed-spawn retry
|
|
163
|
+
* (`BROKEN_BASE_COOLDOWN_MS`, `clients/lsp/index.ts`) re-enters
|
|
164
|
+
* `resolveJavaRuntimeEnv` ~15-20 s later — inside this probe's 30 s transient
|
|
165
|
+
* cooldown — so the very first retry after a stall would otherwise still
|
|
166
|
+
* launder into the permanent `_cachedEnv`. Only `javaAvailabilityLatch`'s own
|
|
167
|
+
* `outcome` distinguishes the two; a durable verdict is never `"transient"`.
|
|
168
|
+
*/
|
|
169
|
+
function probeJavaOnPath() {
|
|
170
|
+
const memo = javaAvailabilityLatch.read();
|
|
171
|
+
if (memo !== null) {
|
|
172
|
+
if (javaAvailabilityLatch.getOutcome() === "transient") {
|
|
173
|
+
// Served from the memo, but the cooldown from the earlier stall
|
|
174
|
+
// hasn't expired — this is NOT a durable verdict. Log it (otherwise
|
|
175
|
+
// this state leaves zero record in latency.log) and surface
|
|
176
|
+
// `undefined` so the caller never writes the session cache.
|
|
177
|
+
logAvailabilityDecision({
|
|
178
|
+
tool: "java",
|
|
179
|
+
verdict: "unavailable",
|
|
180
|
+
outcome: "transient",
|
|
181
|
+
cause: javaAvailabilityLatch.getCause() ?? "probe-timeout",
|
|
182
|
+
elapsedMs: 0,
|
|
183
|
+
latched: false,
|
|
184
|
+
retryAfterMs: Math.max(0, javaAvailabilityLatch.getRetryAtMs() - Date.now()),
|
|
185
|
+
budgetMs: JAVA_PROBE_TIMEOUT_MS,
|
|
186
|
+
});
|
|
187
|
+
return Promise.resolve(undefined);
|
|
188
|
+
}
|
|
189
|
+
return Promise.resolve(memo);
|
|
190
|
+
}
|
|
191
|
+
if (inFlightJavaProbe)
|
|
192
|
+
return inFlightJavaProbe;
|
|
193
|
+
inFlightJavaProbe = runJavaProbe().finally(() => {
|
|
194
|
+
inFlightJavaProbe = null;
|
|
195
|
+
});
|
|
196
|
+
return inFlightJavaProbe;
|
|
197
|
+
}
|
|
198
|
+
/** The actual `where`/`which java` spawn + classification. Never call this
|
|
199
|
+
* directly — go through `probeJavaOnPath()`, which memoizes and dedupes it. */
|
|
200
|
+
async function runJavaProbe() {
|
|
201
|
+
const finder = process.platform === "win32" ? "where" : "which";
|
|
202
|
+
const startedAt = Date.now();
|
|
203
|
+
const sampler = startHostStallSampler();
|
|
204
|
+
let result;
|
|
205
|
+
let hostStallMs;
|
|
206
|
+
try {
|
|
207
|
+
result = await safeSpawnAsync(finder, ["java"], {
|
|
208
|
+
timeout: JAVA_PROBE_TIMEOUT_MS,
|
|
209
|
+
});
|
|
210
|
+
}
|
|
211
|
+
finally {
|
|
212
|
+
hostStallMs = sampler.stop();
|
|
213
|
+
}
|
|
214
|
+
const elapsedMs = Date.now() - startedAt;
|
|
215
|
+
if (result.status === 0 && !result.error) {
|
|
216
|
+
javaAvailabilityLatch.noteAvailable();
|
|
217
|
+
logAvailabilityDecision({
|
|
218
|
+
tool: "java",
|
|
219
|
+
verdict: "available",
|
|
220
|
+
outcome: "success",
|
|
221
|
+
cause: "ok",
|
|
222
|
+
elapsedMs,
|
|
223
|
+
latched: true,
|
|
224
|
+
hostStallMs,
|
|
225
|
+
budgetMs: JAVA_PROBE_TIMEOUT_MS,
|
|
226
|
+
});
|
|
227
|
+
return true;
|
|
228
|
+
}
|
|
229
|
+
// A `where`/`which` that ran fine and found nothing is a genuine absence,
|
|
230
|
+
// same as a pre-existing #1496/#1467 sibling; anything else (timeout,
|
|
231
|
+
// abort, host stall) is transient and must not latch.
|
|
232
|
+
const { outcome, cause } = classifyProbeFailure(result, {
|
|
233
|
+
hostStallMs,
|
|
234
|
+
unclassifiedFailureOutcome: "missing",
|
|
235
|
+
});
|
|
236
|
+
const retryAfterMs = javaAvailabilityLatch.noteUnavailable(outcome, cause);
|
|
237
|
+
logAvailabilityDecision({
|
|
238
|
+
tool: "java",
|
|
239
|
+
verdict: "unavailable",
|
|
240
|
+
outcome,
|
|
241
|
+
cause,
|
|
242
|
+
elapsedMs,
|
|
243
|
+
latched: outcome !== "transient",
|
|
244
|
+
hostStallMs,
|
|
245
|
+
...(retryAfterMs > 0 && { retryAfterMs }),
|
|
246
|
+
budgetMs: JAVA_PROBE_TIMEOUT_MS,
|
|
247
|
+
});
|
|
248
|
+
return outcome === "transient" ? undefined : false;
|
|
129
249
|
}
|
|
130
250
|
/**
|
|
131
251
|
* Spawn-env overlay that makes a JVM-gated server (jdtls) launch when `java`
|
|
132
252
|
* isn't on PATH. Returns undefined when `java` is already resolvable (respect
|
|
133
253
|
* the user's PATH java) or when no JDK can be discovered (fail as before).
|
|
134
|
-
*
|
|
254
|
+
*
|
|
255
|
+
* Memoized per process — but only once the verdict is durable. A JDK found by
|
|
256
|
+
* filesystem discovery is always safe to cache immediately: `discoverJdkHome`
|
|
257
|
+
* is pure stat/readdir, unaffected by the PATH probe's timing. When no JDK is
|
|
258
|
+
* discovered AND the PATH probe was transient, nothing is cached — the next
|
|
259
|
+
* call re-probes (respecting the latch's own cooldown) instead of pinning a
|
|
260
|
+
* "no override" verdict that a stalled probe never earned (#1538).
|
|
135
261
|
*/
|
|
136
262
|
export async function resolveJavaRuntimeEnv() {
|
|
137
263
|
if (_cachedEnv)
|
|
138
264
|
return _cachedEnv.value;
|
|
139
265
|
// `java` already on PATH — nothing to inject; defer to the user's runtime.
|
|
140
|
-
|
|
266
|
+
const javaOnPath = await probeJavaOnPath();
|
|
267
|
+
if (javaOnPath === true) {
|
|
141
268
|
_cachedEnv = { value: undefined };
|
|
142
269
|
return undefined;
|
|
143
270
|
}
|
|
144
271
|
const home = discoverJdkHome();
|
|
145
|
-
if (
|
|
272
|
+
if (home) {
|
|
273
|
+
const binDir = path.join(home, "bin");
|
|
274
|
+
const currentPath = process.env.PATH ?? process.env.Path ?? "";
|
|
275
|
+
_cachedEnv = {
|
|
276
|
+
value: {
|
|
277
|
+
JAVA_HOME: home,
|
|
278
|
+
PATH: binDir + path.delimiter + currentPath,
|
|
279
|
+
},
|
|
280
|
+
};
|
|
281
|
+
return _cachedEnv.value;
|
|
282
|
+
}
|
|
283
|
+
// No JDK discovered. Cache "no override" only when the PATH probe gave a
|
|
284
|
+
// durable "not found" — a transient probe (timeout/host-stall) must not
|
|
285
|
+
// pin this session to `undefined` forever.
|
|
286
|
+
if (javaOnPath === false) {
|
|
146
287
|
_cachedEnv = { value: undefined };
|
|
147
|
-
return undefined;
|
|
148
288
|
}
|
|
149
|
-
|
|
150
|
-
const currentPath = process.env.PATH ?? process.env.Path ?? "";
|
|
151
|
-
_cachedEnv = {
|
|
152
|
-
value: {
|
|
153
|
-
JAVA_HOME: home,
|
|
154
|
-
PATH: binDir + path.delimiter + currentPath,
|
|
155
|
-
},
|
|
156
|
-
};
|
|
157
|
-
return _cachedEnv.value;
|
|
289
|
+
return undefined;
|
|
158
290
|
}
|
|
@@ -1,10 +1,16 @@
|
|
|
1
1
|
import path from "node:path";
|
|
2
|
+
import { getLanguageId as getKindLanguageId, KIND_EXTENSIONS, SPECIAL_FILENAMES, } from "../file-kinds.js";
|
|
3
|
+
import { getLspCapableKinds } from "../language-policy.js";
|
|
2
4
|
/**
|
|
3
5
|
* Language ID Mappings for LSP
|
|
4
6
|
*
|
|
5
7
|
* Maps file extensions to LSP language identifiers.
|
|
6
8
|
*/
|
|
7
|
-
|
|
9
|
+
// Hand-curated ids, finer-grained than the per-kind registry id: one FileKind
|
|
10
|
+
// can span several language ids (jsts covers typescript/typescriptreact/vue,
|
|
11
|
+
// cxx covers c and cpp), and some servers want a spelling the registry doesn't
|
|
12
|
+
// use ("shellscript", not "shell"). These win over the derived fill-in below.
|
|
13
|
+
const CURATED_LANGUAGE_EXTENSIONS = {
|
|
8
14
|
// JavaScript/TypeScript
|
|
9
15
|
".ts": "typescript",
|
|
10
16
|
".tsx": "typescriptreact",
|
|
@@ -66,7 +72,6 @@ export const LANGUAGE_EXTENSIONS = {
|
|
|
66
72
|
".fish": "fish",
|
|
67
73
|
// CMake
|
|
68
74
|
".cmake": "cmake",
|
|
69
|
-
"CMakeLists.txt": "cmake",
|
|
70
75
|
// JSON/YAML
|
|
71
76
|
".json": "json",
|
|
72
77
|
".jsonc": "jsonc",
|
|
@@ -87,7 +92,6 @@ export const LANGUAGE_EXTENSIONS = {
|
|
|
87
92
|
".sql": "sql",
|
|
88
93
|
// Docker
|
|
89
94
|
".dockerfile": "dockerfile",
|
|
90
|
-
"Dockerfile": "dockerfile",
|
|
91
95
|
// Terraform
|
|
92
96
|
".tf": "terraform",
|
|
93
97
|
".tfvars": "terraform",
|
|
@@ -157,6 +161,44 @@ export const LANGUAGE_EXTENSIONS = {
|
|
|
157
161
|
".typ": "typst",
|
|
158
162
|
".typc": "typst",
|
|
159
163
|
};
|
|
164
|
+
/**
|
|
165
|
+
* Curated ids plus a derived fill-in for every extension an lspCapable kind
|
|
166
|
+
* registers. Before #1545 this table was hand-maintained alone and had drifted:
|
|
167
|
+
* powershell had no entry at all and cxx covered a third of its extensions, so
|
|
168
|
+
* `didOpen` announced those files as "plaintext". Tolerance for that varies by
|
|
169
|
+
* server — json/yaml/clangd answer the same either way, a DocumentSelector
|
|
170
|
+
* server may not handle the document at all — so the id is sent correctly
|
|
171
|
+
* rather than relied on being ignored. A newly registered language now reaches
|
|
172
|
+
* this seam by being lspCapable.
|
|
173
|
+
*/
|
|
174
|
+
export const LANGUAGE_EXTENSIONS = (() => {
|
|
175
|
+
const map = { ...CURATED_LANGUAGE_EXTENSIONS };
|
|
176
|
+
for (const kind of getLspCapableKinds()) {
|
|
177
|
+
for (const extension of KIND_EXTENSIONS[kind]) {
|
|
178
|
+
map[extension] ??= getKindLanguageId(kind);
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
return map;
|
|
182
|
+
})();
|
|
183
|
+
/**
|
|
184
|
+
* file-kinds.ts's basename classifier (Makefile, Dockerfile.<suffix>,
|
|
185
|
+
* CMakeLists.txt, …) matches by regex, not literal filename, so it can't be
|
|
186
|
+
* flattened into LANGUAGE_EXTENSIONS' literal-key map. Derived from
|
|
187
|
+
* SPECIAL_FILENAMES — the same single source of truth detectFileKind() uses —
|
|
188
|
+
* filtered to lspCapable kinds so a basename pattern that classifies into an
|
|
189
|
+
* lspCapable kind always resolves a language id here too (#1594).
|
|
190
|
+
*/
|
|
191
|
+
const BASENAME_LANGUAGE_PATTERNS = (() => {
|
|
192
|
+
const lspCapableKinds = new Set(getLspCapableKinds());
|
|
193
|
+
return SPECIAL_FILENAMES.filter(({ kind }) => lspCapableKinds.has(kind)).map(({ pattern, kind }) => ({
|
|
194
|
+
pattern,
|
|
195
|
+
languageId: getKindLanguageId(kind),
|
|
196
|
+
}));
|
|
197
|
+
})();
|
|
198
|
+
function getBasenameLanguageId(base) {
|
|
199
|
+
return BASENAME_LANGUAGE_PATTERNS.find(({ pattern }) => pattern.test(base))
|
|
200
|
+
?.languageId;
|
|
201
|
+
}
|
|
160
202
|
/**
|
|
161
203
|
* Get language ID for a file path
|
|
162
204
|
*/
|
|
@@ -166,7 +208,9 @@ export function getLanguageId(filePath) {
|
|
|
166
208
|
return LANGUAGE_EXTENSIONS[ext];
|
|
167
209
|
}
|
|
168
210
|
const base = path.basename(filePath);
|
|
169
|
-
return LANGUAGE_EXTENSIONS[base] ??
|
|
211
|
+
return (LANGUAGE_EXTENSIONS[base] ??
|
|
212
|
+
LANGUAGE_EXTENSIONS[base.toLowerCase()] ??
|
|
213
|
+
getBasenameLanguageId(base));
|
|
170
214
|
}
|
|
171
215
|
/**
|
|
172
216
|
* Get all extensions for a language ID
|