@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.
Files changed (343) hide show
  1. package/README.md +5 -5
  2. package/node_modules/@herbertgao/pi-cc-extensions/README.en.md +1 -1
  3. package/node_modules/@herbertgao/pi-cc-extensions/README.md +1 -1
  4. package/node_modules/@herbertgao/pi-cc-extensions/extensions/config/config.ts +19 -7
  5. package/node_modules/@herbertgao/pi-cc-extensions/extensions/config/panel.ts +30 -9
  6. package/node_modules/@herbertgao/pi-cc-extensions/extensions/feature/compact-thinking.ts +272 -22
  7. package/node_modules/@herbertgao/pi-cc-extensions/extensions/renderer/compact-mode.ts +94 -77
  8. package/node_modules/@herbertgao/pi-cc-extensions/extensions/renderer/message-display.ts +1 -1
  9. package/node_modules/@herbertgao/pi-cc-extensions/extensions/renderer/mouse/hover.ts +14 -0
  10. package/node_modules/@herbertgao/pi-cc-extensions/extensions/renderer/mouse/interaction.ts +55 -17
  11. package/node_modules/@herbertgao/pi-cc-extensions/extensions/renderer/mouse/layout.ts +41 -2
  12. package/node_modules/@herbertgao/pi-cc-extensions/extensions/renderer/tool/diff/diff-renderer.ts +75 -6
  13. package/node_modules/@herbertgao/pi-cc-extensions/extensions/renderer/tool/diff/types.ts +7 -3
  14. package/node_modules/@herbertgao/pi-cc-extensions/extensions/renderer/tool/grouping.ts +64 -1
  15. package/node_modules/@herbertgao/pi-cc-extensions/package.json +3 -3
  16. package/node_modules/@herbertgao/pi-subagents/CHANGELOG.md +6 -0
  17. package/node_modules/@herbertgao/pi-subagents/README.md +30 -22
  18. package/node_modules/@herbertgao/pi-subagents/examples/agent-tool-description.md +5 -5
  19. package/node_modules/@herbertgao/pi-subagents/package.json +7 -7
  20. package/node_modules/@herbertgao/pi-subagents/src/agent-file-toggle.ts +7 -1
  21. package/node_modules/@herbertgao/pi-subagents/src/agent-manager.ts +48 -19
  22. package/node_modules/@herbertgao/pi-subagents/src/agent-runner.ts +17 -13
  23. package/node_modules/@herbertgao/pi-subagents/src/custom-agents.ts +26 -2
  24. package/node_modules/@herbertgao/pi-subagents/src/index.ts +219 -40
  25. package/node_modules/@herbertgao/pi-subagents/src/invocation-config.ts +101 -3
  26. package/node_modules/@herbertgao/pi-subagents/src/nested-tools.ts +18 -4
  27. package/node_modules/@herbertgao/pi-subagents/src/settings.ts +99 -0
  28. package/node_modules/@herbertgao/pi-subagents/src/types.ts +22 -3
  29. package/node_modules/@herbertgao/pi-subagents/src/ui/agent-widget.ts +51 -3
  30. package/node_modules/@herbertgao/pi-subagents/src/ui/conversation-viewer.ts +20 -2
  31. package/node_modules/@herbertgao/pi-subagents/src/ui/fleet-list.ts +21 -6
  32. package/node_modules/@herbertgao/pi-subagents/src/usage.ts +129 -1
  33. package/node_modules/@herbertgao/pi-subagents/src/worktree.ts +20 -0
  34. package/node_modules/@juicesharp/rpiv-ask-user-question/README.md +1 -0
  35. package/node_modules/@juicesharp/rpiv-ask-user-question/ask-user-question.ts +26 -10
  36. package/node_modules/@juicesharp/rpiv-ask-user-question/config.ts +25 -0
  37. package/node_modules/@juicesharp/rpiv-ask-user-question/docs/configuration.md +13 -4
  38. package/node_modules/@juicesharp/rpiv-ask-user-question/docs/hosts.md +2 -1
  39. package/node_modules/@juicesharp/rpiv-ask-user-question/docs/localization.md +3 -1
  40. package/node_modules/@juicesharp/rpiv-ask-user-question/locales/en.json +2 -2
  41. package/node_modules/@juicesharp/rpiv-ask-user-question/locales/zh.json +2 -2
  42. package/node_modules/@juicesharp/rpiv-ask-user-question/package.json +3 -2
  43. package/node_modules/@juicesharp/rpiv-ask-user-question/state/build-questionnaire.ts +10 -0
  44. package/node_modules/@juicesharp/rpiv-ask-user-question/state/key-router.ts +3 -1
  45. package/node_modules/@juicesharp/rpiv-ask-user-question/state/questionnaire-session.ts +30 -7
  46. package/node_modules/@juicesharp/rpiv-ask-user-question/state/state.ts +14 -6
  47. package/node_modules/@juicesharp/rpiv-ask-user-question/view/dialog-builder.ts +30 -4
  48. package/node_modules/@juicesharp/rpiv-ask-user-question/view/tab-content-strategy.ts +26 -5
  49. package/node_modules/@narumitw/pi-btw/README.md +120 -111
  50. package/node_modules/@narumitw/pi-btw/dist/index.ts +2898 -0
  51. package/node_modules/@narumitw/pi-btw/dist/index.ts.map +7 -0
  52. package/node_modules/@narumitw/pi-btw/package.json +10 -6
  53. package/node_modules/@narumitw/pi-btw/src/btw.ts +36 -40
  54. package/node_modules/@narumitw/pi-btw/src/fullscreen-ui.ts +55 -10
  55. package/node_modules/@narumitw/pi-btw/src/main-tree-picker.ts +390 -0
  56. package/node_modules/@narumitw/pi-btw/src/menu.ts +45 -2
  57. package/node_modules/@narumitw/pi-btw/src/transcript-pager.ts +136 -45
  58. package/node_modules/pi-lens/CHANGELOG.md +909 -0
  59. package/node_modules/pi-lens/README.md +11 -3
  60. package/node_modules/pi-lens/config/ruff/core.toml +42 -0
  61. package/node_modules/pi-lens/dist/clients/actionable-warnings.js +130 -27
  62. package/node_modules/pi-lens/dist/clients/advisory-provenance.js +126 -13
  63. package/node_modules/pi-lens/dist/clients/agent-nudge.js +67 -11
  64. package/node_modules/pi-lens/dist/clients/ast-grep-client.js +9 -3
  65. package/node_modules/pi-lens/dist/clients/atomic-write.js +9 -3
  66. package/node_modules/pi-lens/dist/clients/bash-file-access.js +285 -8
  67. package/node_modules/pi-lens/dist/clients/biome-client.js +61 -30
  68. package/node_modules/pi-lens/dist/clients/blocker-freshness.js +428 -0
  69. package/node_modules/pi-lens/dist/clients/blocker-past-eof.js +119 -0
  70. package/node_modules/pi-lens/dist/clients/bootstrap.js +12 -1
  71. package/node_modules/pi-lens/dist/clients/bounded-pid-file-lock.js +12 -3
  72. package/node_modules/pi-lens/dist/clients/bounded-telemetry.js +192 -0
  73. package/node_modules/pi-lens/dist/clients/cascade-budget.js +196 -0
  74. package/node_modules/pi-lens/dist/clients/cascade-format.js +20 -1
  75. package/node_modules/pi-lens/dist/clients/cascade-types.js +9 -1
  76. package/node_modules/pi-lens/dist/clients/child-unref.js +54 -6
  77. package/node_modules/pi-lens/dist/clients/code-quality-warnings.js +76 -24
  78. package/node_modules/pi-lens/dist/clients/dead-code-client.js +123 -31
  79. package/node_modules/pi-lens/dist/clients/deadline-utils.js +8 -1
  80. package/node_modules/pi-lens/dist/clients/debug-handles.js +5 -0
  81. package/node_modules/pi-lens/dist/clients/degradation-ledger.js +62 -13
  82. package/node_modules/pi-lens/dist/clients/dependency-checker.js +25 -3
  83. package/node_modules/pi-lens/dist/clients/diagnostic-dispositions.js +147 -33
  84. package/node_modules/pi-lens/dist/clients/diagnostic-line-freshness.js +298 -0
  85. package/node_modules/pi-lens/dist/clients/dispatch/dispatcher.js +52 -2
  86. package/node_modules/pi-lens/dist/clients/dispatch/integration.js +256 -88
  87. package/node_modules/pi-lens/dist/clients/dispatch/lazy.js +7 -4
  88. package/node_modules/pi-lens/dist/clients/dispatch/plan.js +5 -0
  89. package/node_modules/pi-lens/dist/clients/dispatch/runners/ast-grep-napi.js +234 -18
  90. package/node_modules/pi-lens/dist/clients/dispatch/runners/biome-check.js +187 -19
  91. package/node_modules/pi-lens/dist/clients/dispatch/runners/cpp-check.js +6 -3
  92. package/node_modules/pi-lens/dist/clients/dispatch/runners/credo.js +11 -9
  93. package/node_modules/pi-lens/dist/clients/dispatch/runners/cue-vet.js +398 -0
  94. package/node_modules/pi-lens/dist/clients/dispatch/runners/elixir-check.js +11 -3
  95. package/node_modules/pi-lens/dist/clients/dispatch/runners/eslint.js +12 -7
  96. package/node_modules/pi-lens/dist/clients/dispatch/runners/go-vet.js +18 -0
  97. package/node_modules/pi-lens/dist/clients/dispatch/runners/helm-render.js +895 -0
  98. package/node_modules/pi-lens/dist/clients/dispatch/runners/index.js +4 -0
  99. package/node_modules/pi-lens/dist/clients/dispatch/runners/javac.js +16 -3
  100. package/node_modules/pi-lens/dist/clients/dispatch/runners/lsp.js +60 -53
  101. package/node_modules/pi-lens/dist/clients/dispatch/runners/markdownlint.js +16 -0
  102. package/node_modules/pi-lens/dist/clients/dispatch/runners/mypy.js +23 -0
  103. package/node_modules/pi-lens/dist/clients/dispatch/runners/psscriptanalyzer.js +331 -55
  104. package/node_modules/pi-lens/dist/clients/dispatch/runners/pyright.js +38 -5
  105. package/node_modules/pi-lens/dist/clients/dispatch/runners/rust-clippy.js +97 -19
  106. package/node_modules/pi-lens/dist/clients/dispatch/runners/spellcheck.js +14 -0
  107. package/node_modules/pi-lens/dist/clients/dispatch/runners/sqlfluff.js +20 -0
  108. package/node_modules/pi-lens/dist/clients/dispatch/runners/stylelint.js +22 -0
  109. package/node_modules/pi-lens/dist/clients/dispatch/runners/swiftlint.js +10 -0
  110. package/node_modules/pi-lens/dist/clients/dispatch/runners/taplo.js +18 -6
  111. package/node_modules/pi-lens/dist/clients/dispatch/runners/trivy-config.js +73 -12
  112. package/node_modules/pi-lens/dist/clients/dispatch/runners/utils/availability-policy.js +275 -13
  113. package/node_modules/pi-lens/dist/clients/dispatch/runners/utils/candidate-probe.js +21 -6
  114. package/node_modules/pi-lens/dist/clients/dispatch/runners/utils/lazy-installer.js +260 -27
  115. package/node_modules/pi-lens/dist/clients/dispatch/runners/utils/runner-helpers.js +734 -64
  116. package/node_modules/pi-lens/dist/clients/dispatch/runners/utils/spawn-outcome.js +86 -11
  117. package/node_modules/pi-lens/dist/clients/dispatch/runners/utils/tool-failure.js +72 -0
  118. package/node_modules/pi-lens/dist/clients/dispatch/runners/utils/toolchain-availability.js +9 -0
  119. package/node_modules/pi-lens/dist/clients/dispatch/runners/vale.js +9 -0
  120. package/node_modules/pi-lens/dist/clients/dispatch/runners/yamllint.js +18 -1
  121. package/node_modules/pi-lens/dist/clients/dispatch/runners/zig-check.js +4 -2
  122. package/node_modules/pi-lens/dist/clients/event-loop-monitor.js +28 -5
  123. package/node_modules/pi-lens/dist/clients/extension-log.js +22 -1
  124. package/node_modules/pi-lens/dist/clients/file-kinds.js +8 -2
  125. package/node_modules/pi-lens/dist/clients/finding-delivery-gate.js +294 -0
  126. package/node_modules/pi-lens/dist/clients/finding-identity.js +88 -0
  127. package/node_modules/pi-lens/dist/clients/formatters-lazy.js +3 -2
  128. package/node_modules/pi-lens/dist/clients/formatters.js +500 -115
  129. package/node_modules/pi-lens/dist/clients/generation-guard.js +216 -0
  130. package/node_modules/pi-lens/dist/clients/git-guard.js +31 -0
  131. package/node_modules/pi-lens/dist/clients/gitleaks-client.js +181 -8
  132. package/node_modules/pi-lens/dist/clients/govulncheck-client.js +109 -9
  133. package/node_modules/pi-lens/dist/clients/grammar-source.js +333 -10
  134. package/node_modules/pi-lens/dist/clients/host-ports.js +8 -0
  135. package/node_modules/pi-lens/dist/clients/installer/index.js +1114 -100
  136. package/node_modules/pi-lens/dist/clients/installer/managed-tool-refresh-session.js +58 -0
  137. package/node_modules/pi-lens/dist/clients/installer/managed-tool-refresh.js +715 -0
  138. package/node_modules/pi-lens/dist/clients/instance-reaper.js +643 -97
  139. package/node_modules/pi-lens/dist/clients/instance-registry.js +87 -17
  140. package/node_modules/pi-lens/dist/clients/jscpd-client.js +82 -6
  141. package/node_modules/pi-lens/dist/clients/knip-client.js +310 -10
  142. package/node_modules/pi-lens/dist/clients/language-policy.js +8 -2
  143. package/node_modules/pi-lens/dist/clients/language-profile.js +2 -0
  144. package/node_modules/pi-lens/dist/clients/latency-logger.js +440 -11
  145. package/node_modules/pi-lens/dist/clients/lazy-import.js +21 -0
  146. package/node_modules/pi-lens/dist/clients/ledger-bounds.js +21 -0
  147. package/node_modules/pi-lens/dist/clients/lens-flag-registry.js +8 -0
  148. package/node_modules/pi-lens/dist/clients/lsp/cascade-tier.js +102 -7
  149. package/node_modules/pi-lens/dist/clients/lsp/client.js +1516 -159
  150. package/node_modules/pi-lens/dist/clients/lsp/diagnostic-binding.js +83 -1
  151. package/node_modules/pi-lens/dist/clients/lsp/document-drift.js +389 -0
  152. package/node_modules/pi-lens/dist/clients/lsp/index.js +2274 -147
  153. package/node_modules/pi-lens/dist/clients/lsp/inferred-project.js +215 -0
  154. package/node_modules/pi-lens/dist/clients/lsp/jvm-runtime.js +146 -14
  155. package/node_modules/pi-lens/dist/clients/lsp/language.js +48 -4
  156. package/node_modules/pi-lens/dist/clients/lsp/server.js +277 -16
  157. package/node_modules/pi-lens/dist/clients/lsp/spawn-history.js +22 -0
  158. package/node_modules/pi-lens/dist/clients/lsp/sync-kind.js +43 -0
  159. package/node_modules/pi-lens/dist/clients/lsp/tsserver-sync.js +79 -3
  160. package/node_modules/pi-lens/dist/clients/lsp/wait-policy/strategies.js +43 -0
  161. package/node_modules/pi-lens/dist/clients/lsp/workspace-diagnostics-cache.js +422 -28
  162. package/node_modules/pi-lens/dist/clients/lsp/workspace-diagnostics-session.js +30 -0
  163. package/node_modules/pi-lens/dist/clients/lsp/workspace-sweep-hold.js +175 -0
  164. package/node_modules/pi-lens/dist/clients/lsp-lazy.js +3 -2
  165. package/node_modules/pi-lens/dist/clients/mcp/session.js +10 -2
  166. package/node_modules/pi-lens/dist/clients/module-report.js +8 -0
  167. package/node_modules/pi-lens/dist/clients/opengrep-client.js +15 -1
  168. package/node_modules/pi-lens/dist/clients/package-manager.js +170 -14
  169. package/node_modules/pi-lens/dist/clients/path-attribution-telemetry.js +27 -0
  170. package/node_modules/pi-lens/dist/clients/path-utils.js +160 -0
  171. package/node_modules/pi-lens/dist/clients/pipeline.js +154 -33
  172. package/node_modules/pi-lens/dist/clients/post-autofix-notice.js +37 -0
  173. package/node_modules/pi-lens/dist/clients/project-diagnostics/cache.js +17 -3
  174. package/node_modules/pi-lens/dist/clients/project-diagnostics/extractors.js +89 -22
  175. package/node_modules/pi-lens/dist/clients/project-diagnostics/fresh-fetch.js +84 -14
  176. package/node_modules/pi-lens/dist/clients/project-diagnostics/runner-adapters/gitleaks.js +15 -3
  177. package/node_modules/pi-lens/dist/clients/project-diagnostics/runner-adapters/trivy.js +50 -2
  178. package/node_modules/pi-lens/dist/clients/project-diagnostics/scanner.js +5 -0
  179. package/node_modules/pi-lens/dist/clients/project-lens-config.js +3 -0
  180. package/node_modules/pi-lens/dist/clients/project-snapshot.js +299 -0
  181. package/node_modules/pi-lens/dist/clients/quiet-window-config.js +47 -0
  182. package/node_modules/pi-lens/dist/clients/quiet-window.js +11 -25
  183. package/node_modules/pi-lens/dist/clients/read-guard-logger.js +1 -1
  184. package/node_modules/pi-lens/dist/clients/read-guard.js +184 -10
  185. package/node_modules/pi-lens/dist/clients/resource-sampler.js +49 -17
  186. package/node_modules/pi-lens/dist/clients/reverse-deps.js +50 -11
  187. package/node_modules/pi-lens/dist/clients/review-graph/query.js +52 -4
  188. package/node_modules/pi-lens/dist/clients/runtime-agent-end.js +96 -7
  189. package/node_modules/pi-lens/dist/clients/runtime-context.js +8 -1
  190. package/node_modules/pi-lens/dist/clients/runtime-coordinator.js +308 -45
  191. package/node_modules/pi-lens/dist/clients/runtime-session.js +332 -9
  192. package/node_modules/pi-lens/dist/clients/runtime-tool-call.js +217 -22
  193. package/node_modules/pi-lens/dist/clients/runtime-tool-result.js +212 -79
  194. package/node_modules/pi-lens/dist/clients/runtime-turn.js +575 -67
  195. package/node_modules/pi-lens/dist/clients/safe-spawn.js +220 -7
  196. package/node_modules/pi-lens/dist/clients/scratch-tree-policy.js +161 -0
  197. package/node_modules/pi-lens/dist/clients/search-read-registration.js +34 -6
  198. package/node_modules/pi-lens/dist/clients/security-scan-client.js +157 -24
  199. package/node_modules/pi-lens/dist/clients/sg-runner.js +116 -22
  200. package/node_modules/pi-lens/dist/clients/single-flight.js +158 -0
  201. package/node_modules/pi-lens/dist/clients/stale-marker.js +17 -0
  202. package/node_modules/pi-lens/dist/clients/startup-timing.js +19 -1
  203. package/node_modules/pi-lens/dist/clients/test-runner-client.js +151 -16
  204. package/node_modules/pi-lens/dist/clients/tool-event.js +56 -5
  205. package/node_modules/pi-lens/dist/clients/tool-policy.js +125 -20
  206. package/node_modules/pi-lens/dist/clients/tree-sitter-cache.js +75 -1
  207. package/node_modules/pi-lens/dist/clients/tree-sitter-client.js +769 -64
  208. package/node_modules/pi-lens/dist/clients/tree-sitter-shared.js +11 -0
  209. package/node_modules/pi-lens/dist/clients/tree-sitter-symbol-extractor.js +90 -0
  210. package/node_modules/pi-lens/dist/clients/trivy-client.js +19 -1
  211. package/node_modules/pi-lens/dist/clients/widget-state.js +336 -36
  212. package/node_modules/pi-lens/dist/clients/zizmor-config.js +214 -14
  213. package/node_modules/pi-lens/dist/index.js +67738 -55739
  214. package/node_modules/pi-lens/dist/tools/lens-diagnostics.js +466 -54
  215. package/node_modules/pi-lens/dist/tools/lsp-diagnostics.js +132 -43
  216. package/node_modules/pi-lens/dist/tools/lsp-navigation.js +46 -7
  217. package/node_modules/pi-lens/docs/agent-guide.md +6 -1
  218. package/node_modules/pi-lens/docs/ast-grep_rules_catalog.md +515 -506
  219. package/node_modules/pi-lens/docs/dispositions.md +21 -0
  220. package/node_modules/pi-lens/docs/features.md +19 -5
  221. package/node_modules/pi-lens/docs/globalconfig.md +3 -0
  222. package/node_modules/pi-lens/docs/language-coverage.md +71 -5
  223. package/node_modules/pi-lens/docs/mcp.md +2 -2
  224. package/node_modules/pi-lens/docs/servercapabilities.md +4 -1
  225. package/node_modules/pi-lens/docs/settings.md +19 -1
  226. package/node_modules/pi-lens/docs/usage.md +1 -0
  227. package/node_modules/pi-lens/package.json +10 -6
  228. package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/__snapshots__/no-reflect-get-js-snapshot.yml +23 -0
  229. package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/__snapshots__/no-reflect-get-snapshot.yml +23 -0
  230. package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/__snapshots__/ts-void-zero-snapshot.yml +23 -0
  231. package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/no-bare-object-param-test.yml +16 -0
  232. package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/no-chained-type-assertions-test.yml +15 -1
  233. package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/no-compile-call-test.yml +29 -1
  234. package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/no-dupe-class-members-test.yml +33 -0
  235. package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/no-inner-html-js-test.yml +7 -1
  236. package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/no-inner-html-test.yml +7 -1
  237. package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/no-known-value-widening-test.yml +9 -0
  238. package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/no-non-null-assertion-test.yml +216 -0
  239. package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/no-reflect-apply-js-test.yml +2 -0
  240. package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/no-reflect-apply-test.yml +2 -0
  241. package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/no-reflect-get-js-test.yml +2 -1
  242. package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/no-reflect-get-test.yml +2 -1
  243. package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/no-return-value-in-generator-test.yml +12 -0
  244. package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/no-runtime-typeof-test.yml +33 -0
  245. package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/no-server-bind-wildcard-test.yml +9 -0
  246. package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/no-shape-in-symbol-names-test.yml +13 -0
  247. package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/no-sql-in-code-js-test.yml +5 -1
  248. package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/no-sql-in-code-test.yml +5 -1
  249. package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/no-unknown-parameters-test.yml +12 -0
  250. package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/no-unknown-returns-test.yml +16 -0
  251. package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/no-unsafe-dictionary-any-test.yml +10 -0
  252. package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/no-unsafe-dictionary-unknown-test.yml +8 -0
  253. package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/redundant-unsafe-function-test.yml +35 -0
  254. package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/require-safety-comment-for-as-unknown-as-test.yml +177 -0
  255. package/node_modules/pi-lens/rules/ast-grep-rules/rule-tests/ts-void-zero-test.yml +1 -0
  256. package/node_modules/pi-lens/rules/ast-grep-rules/rules/no-await-expression-member-js.yml +13 -2
  257. package/node_modules/pi-lens/rules/ast-grep-rules/rules/no-await-expression-member.yml +13 -2
  258. package/node_modules/pi-lens/rules/ast-grep-rules/rules/no-bare-host-path-in-win32-branch.yml +2 -0
  259. package/node_modules/pi-lens/rules/ast-grep-rules/rules/no-bare-object-param.yml +60 -0
  260. package/node_modules/pi-lens/rules/ast-grep-rules/rules/no-chained-type-assertions.yml +57 -12
  261. package/node_modules/pi-lens/rules/ast-grep-rules/rules/no-compile-call.yml +63 -5
  262. package/node_modules/pi-lens/rules/ast-grep-rules/rules/no-dupe-class-members.yml +52 -8
  263. package/node_modules/pi-lens/rules/ast-grep-rules/rules/no-inner-html-js.yml +27 -2
  264. package/node_modules/pi-lens/rules/ast-grep-rules/rules/no-inner-html.yml +27 -2
  265. package/node_modules/pi-lens/rules/ast-grep-rules/rules/no-known-value-widening.yml +71 -0
  266. package/node_modules/pi-lens/rules/ast-grep-rules/rules/no-non-null-assertion.yml +316 -0
  267. package/node_modules/pi-lens/rules/ast-grep-rules/rules/no-raw-json-store-write.yml +7 -0
  268. package/node_modules/pi-lens/rules/ast-grep-rules/rules/no-reflect-apply-js.yml +22 -2
  269. package/node_modules/pi-lens/rules/ast-grep-rules/rules/no-reflect-apply.yml +23 -2
  270. package/node_modules/pi-lens/rules/ast-grep-rules/rules/no-reflect-get-js.yml +33 -5
  271. package/node_modules/pi-lens/rules/ast-grep-rules/rules/no-reflect-get.yml +34 -8
  272. package/node_modules/pi-lens/rules/ast-grep-rules/rules/no-return-value-in-generator.yml +22 -5
  273. package/node_modules/pi-lens/rules/ast-grep-rules/rules/no-runtime-typeof.yml +121 -0
  274. package/node_modules/pi-lens/rules/ast-grep-rules/rules/no-server-bind-wildcard.yml +23 -7
  275. package/node_modules/pi-lens/rules/ast-grep-rules/rules/no-shape-in-symbol-names.yml +68 -0
  276. package/node_modules/pi-lens/rules/ast-grep-rules/rules/no-sql-in-code-js.yml +41 -2
  277. package/node_modules/pi-lens/rules/ast-grep-rules/rules/no-sql-in-code.yml +41 -2
  278. package/node_modules/pi-lens/rules/ast-grep-rules/rules/no-unknown-laundering.yml +6 -1
  279. package/node_modules/pi-lens/rules/ast-grep-rules/rules/no-unknown-parameters.yml +67 -0
  280. package/node_modules/pi-lens/rules/ast-grep-rules/rules/no-unknown-returns.yml +106 -0
  281. package/node_modules/pi-lens/rules/ast-grep-rules/rules/no-unsafe-dictionary-any.yml +50 -0
  282. package/node_modules/pi-lens/rules/ast-grep-rules/rules/no-unsafe-dictionary-unknown.yml +56 -0
  283. package/node_modules/pi-lens/rules/ast-grep-rules/rules/no-win32-isabsolute-for-qualification.yml +2 -0
  284. package/node_modules/pi-lens/rules/ast-grep-rules/rules/redundant-unsafe-function.yml +32 -0
  285. package/node_modules/pi-lens/rules/ast-grep-rules/rules/require-safety-comment-for-as-unknown-as.yml +184 -0
  286. package/node_modules/pi-lens/rules/ast-grep-rules/rules/ts-void-zero.yml +5 -0
  287. package/node_modules/pi-lens/rules/ast-grep-rules/self-scan-baseline.json +5 -0
  288. package/node_modules/pi-lens/scripts/analyze-pi-lens-logs.mjs +53 -1
  289. package/node_modules/pi-lens/scripts/download-grammars.js +25 -0
  290. package/node_modules/pi-lens/scripts/grammars.lock.json +9 -0
  291. package/node_modules/pi-lens/skills/pi-lens-ast-grep/SKILL.md +2 -0
  292. package/node_modules/pi-lens/skills/pi-lens-write-ast-grep-rule/SKILL.md +80 -3
  293. package/node_modules/pi-lens/skills/pi-lens-write-ast-grep-rule/reference.md +41 -0
  294. package/node_modules/pi-lens/vendor/grammars/tree-sitter-cue.wasm +0 -0
  295. package/node_modules/pi-mcp-adapter/CHANGELOG.md +36 -0
  296. package/node_modules/pi-mcp-adapter/README.md +47 -5
  297. package/node_modules/pi-mcp-adapter/cli.js +163 -1
  298. package/node_modules/pi-mcp-adapter/commands.ts +128 -22
  299. package/node_modules/pi-mcp-adapter/config.ts +25 -7
  300. package/node_modules/pi-mcp-adapter/direct-tools.ts +5 -4
  301. package/node_modules/pi-mcp-adapter/index.ts +219 -32
  302. package/node_modules/pi-mcp-adapter/init.ts +36 -4
  303. package/node_modules/pi-mcp-adapter/lifecycle.ts +315 -24
  304. package/node_modules/pi-mcp-adapter/mcp-auth-flow.ts +39 -6
  305. package/node_modules/pi-mcp-adapter/mcp-bearer-store.ts +387 -0
  306. package/node_modules/pi-mcp-adapter/mcp-callback-server.ts +27 -3
  307. package/node_modules/pi-mcp-adapter/mcp-code.ts +4 -0
  308. package/node_modules/pi-mcp-adapter/mcp-panel.ts +42 -13
  309. package/node_modules/pi-mcp-adapter/metadata-cache.ts +32 -21
  310. package/node_modules/pi-mcp-adapter/package-mcp-loader.ts +168 -0
  311. package/node_modules/pi-mcp-adapter/package.json +3 -1
  312. package/node_modules/pi-mcp-adapter/proxy-modes.ts +5 -4
  313. package/node_modules/pi-mcp-adapter/request-headers-command.ts +31 -37
  314. package/node_modules/pi-mcp-adapter/search-ranking.ts +92 -22
  315. package/node_modules/pi-mcp-adapter/server-manager.ts +140 -2
  316. package/node_modules/pi-mcp-adapter/session-recovery.ts +7 -0
  317. package/node_modules/pi-mcp-adapter/tool-approval.ts +15 -2
  318. package/node_modules/pi-mcp-adapter/tool-result-renderer.ts +44 -4
  319. package/node_modules/pi-mcp-adapter/types.ts +2 -0
  320. package/node_modules/pi-mcp-adapter/ui-server.ts +18 -16
  321. package/node_modules/pi-mcp-adapter/utils.ts +70 -0
  322. package/node_modules/pi-web-access/CHANGELOG.md +23 -0
  323. package/node_modules/pi-web-access/README.md +27 -9
  324. package/node_modules/pi-web-access/anysearch.ts +4 -2
  325. package/node_modules/pi-web-access/brave.ts +16 -4
  326. package/node_modules/pi-web-access/curator-page.ts +6 -3
  327. package/node_modules/pi-web-access/curator-server.ts +4 -1
  328. package/node_modules/pi-web-access/exa.ts +18 -7
  329. package/node_modules/pi-web-access/extract.ts +28 -3
  330. package/node_modules/pi-web-access/gemini-search.ts +16 -4
  331. package/node_modules/pi-web-access/index.ts +41 -57
  332. package/node_modules/pi-web-access/package.json +1 -1
  333. package/node_modules/pi-web-access/page-query.ts +4 -2
  334. package/node_modules/pi-web-access/parallel-mcp.ts +249 -0
  335. package/node_modules/pi-web-access/parallel.ts +2 -2
  336. package/node_modules/pi-web-access/query-rewrite.ts +51 -0
  337. package/node_modules/pi-web-access/serper.ts +211 -0
  338. package/node_modules/pi-web-access/summary-model-scope.ts +12 -4
  339. package/node_modules/pi-web-access/summary-review.ts +44 -22
  340. package/node_modules/pi-web-access/tavily.ts +16 -4
  341. package/node_modules/pi-web-access/utils.ts +87 -0
  342. package/node_modules/pi-web-access/valyu.ts +199 -0
  343. 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 { isCommandAvailableAsync } from "../safe-spawn.js";
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
- * Memoized per process — discovery is filesystem-only but stable for a session.
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
- if (await isCommandAvailableAsync("java")) {
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 (!home) {
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
- const binDir = path.join(home, "bin");
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
- export const LANGUAGE_EXTENSIONS = {
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] ?? LANGUAGE_EXTENSIONS[base.toLowerCase()];
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