@duckmind/dm-linux-x64 0.66.0 → 0.66.2

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 (546) hide show
  1. package/dm +2 -2
  2. package/extensions/.dm-extensions.json +12 -546
  3. package/extensions/dm-lens/clients/dispatch/runners/utils/runner-helpers.js +1 -1
  4. package/extensions/dm-mcp-adapter/mcp-keyring-helper.cjs +1 -1
  5. package/extensions/dm-ponytail/hooks/ponytail-activate.js +1 -1
  6. package/extensions/dm-ponytail/hooks/ponytail-instructions.js +1 -1
  7. package/extensions/dm-subagents/src/runs/background/runner-aliases.js +2 -2
  8. package/extensions/dm-subagents/src/runs/foreground/prompt-audit.js +4 -1
  9. package/extensions/dm-subagents/src/runs/shared/child-session.js +8 -6
  10. package/extensions/dm-subagents/src/watchdog/permission-arbiter.js +9 -1
  11. package/extensions/dm-subagents/src/watchdog/review.js +4 -1
  12. package/package.json +1 -1
  13. package/extensions/dm-lens/dist/clients/actionable-warnings-logger.js +0 -24
  14. package/extensions/dm-lens/dist/clients/actionable-warnings.js +0 -1014
  15. package/extensions/dm-lens/dist/clients/advisory-provenance.js +0 -385
  16. package/extensions/dm-lens/dist/clients/agent-behavior-client.js +0 -94
  17. package/extensions/dm-lens/dist/clients/agent-nudge.js +0 -151
  18. package/extensions/dm-lens/dist/clients/analysed-root.js +0 -1
  19. package/extensions/dm-lens/dist/clients/ast-grep-client.js +0 -576
  20. package/extensions/dm-lens/dist/clients/ast-grep-rule-manager.js +0 -114
  21. package/extensions/dm-lens/dist/clients/ast-grep-tool-logger.js +0 -85
  22. package/extensions/dm-lens/dist/clients/ast-grep-types.js +0 -1
  23. package/extensions/dm-lens/dist/clients/ast-grep-yaml-synth.js +0 -109
  24. package/extensions/dm-lens/dist/clients/atomic-write-staging.js +0 -66
  25. package/extensions/dm-lens/dist/clients/atomic-write.js +0 -37
  26. package/extensions/dm-lens/dist/clients/availability-probe-flight.js +0 -11
  27. package/extensions/dm-lens/dist/clients/bash-file-access.js +0 -830
  28. package/extensions/dm-lens/dist/clients/biome-client.js +0 -221
  29. package/extensions/dm-lens/dist/clients/blocker-freshness.js +0 -385
  30. package/extensions/dm-lens/dist/clients/blocker-past-eof.js +0 -49
  31. package/extensions/dm-lens/dist/clients/bootstrap.js +0 -246
  32. package/extensions/dm-lens/dist/clients/bounded-cache.js +0 -105
  33. package/extensions/dm-lens/dist/clients/bounded-pid-file-lock.js +0 -173
  34. package/extensions/dm-lens/dist/clients/bounded-telemetry.js +0 -104
  35. package/extensions/dm-lens/dist/clients/build-identity.js +0 -45
  36. package/extensions/dm-lens/dist/clients/bundled-resource-health.js +0 -41
  37. package/extensions/dm-lens/dist/clients/bus-events-logger.js +0 -48
  38. package/extensions/dm-lens/dist/clients/bus-publish.js +0 -117
  39. package/extensions/dm-lens/dist/clients/cache/rule-cache.js +0 -103
  40. package/extensions/dm-lens/dist/clients/cache-manager.js +0 -340
  41. package/extensions/dm-lens/dist/clients/cache-observability.js +0 -847
  42. package/extensions/dm-lens/dist/clients/call-graph.js +0 -628
  43. package/extensions/dm-lens/dist/clients/cargo-manifest.js +0 -151
  44. package/extensions/dm-lens/dist/clients/cascade-budget.js +0 -52
  45. package/extensions/dm-lens/dist/clients/cascade-format.js +0 -160
  46. package/extensions/dm-lens/dist/clients/cascade-logger.js +0 -22
  47. package/extensions/dm-lens/dist/clients/cascade-types.js +0 -1
  48. package/extensions/dm-lens/dist/clients/child-unref.js +0 -59
  49. package/extensions/dm-lens/dist/clients/code-quality-warnings.js +0 -192
  50. package/extensions/dm-lens/dist/clients/codebase-model.js +0 -110
  51. package/extensions/dm-lens/dist/clients/collateral-test-role.js +0 -8
  52. package/extensions/dm-lens/dist/clients/complexity-client.js +0 -398
  53. package/extensions/dm-lens/dist/clients/config-core/deny.js +0 -117
  54. package/extensions/dm-lens/dist/clients/config-core/index.js +0 -2
  55. package/extensions/dm-lens/dist/clients/config-core/merge.js +0 -228
  56. package/extensions/dm-lens/dist/clients/config-core/normalize.js +0 -217
  57. package/extensions/dm-lens/dist/clients/config-core/process-spec.js +0 -147
  58. package/extensions/dm-lens/dist/clients/config-core/provenance.js +0 -54
  59. package/extensions/dm-lens/dist/clients/config-core/records.js +0 -79
  60. package/extensions/dm-lens/dist/clients/config-core/resolve.js +0 -48
  61. package/extensions/dm-lens/dist/clients/config-core/safe-object.js +0 -22
  62. package/extensions/dm-lens/dist/clients/config-core/schema.js +0 -90
  63. package/extensions/dm-lens/dist/clients/config-diagnostic-codes.js +0 -90
  64. package/extensions/dm-lens/dist/clients/config-locations.js +0 -175
  65. package/extensions/dm-lens/dist/clients/config-resolve.js +0 -359
  66. package/extensions/dm-lens/dist/clients/config-schema.js +0 -128
  67. package/extensions/dm-lens/dist/clients/config-warn.js +0 -146
  68. package/extensions/dm-lens/dist/clients/console-guard-install.js +0 -4
  69. package/extensions/dm-lens/dist/clients/cooperative-budget.js +0 -36
  70. package/extensions/dm-lens/dist/clients/dead-code-client.js +0 -342
  71. package/extensions/dm-lens/dist/clients/dead-code-logger.js +0 -18
  72. package/extensions/dm-lens/dist/clients/deadline-utils.js +0 -117
  73. package/extensions/dm-lens/dist/clients/debug-handles.js +0 -121
  74. package/extensions/dm-lens/dist/clients/debug-heap.js +0 -80
  75. package/extensions/dm-lens/dist/clients/deferred-lsp-work.js +0 -33
  76. package/extensions/dm-lens/dist/clients/degradation-ledger.js +0 -272
  77. package/extensions/dm-lens/dist/clients/demoted-finding-render.js +0 -61
  78. package/extensions/dm-lens/dist/clients/dependency-checker.js +0 -525
  79. package/extensions/dm-lens/dist/clients/deps/ast-grep-napi.js +0 -17
  80. package/extensions/dm-lens/dist/clients/deps/dm-host-deps.js +0 -10
  81. package/extensions/dm-lens/dist/clients/deps/dm-tui-compat.js +0 -58
  82. package/extensions/dm-lens/dist/clients/deps/js-yaml.js +0 -7
  83. package/extensions/dm-lens/dist/clients/deps/minimatch.js +0 -6
  84. package/extensions/dm-lens/dist/clients/deps/pidusage.js +0 -5
  85. package/extensions/dm-lens/dist/clients/deps/typebox.js +0 -5
  86. package/extensions/dm-lens/dist/clients/deps/vscode-jsonrpc.js +0 -8
  87. package/extensions/dm-lens/dist/clients/deps/web-tree-sitter.js +0 -11
  88. package/extensions/dm-lens/dist/clients/diagnostic-dispositions.js +0 -318
  89. package/extensions/dm-lens/dist/clients/diagnostic-line-freshness.js +0 -144
  90. package/extensions/dm-lens/dist/clients/diagnostic-logger.js +0 -60
  91. package/extensions/dm-lens/dist/clients/diagnostic-tracker.js +0 -89
  92. package/extensions/dm-lens/dist/clients/diagnostics-publish.js +0 -134
  93. package/extensions/dm-lens/dist/clients/dispatch/ast-grep-catalog.js +0 -16
  94. package/extensions/dm-lens/dist/clients/dispatch/auxiliary-lsp.js +0 -158
  95. package/extensions/dm-lens/dist/clients/dispatch/collect-later-tier.js +0 -25
  96. package/extensions/dm-lens/dist/clients/dispatch/diagnostic-taxonomy.js +0 -58
  97. package/extensions/dm-lens/dist/clients/dispatch/dispatcher.js +0 -953
  98. package/extensions/dm-lens/dist/clients/dispatch/fact-provider-types.js +0 -1
  99. package/extensions/dm-lens/dist/clients/dispatch/fact-rule-runner.js +0 -17
  100. package/extensions/dm-lens/dist/clients/dispatch/fact-runner.js +0 -18
  101. package/extensions/dm-lens/dist/clients/dispatch/fact-scheduler.js +0 -52
  102. package/extensions/dm-lens/dist/clients/dispatch/fact-store.js +0 -199
  103. package/extensions/dm-lens/dist/clients/dispatch/facts/comment-facts.js +0 -20
  104. package/extensions/dm-lens/dist/clients/dispatch/facts/file-content.js +0 -18
  105. package/extensions/dm-lens/dist/clients/dispatch/facts/function-facts.js +0 -281
  106. package/extensions/dm-lens/dist/clients/dispatch/facts/import-facts.js +0 -169
  107. package/extensions/dm-lens/dist/clients/dispatch/facts/tree-sitter-facts.js +0 -19
  108. package/extensions/dm-lens/dist/clients/dispatch/facts/try-catch-facts.js +0 -95
  109. package/extensions/dm-lens/dist/clients/dispatch/finding-policy.js +0 -159
  110. package/extensions/dm-lens/dist/clients/dispatch/indent-detect.js +0 -227
  111. package/extensions/dm-lens/dist/clients/dispatch/inline-suppressions.js +0 -52
  112. package/extensions/dm-lens/dist/clients/dispatch/integration.js +0 -1463
  113. package/extensions/dm-lens/dist/clients/dispatch/lazy.js +0 -8
  114. package/extensions/dm-lens/dist/clients/dispatch/pending-runner-findings.js +0 -75
  115. package/extensions/dm-lens/dist/clients/dispatch/plan.js +0 -278
  116. package/extensions/dm-lens/dist/clients/dispatch/priorities.js +0 -14
  117. package/extensions/dm-lens/dist/clients/dispatch/rule-id-normalize.js +0 -42
  118. package/extensions/dm-lens/dist/clients/dispatch/rule-ignores.js +0 -21
  119. package/extensions/dm-lens/dist/clients/dispatch/rule-policy.js +0 -73
  120. package/extensions/dm-lens/dist/clients/dispatch/rules/async-noise.js +0 -31
  121. package/extensions/dm-lens/dist/clients/dispatch/rules/async-unnecessary-wrapper.js +0 -27
  122. package/extensions/dm-lens/dist/clients/dispatch/rules/cors-wildcard.js +0 -35
  123. package/extensions/dm-lens/dist/clients/dispatch/rules/error-obscuring.js +0 -29
  124. package/extensions/dm-lens/dist/clients/dispatch/rules/error-swallowing.js +0 -29
  125. package/extensions/dm-lens/dist/clients/dispatch/rules/framework-call-noise.js +0 -31
  126. package/extensions/dm-lens/dist/clients/dispatch/rules/high-complexity.js +0 -56
  127. package/extensions/dm-lens/dist/clients/dispatch/rules/high-fan-out.js +0 -45
  128. package/extensions/dm-lens/dist/clients/dispatch/rules/high-import-coupling.js +0 -31
  129. package/extensions/dm-lens/dist/clients/dispatch/rules/missing-error-propagation.js +0 -45
  130. package/extensions/dm-lens/dist/clients/dispatch/rules/no-commented-credentials.js +0 -46
  131. package/extensions/dm-lens/dist/clients/dispatch/rules/pass-through-wrappers.js +0 -38
  132. package/extensions/dm-lens/dist/clients/dispatch/rules/placeholder-comments.js +0 -40
  133. package/extensions/dm-lens/dist/clients/dispatch/rules/unsafe-boundary.js +0 -101
  134. package/extensions/dm-lens/dist/clients/dispatch/runner-context.js +0 -46
  135. package/extensions/dm-lens/dist/clients/dispatch/runners/actionlint.js +0 -98
  136. package/extensions/dm-lens/dist/clients/dispatch/runners/ast-grep-napi.js +0 -690
  137. package/extensions/dm-lens/dist/clients/dispatch/runners/biome-check.js +0 -202
  138. package/extensions/dm-lens/dist/clients/dispatch/runners/cpp-check.js +0 -190
  139. package/extensions/dm-lens/dist/clients/dispatch/runners/credo.js +0 -66
  140. package/extensions/dm-lens/dist/clients/dispatch/runners/cue-vet.js +0 -167
  141. package/extensions/dm-lens/dist/clients/dispatch/runners/dart-analyze.js +0 -151
  142. package/extensions/dm-lens/dist/clients/dispatch/runners/detekt.js +0 -157
  143. package/extensions/dm-lens/dist/clients/dispatch/runners/dotnet-build.js +0 -157
  144. package/extensions/dm-lens/dist/clients/dispatch/runners/elixir-check.js +0 -153
  145. package/extensions/dm-lens/dist/clients/dispatch/runners/eslint.js +0 -99
  146. package/extensions/dm-lens/dist/clients/dispatch/runners/fact-rules.js +0 -20
  147. package/extensions/dm-lens/dist/clients/dispatch/runners/fish-indent.js +0 -65
  148. package/extensions/dm-lens/dist/clients/dispatch/runners/gleam-check.js +0 -107
  149. package/extensions/dm-lens/dist/clients/dispatch/runners/go-vet.js +0 -51
  150. package/extensions/dm-lens/dist/clients/dispatch/runners/golangci-lint.js +0 -89
  151. package/extensions/dm-lens/dist/clients/dispatch/runners/hadolint.js +0 -83
  152. package/extensions/dm-lens/dist/clients/dispatch/runners/helm-lint.js +0 -144
  153. package/extensions/dm-lens/dist/clients/dispatch/runners/helm-render.js +0 -593
  154. package/extensions/dm-lens/dist/clients/dispatch/runners/htmlhint.js +0 -103
  155. package/extensions/dm-lens/dist/clients/dispatch/runners/index.js +0 -100
  156. package/extensions/dm-lens/dist/clients/dispatch/runners/javac.js +0 -82
  157. package/extensions/dm-lens/dist/clients/dispatch/runners/ktlint.js +0 -93
  158. package/extensions/dm-lens/dist/clients/dispatch/runners/lsp.js +0 -206
  159. package/extensions/dm-lens/dist/clients/dispatch/runners/markdownlint.js +0 -129
  160. package/extensions/dm-lens/dist/clients/dispatch/runners/mypy.js +0 -70
  161. package/extensions/dm-lens/dist/clients/dispatch/runners/oxlint.js +0 -305
  162. package/extensions/dm-lens/dist/clients/dispatch/runners/php-lint.js +0 -70
  163. package/extensions/dm-lens/dist/clients/dispatch/runners/phpstan.js +0 -90
  164. package/extensions/dm-lens/dist/clients/dispatch/runners/prisma-validate.js +0 -56
  165. package/extensions/dm-lens/dist/clients/dispatch/runners/psscriptanalyzer.js +0 -307
  166. package/extensions/dm-lens/dist/clients/dispatch/runners/pyright.js +0 -118
  167. package/extensions/dm-lens/dist/clients/dispatch/runners/rubocop.js +0 -79
  168. package/extensions/dm-lens/dist/clients/dispatch/runners/ruff.js +0 -69
  169. package/extensions/dm-lens/dist/clients/dispatch/runners/rust-clippy.js +0 -147
  170. package/extensions/dm-lens/dist/clients/dispatch/runners/shellcheck.js +0 -111
  171. package/extensions/dm-lens/dist/clients/dispatch/runners/shfmt.js +0 -81
  172. package/extensions/dm-lens/dist/clients/dispatch/runners/spellcheck.js +0 -74
  173. package/extensions/dm-lens/dist/clients/dispatch/runners/spotbugs.js +0 -208
  174. package/extensions/dm-lens/dist/clients/dispatch/runners/sqlfluff.js +0 -136
  175. package/extensions/dm-lens/dist/clients/dispatch/runners/stylelint.js +0 -118
  176. package/extensions/dm-lens/dist/clients/dispatch/runners/swiftlint.js +0 -143
  177. package/extensions/dm-lens/dist/clients/dispatch/runners/taplo.js +0 -97
  178. package/extensions/dm-lens/dist/clients/dispatch/runners/terragrunt.js +0 -110
  179. package/extensions/dm-lens/dist/clients/dispatch/runners/tflint.js +0 -104
  180. package/extensions/dm-lens/dist/clients/dispatch/runners/tree-sitter.js +0 -516
  181. package/extensions/dm-lens/dist/clients/dispatch/runners/trivy-config.js +0 -155
  182. package/extensions/dm-lens/dist/clients/dispatch/runners/utils/availability-policy.js +0 -285
  183. package/extensions/dm-lens/dist/clients/dispatch/runners/utils/candidate-probe.js +0 -61
  184. package/extensions/dm-lens/dist/clients/dispatch/runners/utils/diagnostic-parsers.js +0 -61
  185. package/extensions/dm-lens/dist/clients/dispatch/runners/utils/lazy-installer.js +0 -130
  186. package/extensions/dm-lens/dist/clients/dispatch/runners/utils/runner-helpers.js +0 -1067
  187. package/extensions/dm-lens/dist/clients/dispatch/runners/utils/spawn-outcome.js +0 -40
  188. package/extensions/dm-lens/dist/clients/dispatch/runners/utils/tool-failure.js +0 -117
  189. package/extensions/dm-lens/dist/clients/dispatch/runners/utils/toolchain-availability.js +0 -88
  190. package/extensions/dm-lens/dist/clients/dispatch/runners/utils.js +0 -8
  191. package/extensions/dm-lens/dist/clients/dispatch/runners/vale.js +0 -106
  192. package/extensions/dm-lens/dist/clients/dispatch/runners/yaml-rule-parser.js +0 -163
  193. package/extensions/dm-lens/dist/clients/dispatch/runners/yamllint.js +0 -83
  194. package/extensions/dm-lens/dist/clients/dispatch/runners/zig-check.js +0 -72
  195. package/extensions/dm-lens/dist/clients/dispatch/suppress-writer.js +0 -57
  196. package/extensions/dm-lens/dist/clients/dispatch/tool-profile.js +0 -30
  197. package/extensions/dm-lens/dist/clients/dispatch/types.js +0 -7
  198. package/extensions/dm-lens/dist/clients/dispatch/utils/format-utils.js +0 -45
  199. package/extensions/dm-lens/dist/clients/dispatch/utils/lsp-diagnostics.js +0 -31
  200. package/extensions/dm-lens/dist/clients/disposition-logger.js +0 -19
  201. package/extensions/dm-lens/dist/clients/disposition-publish.js +0 -88
  202. package/extensions/dm-lens/dist/clients/durable-store.js +0 -77
  203. package/extensions/dm-lens/dist/clients/effective-config.js +0 -160
  204. package/extensions/dm-lens/dist/clients/env-utils.js +0 -26
  205. package/extensions/dm-lens/dist/clients/error-class.js +0 -3
  206. package/extensions/dm-lens/dist/clients/eval-timestamp.js +0 -2
  207. package/extensions/dm-lens/dist/clients/event-loop-hold.js +0 -119
  208. package/extensions/dm-lens/dist/clients/event-loop-monitor.js +0 -84
  209. package/extensions/dm-lens/dist/clients/extension-log.js +0 -230
  210. package/extensions/dm-lens/dist/clients/extension-mode.js +0 -20
  211. package/extensions/dm-lens/dist/clients/feature-hints.js +0 -88
  212. package/extensions/dm-lens/dist/clients/file-kinds.js +0 -304
  213. package/extensions/dm-lens/dist/clients/file-role.js +0 -50
  214. package/extensions/dm-lens/dist/clients/file-time.js +0 -112
  215. package/extensions/dm-lens/dist/clients/file-utils.js +0 -630
  216. package/extensions/dm-lens/dist/clients/finding-delivery-gate.js +0 -129
  217. package/extensions/dm-lens/dist/clients/finding-identity.js +0 -23
  218. package/extensions/dm-lens/dist/clients/fix-worklog.js +0 -75
  219. package/extensions/dm-lens/dist/clients/format-events-publish.js +0 -230
  220. package/extensions/dm-lens/dist/clients/format-service.js +0 -154
  221. package/extensions/dm-lens/dist/clients/formatters-lazy.js +0 -8
  222. package/extensions/dm-lens/dist/clients/formatters.js +0 -1351
  223. package/extensions/dm-lens/dist/clients/freshness-cadence.js +0 -1
  224. package/extensions/dm-lens/dist/clients/freshness.js +0 -8
  225. package/extensions/dm-lens/dist/clients/generated-artifacts.js +0 -209
  226. package/extensions/dm-lens/dist/clients/generation-guard.js +0 -105
  227. package/extensions/dm-lens/dist/clients/git-guard.js +0 -770
  228. package/extensions/dm-lens/dist/clients/git-tracked-ignore.js +0 -120
  229. package/extensions/dm-lens/dist/clients/gitleaks-client.js +0 -282
  230. package/extensions/dm-lens/dist/clients/go-client.js +0 -47
  231. package/extensions/dm-lens/dist/clients/govulncheck-client.js +0 -411
  232. package/extensions/dm-lens/dist/clients/gradle-ktfmt-style.js +0 -177
  233. package/extensions/dm-lens/dist/clients/grammar-source.js +0 -224
  234. package/extensions/dm-lens/dist/clients/gzip-stage-write.js +0 -85
  235. package/extensions/dm-lens/dist/clients/hashline-anchor.js +0 -222
  236. package/extensions/dm-lens/dist/clients/hook-budgets.js +0 -16
  237. package/extensions/dm-lens/dist/clients/host-edit-normalize.js +0 -87
  238. package/extensions/dm-lens/dist/clients/host-ports.js +0 -35
  239. package/extensions/dm-lens/dist/clients/indent-retarget.js +0 -102
  240. package/extensions/dm-lens/dist/clients/inline-blocker-dispositions.js +0 -103
  241. package/extensions/dm-lens/dist/clients/install-diagnostics.js +0 -123
  242. package/extensions/dm-lens/dist/clients/installer/index.js +0 -3770
  243. package/extensions/dm-lens/dist/clients/installer/managed-tool-refresh-session.js +0 -17
  244. package/extensions/dm-lens/dist/clients/installer/managed-tool-refresh.js +0 -522
  245. package/extensions/dm-lens/dist/clients/instance-reaper-state.js +0 -3
  246. package/extensions/dm-lens/dist/clients/instance-reaper.js +0 -577
  247. package/extensions/dm-lens/dist/clients/instance-registry-lock.js +0 -131
  248. package/extensions/dm-lens/dist/clients/instance-registry.js +0 -452
  249. package/extensions/dm-lens/dist/clients/jscpd-client.js +0 -252
  250. package/extensions/dm-lens/dist/clients/json-cache-read.js +0 -25
  251. package/extensions/dm-lens/dist/clients/knip-client.js +0 -472
  252. package/extensions/dm-lens/dist/clients/language-policy.js +0 -242
  253. package/extensions/dm-lens/dist/clients/language-profile.js +0 -261
  254. package/extensions/dm-lens/dist/clients/language-registry.js +0 -424
  255. package/extensions/dm-lens/dist/clients/latency-logger.js +0 -192
  256. package/extensions/dm-lens/dist/clients/lazy-import.js +0 -14
  257. package/extensions/dm-lens/dist/clients/ledger-bounds.js +0 -21
  258. package/extensions/dm-lens/dist/clients/lens-config.js +0 -237
  259. package/extensions/dm-lens/dist/clients/lens-engine.js +0 -181
  260. package/extensions/dm-lens/dist/clients/lens-events.js +0 -105
  261. package/extensions/dm-lens/dist/clients/lens-flag-registry.js +0 -302
  262. package/extensions/dm-lens/dist/clients/lens-map.js +0 -980
  263. package/extensions/dm-lens/dist/clients/live-bus-emitter.js +0 -53
  264. package/extensions/dm-lens/dist/clients/log-cleanup.js +0 -138
  265. package/extensions/dm-lens/dist/clients/lsp/aggregation.js +0 -88
  266. package/extensions/dm-lens/dist/clients/lsp/cascade-tier.js +0 -203
  267. package/extensions/dm-lens/dist/clients/lsp/client.js +0 -2709
  268. package/extensions/dm-lens/dist/clients/lsp/config.js +0 -252
  269. package/extensions/dm-lens/dist/clients/lsp/content-limits.js +0 -21
  270. package/extensions/dm-lens/dist/clients/lsp/diagnostic-binding.js +0 -79
  271. package/extensions/dm-lens/dist/clients/lsp/document-drift.js +0 -312
  272. package/extensions/dm-lens/dist/clients/lsp/edits.js +0 -930
  273. package/extensions/dm-lens/dist/clients/lsp/index.js +0 -4448
  274. package/extensions/dm-lens/dist/clients/lsp/inferred-project.js +0 -121
  275. package/extensions/dm-lens/dist/clients/lsp/jvm-runtime.js +0 -194
  276. package/extensions/dm-lens/dist/clients/lsp/language.js +0 -23
  277. package/extensions/dm-lens/dist/clients/lsp/launch.js +0 -468
  278. package/extensions/dm-lens/dist/clients/lsp/lombok.js +0 -146
  279. package/extensions/dm-lens/dist/clients/lsp/path-utils.js +0 -1
  280. package/extensions/dm-lens/dist/clients/lsp/pending-aux-coverage.js +0 -90
  281. package/extensions/dm-lens/dist/clients/lsp/position-encoding.js +0 -28
  282. package/extensions/dm-lens/dist/clients/lsp/ruby-drive-dirs.js +0 -42
  283. package/extensions/dm-lens/dist/clients/lsp/server.js +0 -2422
  284. package/extensions/dm-lens/dist/clients/lsp/session-roots.js +0 -52
  285. package/extensions/dm-lens/dist/clients/lsp/spawn-history.js +0 -15
  286. package/extensions/dm-lens/dist/clients/lsp/sync-kind.js +0 -30
  287. package/extensions/dm-lens/dist/clients/lsp/tsserver-sync.js +0 -156
  288. package/extensions/dm-lens/dist/clients/lsp/wait-policy/capability-snapshot.js +0 -1
  289. package/extensions/dm-lens/dist/clients/lsp/wait-policy/classification.js +0 -36
  290. package/extensions/dm-lens/dist/clients/lsp/wait-policy/index.js +0 -3
  291. package/extensions/dm-lens/dist/clients/lsp/wait-policy/strategies.js +0 -175
  292. package/extensions/dm-lens/dist/clients/lsp/watch-queue.js +0 -40
  293. package/extensions/dm-lens/dist/clients/lsp/workspace-diagnostics-cache.js +0 -267
  294. package/extensions/dm-lens/dist/clients/lsp/workspace-diagnostics-session.js +0 -7
  295. package/extensions/dm-lens/dist/clients/lsp/workspace-sweep-hold.js +0 -93
  296. package/extensions/dm-lens/dist/clients/lsp-budget.js +0 -83
  297. package/extensions/dm-lens/dist/clients/lsp-document-symbols.js +0 -93
  298. package/extensions/dm-lens/dist/clients/lsp-lazy.js +0 -8
  299. package/extensions/dm-lens/dist/clients/lsp-mutation.js +0 -273
  300. package/extensions/dm-lens/dist/clients/lsp-status.js +0 -37
  301. package/extensions/dm-lens/dist/clients/map-with-concurrency.js +0 -20
  302. package/extensions/dm-lens/dist/clients/mcp/analyze.js +0 -251
  303. package/extensions/dm-lens/dist/clients/mcp/host-shim.js +0 -14
  304. package/extensions/dm-lens/dist/clients/mcp/ipc.js +0 -302
  305. package/extensions/dm-lens/dist/clients/mcp/review.js +0 -137
  306. package/extensions/dm-lens/dist/clients/mcp/session.js +0 -305
  307. package/extensions/dm-lens/dist/clients/memory-sampler.js +0 -107
  308. package/extensions/dm-lens/dist/clients/message-end-attribution.js +0 -18
  309. package/extensions/dm-lens/dist/clients/metrics-client.js +0 -80
  310. package/extensions/dm-lens/dist/clients/metrics-history.js +0 -255
  311. package/extensions/dm-lens/dist/clients/middle-man-analysis.js +0 -161
  312. package/extensions/dm-lens/dist/clients/model-provider.js +0 -31
  313. package/extensions/dm-lens/dist/clients/module-report-lsp.js +0 -140
  314. package/extensions/dm-lens/dist/clients/module-report.js +0 -1642
  315. package/extensions/dm-lens/dist/clients/mutating-tool.js +0 -377
  316. package/extensions/dm-lens/dist/clients/mutation-attribution.js +0 -168
  317. package/extensions/dm-lens/dist/clients/mutation-bridge.js +0 -102
  318. package/extensions/dm-lens/dist/clients/ndjson-logger.js +0 -471
  319. package/extensions/dm-lens/dist/clients/observed-mutation-sources.js +0 -43
  320. package/extensions/dm-lens/dist/clients/observed-mutation.js +0 -709
  321. package/extensions/dm-lens/dist/clients/oldtext-autopatch.js +0 -100
  322. package/extensions/dm-lens/dist/clients/opaque-mutation-scan.js +0 -313
  323. package/extensions/dm-lens/dist/clients/opengrep-client.js +0 -216
  324. package/extensions/dm-lens/dist/clients/opengrep-config.js +0 -52
  325. package/extensions/dm-lens/dist/clients/package-manager.js +0 -303
  326. package/extensions/dm-lens/dist/clients/package-root.js +0 -25
  327. package/extensions/dm-lens/dist/clients/partial-edit-apply.js +0 -337
  328. package/extensions/dm-lens/dist/clients/path-attribution-telemetry.js +0 -31
  329. package/extensions/dm-lens/dist/clients/path-keyed-map.js +0 -57
  330. package/extensions/dm-lens/dist/clients/path-utils.js +0 -476
  331. package/extensions/dm-lens/dist/clients/performance-report.js +0 -291
  332. package/extensions/dm-lens/dist/clients/persist-debounce.js +0 -37
  333. package/extensions/dm-lens/dist/clients/persistent-reverify.js +0 -165
  334. package/extensions/dm-lens/dist/clients/php-cs-fixer-config.js +0 -15
  335. package/extensions/dm-lens/dist/clients/pipeline.js +0 -1091
  336. package/extensions/dm-lens/dist/clients/post-autofix-notice.js +0 -19
  337. package/extensions/dm-lens/dist/clients/print-mode.js +0 -3
  338. package/extensions/dm-lens/dist/clients/probe-home-state.js +0 -62
  339. package/extensions/dm-lens/dist/clients/process-bridge.js +0 -20
  340. package/extensions/dm-lens/dist/clients/process-singletons.js +0 -69
  341. package/extensions/dm-lens/dist/clients/process-snapshot.js +0 -22
  342. package/extensions/dm-lens/dist/clients/project-changes.js +0 -112
  343. package/extensions/dm-lens/dist/clients/project-conventions.js +0 -152
  344. package/extensions/dm-lens/dist/clients/project-diagnostics/cache.js +0 -91
  345. package/extensions/dm-lens/dist/clients/project-diagnostics/extractors.js +0 -53
  346. package/extensions/dm-lens/dist/clients/project-diagnostics/fresh-fetch.js +0 -408
  347. package/extensions/dm-lens/dist/clients/project-diagnostics/runner-adapters/call-graph-impact.js +0 -64
  348. package/extensions/dm-lens/dist/clients/project-diagnostics/runner-adapters/dead-code.js +0 -38
  349. package/extensions/dm-lens/dist/clients/project-diagnostics/runner-adapters/gitleaks.js +0 -21
  350. package/extensions/dm-lens/dist/clients/project-diagnostics/runner-adapters/govulncheck.js +0 -23
  351. package/extensions/dm-lens/dist/clients/project-diagnostics/runner-adapters/jscpd.js +0 -28
  352. package/extensions/dm-lens/dist/clients/project-diagnostics/runner-adapters/knip.js +0 -45
  353. package/extensions/dm-lens/dist/clients/project-diagnostics/runner-adapters/madge.js +0 -34
  354. package/extensions/dm-lens/dist/clients/project-diagnostics/runner-adapters/opengrep.js +0 -32
  355. package/extensions/dm-lens/dist/clients/project-diagnostics/runner-adapters/runner-findings.js +0 -79
  356. package/extensions/dm-lens/dist/clients/project-diagnostics/runner-adapters/trivy.js +0 -41
  357. package/extensions/dm-lens/dist/clients/project-diagnostics/scanner.js +0 -349
  358. package/extensions/dm-lens/dist/clients/project-diagnostics/types.js +0 -1
  359. package/extensions/dm-lens/dist/clients/project-lens-config.js +0 -437
  360. package/extensions/dm-lens/dist/clients/project-report.js +0 -527
  361. package/extensions/dm-lens/dist/clients/project-scale.js +0 -60
  362. package/extensions/dm-lens/dist/clients/project-scan-policy.js +0 -4
  363. package/extensions/dm-lens/dist/clients/project-snapshot-fingerprint.js +0 -39
  364. package/extensions/dm-lens/dist/clients/project-snapshot-persist-worker.js +0 -14
  365. package/extensions/dm-lens/dist/clients/project-snapshot.js +0 -1178
  366. package/extensions/dm-lens/dist/clients/project-trust.js +0 -104
  367. package/extensions/dm-lens/dist/clients/python-environment.js +0 -120
  368. package/extensions/dm-lens/dist/clients/python-provenance.js +0 -551
  369. package/extensions/dm-lens/dist/clients/quiet-window-config.js +0 -16
  370. package/extensions/dm-lens/dist/clients/quiet-window.js +0 -126
  371. package/extensions/dm-lens/dist/clients/read-bridge.js +0 -46
  372. package/extensions/dm-lens/dist/clients/read-expansion.js +0 -218
  373. package/extensions/dm-lens/dist/clients/read-guard-logger.js +0 -178
  374. package/extensions/dm-lens/dist/clients/read-guard-tool-lines.js +0 -1042
  375. package/extensions/dm-lens/dist/clients/read-guard.js +0 -1096
  376. package/extensions/dm-lens/dist/clients/recent-touches.js +0 -126
  377. package/extensions/dm-lens/dist/clients/redact/secrets.js +0 -386
  378. package/extensions/dm-lens/dist/clients/resource-sampler.js +0 -344
  379. package/extensions/dm-lens/dist/clients/reverse-deps.js +0 -227
  380. package/extensions/dm-lens/dist/clients/review-graph/builder.js +0 -3635
  381. package/extensions/dm-lens/dist/clients/review-graph/format.js +0 -30
  382. package/extensions/dm-lens/dist/clients/review-graph/git-identity.js +0 -115
  383. package/extensions/dm-lens/dist/clients/review-graph/import-resolvers.js +0 -325
  384. package/extensions/dm-lens/dist/clients/review-graph/persist-worker.js +0 -8
  385. package/extensions/dm-lens/dist/clients/review-graph/query.js +0 -195
  386. package/extensions/dm-lens/dist/clients/review-graph/revision-drift.js +0 -3
  387. package/extensions/dm-lens/dist/clients/review-graph/service.js +0 -60
  388. package/extensions/dm-lens/dist/clients/review-graph/shared-extraction-ir.js +0 -54
  389. package/extensions/dm-lens/dist/clients/review-graph/symbol-id.js +0 -29
  390. package/extensions/dm-lens/dist/clients/review-graph/tsconfig-paths.js +0 -253
  391. package/extensions/dm-lens/dist/clients/review-graph/types.js +0 -1
  392. package/extensions/dm-lens/dist/clients/review-graph/workspace-modules.js +0 -374
  393. package/extensions/dm-lens/dist/clients/review-graph-logger.js +0 -51
  394. package/extensions/dm-lens/dist/clients/ruff-client.js +0 -109
  395. package/extensions/dm-lens/dist/clients/rules-scanner.js +0 -113
  396. package/extensions/dm-lens/dist/clients/run-duration.js +0 -9
  397. package/extensions/dm-lens/dist/clients/runtime-agent-end.js +0 -608
  398. package/extensions/dm-lens/dist/clients/runtime-config.js +0 -39
  399. package/extensions/dm-lens/dist/clients/runtime-context.js +0 -155
  400. package/extensions/dm-lens/dist/clients/runtime-coordinator.js +0 -817
  401. package/extensions/dm-lens/dist/clients/runtime-session.js +0 -1625
  402. package/extensions/dm-lens/dist/clients/runtime-tool-call.js +0 -868
  403. package/extensions/dm-lens/dist/clients/runtime-tool-result.js +0 -1317
  404. package/extensions/dm-lens/dist/clients/runtime-turn.js +0 -2333
  405. package/extensions/dm-lens/dist/clients/rust-client.js +0 -48
  406. package/extensions/dm-lens/dist/clients/safe-spawn.js +0 -1267
  407. package/extensions/dm-lens/dist/clients/sanitize.js +0 -174
  408. package/extensions/dm-lens/dist/clients/scan-utils.js +0 -7
  409. package/extensions/dm-lens/dist/clients/scratch-tree-policy.js +0 -57
  410. package/extensions/dm-lens/dist/clients/search-read-registration.js +0 -59
  411. package/extensions/dm-lens/dist/clients/secret-findings.js +0 -69
  412. package/extensions/dm-lens/dist/clients/security-scan-client.js +0 -208
  413. package/extensions/dm-lens/dist/clients/session-event-guard.js +0 -111
  414. package/extensions/dm-lens/dist/clients/session-lifecycle.js +0 -173
  415. package/extensions/dm-lens/dist/clients/session-start-observability.js +0 -47
  416. package/extensions/dm-lens/dist/clients/session-state-store.js +0 -63
  417. package/extensions/dm-lens/dist/clients/session-summary.js +0 -8
  418. package/extensions/dm-lens/dist/clients/sessionstart-logger.js +0 -22
  419. package/extensions/dm-lens/dist/clients/sg-runner.js +0 -627
  420. package/extensions/dm-lens/dist/clients/sgconfig.js +0 -280
  421. package/extensions/dm-lens/dist/clients/shared-checkout-guard.js +0 -177
  422. package/extensions/dm-lens/dist/clients/single-flight.js +0 -52
  423. package/extensions/dm-lens/dist/clients/situational-tool-telemetry.js +0 -85
  424. package/extensions/dm-lens/dist/clients/skills-resolver.js +0 -38
  425. package/extensions/dm-lens/dist/clients/slow-fs.js +0 -77
  426. package/extensions/dm-lens/dist/clients/smells-rollup.js +0 -118
  427. package/extensions/dm-lens/dist/clients/source-filter.js +0 -320
  428. package/extensions/dm-lens/dist/clients/source-walker.js +0 -96
  429. package/extensions/dm-lens/dist/clients/spawn-output-cap.js +0 -35
  430. package/extensions/dm-lens/dist/clients/spawn-timeout-cooldown.js +0 -51
  431. package/extensions/dm-lens/dist/clients/stale-marker.js +0 -1
  432. package/extensions/dm-lens/dist/clients/startup-scan.js +0 -222
  433. package/extensions/dm-lens/dist/clients/startup-timing.js +0 -67
  434. package/extensions/dm-lens/dist/clients/string-utils.js +0 -6
  435. package/extensions/dm-lens/dist/clients/subagent-mode.js +0 -40
  436. package/extensions/dm-lens/dist/clients/symbol-containment.js +0 -16
  437. package/extensions/dm-lens/dist/clients/symbol-types.js +0 -1
  438. package/extensions/dm-lens/dist/clients/test-runner-client.js +0 -1504
  439. package/extensions/dm-lens/dist/clients/test-runner-delivery.js +0 -260
  440. package/extensions/dm-lens/dist/clients/todo-scanner.js +0 -164
  441. package/extensions/dm-lens/dist/clients/tool-agreement.js +0 -377
  442. package/extensions/dm-lens/dist/clients/tool-config.js +0 -218
  443. package/extensions/dm-lens/dist/clients/tool-cwd.js +0 -235
  444. package/extensions/dm-lens/dist/clients/tool-definition.js +0 -22
  445. package/extensions/dm-lens/dist/clients/tool-event.js +0 -18
  446. package/extensions/dm-lens/dist/clients/tool-policy.js +0 -2393
  447. package/extensions/dm-lens/dist/clients/tool-probe.js +0 -5
  448. package/extensions/dm-lens/dist/clients/tool-render.js +0 -79
  449. package/extensions/dm-lens/dist/clients/tool-set-policy.js +0 -70
  450. package/extensions/dm-lens/dist/clients/tree-sitter-cache.js +0 -206
  451. package/extensions/dm-lens/dist/clients/tree-sitter-client.js +0 -2787
  452. package/extensions/dm-lens/dist/clients/tree-sitter-logger.js +0 -77
  453. package/extensions/dm-lens/dist/clients/tree-sitter-navigator.js +0 -198
  454. package/extensions/dm-lens/dist/clients/tree-sitter-query-loader.js +0 -318
  455. package/extensions/dm-lens/dist/clients/tree-sitter-shared.js +0 -87
  456. package/extensions/dm-lens/dist/clients/tree-sitter-symbol-extractor.js +0 -957
  457. package/extensions/dm-lens/dist/clients/trivy-client.js +0 -305
  458. package/extensions/dm-lens/dist/clients/tui-fit.js +0 -26
  459. package/extensions/dm-lens/dist/clients/turn-context.js +0 -48
  460. package/extensions/dm-lens/dist/clients/turn-end/lane.js +0 -1
  461. package/extensions/dm-lens/dist/clients/turn-end/lanes/govulncheck.js +0 -54
  462. package/extensions/dm-lens/dist/clients/turn-end/lanes/secrets.js +0 -131
  463. package/extensions/dm-lens/dist/clients/turn-summary-render.js +0 -56
  464. package/extensions/dm-lens/dist/clients/turn-summary.js +0 -84
  465. package/extensions/dm-lens/dist/clients/typos-config.js +0 -9
  466. package/extensions/dm-lens/dist/clients/user-notify.js +0 -15
  467. package/extensions/dm-lens/dist/clients/vanished-instance-marker.js +0 -18
  468. package/extensions/dm-lens/dist/clients/warm-attach.js +0 -210
  469. package/extensions/dm-lens/dist/clients/widget-state.js +0 -963
  470. package/extensions/dm-lens/dist/clients/word-index-logger.js +0 -21
  471. package/extensions/dm-lens/dist/clients/word-index-store.js +0 -222
  472. package/extensions/dm-lens/dist/clients/word-index.js +0 -1426
  473. package/extensions/dm-lens/dist/clients/workspace-topology.js +0 -261
  474. package/extensions/dm-lens/dist/clients/write-ordering-guard.js +0 -24
  475. package/extensions/dm-lens/dist/clients/zizmor-config.js +0 -160
  476. package/extensions/dm-lens/dist/i18n.js +0 -67
  477. package/extensions/dm-lens/dist/index.js +0 -1782
  478. package/extensions/dm-lens/dist/mcp/analyze-cli.js +0 -178
  479. package/extensions/dm-lens/dist/mcp/build-staleness.js +0 -55
  480. package/extensions/dm-lens/dist/mcp/cli.js +0 -78
  481. package/extensions/dm-lens/dist/mcp/server.js +0 -1208
  482. package/extensions/dm-lens/dist/mcp/worker.js +0 -33
  483. package/extensions/dm-lens/dist/scripts/lib/process-scan.mjs +0 -256
  484. package/extensions/dm-lens/dist/scripts/lib/skills-predicate.mjs +0 -53
  485. package/extensions/dm-lens/dist/scripts/lib/web-tree-sitter-dir.mjs +0 -45
  486. package/extensions/dm-lens/dist/tools/activate-tools.js +0 -61
  487. package/extensions/dm-lens/dist/tools/ast-grep-outline.js +0 -127
  488. package/extensions/dm-lens/dist/tools/ast-grep-replace.js +0 -226
  489. package/extensions/dm-lens/dist/tools/ast-grep-search.js +0 -687
  490. package/extensions/dm-lens/dist/tools/effective-config.js +0 -59
  491. package/extensions/dm-lens/dist/tools/lens-diagnostic-mark.js +0 -240
  492. package/extensions/dm-lens/dist/tools/lens-diagnostics.js +0 -1484
  493. package/extensions/dm-lens/dist/tools/lsp-diagnostics.js +0 -1088
  494. package/extensions/dm-lens/dist/tools/lsp-navigation.js +0 -1194
  495. package/extensions/dm-lens/dist/tools/lsp-structured-output.js +0 -277
  496. package/extensions/dm-lens/dist/tools/module-report.js +0 -332
  497. package/extensions/dm-lens/dist/tools/project-report.js +0 -72
  498. package/extensions/dm-lens/dist/tools/render-compact.js +0 -272
  499. package/extensions/dm-lens/dist/tools/scan-progress.js +0 -31
  500. package/extensions/dm-lens/dist/tools/shared.js +0 -26
  501. package/extensions/dm-lens/dist/tools/symbol-search.js +0 -133
  502. package/extensions/dm-mcp-adapter/dist/abort.js +0 -35
  503. package/extensions/dm-mcp-adapter/dist/agent-dir.js +0 -45
  504. package/extensions/dm-mcp-adapter/dist/agent-plugin-loader.js +0 -392
  505. package/extensions/dm-mcp-adapter/dist/agent-plugin-provenance.js +0 -26
  506. package/extensions/dm-mcp-adapter/dist/bearer-command-resolver.js +0 -182
  507. package/extensions/dm-mcp-adapter/dist/claude-plugin-loader.js +0 -350
  508. package/extensions/dm-mcp-adapter/dist/config.js +0 -1310
  509. package/extensions/dm-mcp-adapter/dist/consent-manager.js +0 -84
  510. package/extensions/dm-mcp-adapter/dist/elicitation-handler.js +0 -308
  511. package/extensions/dm-mcp-adapter/dist/errors.js +0 -225
  512. package/extensions/dm-mcp-adapter/dist/http-ca.js +0 -71
  513. package/extensions/dm-mcp-adapter/dist/jev-client.js +0 -359
  514. package/extensions/dm-mcp-adapter/dist/jev-contracts.js +0 -1
  515. package/extensions/dm-mcp-adapter/dist/jev-key-store.js +0 -176
  516. package/extensions/dm-mcp-adapter/dist/json-schema-validator.js +0 -70
  517. package/extensions/dm-mcp-adapter/dist/lifecycle.js +0 -387
  518. package/extensions/dm-mcp-adapter/dist/logger.js +0 -115
  519. package/extensions/dm-mcp-adapter/dist/mcp-auth-fetch.js +0 -86
  520. package/extensions/dm-mcp-adapter/dist/mcp-auth-flow.js +0 -949
  521. package/extensions/dm-mcp-adapter/dist/mcp-auth.js +0 -997
  522. package/extensions/dm-mcp-adapter/dist/mcp-bearer-store.js +0 -182
  523. package/extensions/dm-mcp-adapter/dist/mcp-callback-server.js +0 -381
  524. package/extensions/dm-mcp-adapter/dist/mcp-oauth-provider.js +0 -524
  525. package/extensions/dm-mcp-adapter/dist/mcp-probe.js +0 -151
  526. package/extensions/dm-mcp-adapter/dist/mcp-tasks.js +0 -300
  527. package/extensions/dm-mcp-adapter/dist/mcp-trace.js +0 -215
  528. package/extensions/dm-mcp-adapter/dist/metadata-cache.js +0 -267
  529. package/extensions/dm-mcp-adapter/dist/npx-resolver.js +0 -465
  530. package/extensions/dm-mcp-adapter/dist/package-mcp-loader.js +0 -135
  531. package/extensions/dm-mcp-adapter/dist/request-headers-command.js +0 -294
  532. package/extensions/dm-mcp-adapter/dist/resource-tools.js +0 -7
  533. package/extensions/dm-mcp-adapter/dist/runtime-owner.js +0 -94
  534. package/extensions/dm-mcp-adapter/dist/sampling-handler.js +0 -213
  535. package/extensions/dm-mcp-adapter/dist/secure-keyring.js +0 -191
  536. package/extensions/dm-mcp-adapter/dist/server-manager.js +0 -1514
  537. package/extensions/dm-mcp-adapter/dist/session-approvals.js +0 -127
  538. package/extensions/dm-mcp-adapter/dist/session-recovery.js +0 -82
  539. package/extensions/dm-mcp-adapter/dist/state.js +0 -1
  540. package/extensions/dm-mcp-adapter/dist/types.js +0 -286
  541. package/extensions/dm-mcp-adapter/dist/ui-app-bridge-helpers.js +0 -36
  542. package/extensions/dm-mcp-adapter/dist/ui-resource-handler.js +0 -204
  543. package/extensions/dm-mcp-adapter/dist/ui-stream-types.js +0 -58
  544. package/extensions/dm-mcp-adapter/dist/ui-tool-visibility.js +0 -26
  545. package/extensions/dm-mcp-adapter/dist/unix-socket-transport.js +0 -83
  546. package/extensions/dm-mcp-adapter/dist/utils.js +0 -382
@@ -1,2709 +0,0 @@
1
- import { spawn as nodeSpawn } from "node:child_process";
2
- import { EventEmitter } from "node:events";
3
- import { access, lstat, readFile } from "node:fs/promises";
4
- import * as os from "node:os";
5
- import { pathToFileURL } from "node:url";
6
- import { emitBounded } from "../bounded-telemetry.js";
7
- import { withTimeout } from "../deadline-utils.js";
8
- import { minimatch } from "../deps/minimatch.js";
9
- import { mapWithConcurrency } from "../map-with-concurrency.js";
10
- import { incrementDegradationCount, recordDegradationOnce } from "../degradation-ledger.js";
11
- import { CancellationTokenSource, createMessageConnection, StreamMessageReader, StreamMessageWriter } from "../deps/vscode-jsonrpc.js";
12
- import { logExtension } from "../extension-log.js";
13
- import { recordLspChild, removeLspChild } from "../instance-registry.js";
14
- import { workspaceDiagnosticsCacheSessionStart } from "./workspace-diagnostics-session.js";
15
- import { logLatency } from "../latency-logger.js";
16
- import { newLspMutationCorrelationId } from "../lsp-mutation.js";
17
- import { getProcessSingleton } from "../process-singletons.js";
18
- import { getAmbientAbortSignal, isOwnLiveChild, releaseOwnChildPid } from "../safe-spawn.js";
19
- import { raceToCompletion } from "./aggregation.js";
20
- import { hashDiagnosticContent } from "./diagnostic-binding.js";
21
- import { applyWorkspaceEdit, normalizeWorkspaceEditToUtf16 } from "./edits.js";
22
- import { normalizeMapKey, uriToPath } from "./path-utils.js";
23
- import { ADVERTISED_POSITION_ENCODINGS, convertCharacterOffset, lineTextAt, negotiatePositionEncoding } from "./position-encoding.js";
24
- import { negotiateSaveOptions, negotiateSyncKind, TEXT_DOCUMENT_SYNC_KIND_FULL, TEXT_DOCUMENT_SYNC_KIND_INCREMENTAL } from "./sync-kind.js";
25
- import { exceedsLspSyncLimits } from "./content-limits.js";
26
- import { probeTsserverProjectIdentity } from "./tsserver-sync.js";
27
- import { getStrategy } from "./wait-policy/index.js";
28
- import { WatchedFilesQueue } from "./watch-queue.js";
29
- import { clearAllWorkspaceDiagnosticsCaches, clearWorkspaceDiagnosticsCacheAtAndAbove } from "./workspace-diagnostics-cache.js";
30
- const PUB_DEBUG = Boolean(process.env.PILENS_PUB_DEBUG);
31
- function extractSpawnMarker(args) {
32
- if (!args)
33
- return;
34
- const tmpDir = os.tmpdir();
35
- for (let i = 0;i < args.length - 1; i++) {
36
- const flag = args[i];
37
- if (flag === "--config" || flag === "-c") {
38
- const value = args[i + 1];
39
- if (value?.startsWith(tmpDir))
40
- return value;
41
- }
42
- }
43
- return;
44
- }
45
- export const INITIALIZE_TIMEOUT_MS = positiveIntFromEnv("DM_LENS_LSP_INIT_TIMEOUT_MS", 15000);
46
- export const CLIENT_CAPABILITIES = {
47
- general: { positionEncodings: ADVERTISED_POSITION_ENCODINGS },
48
- window: {},
49
- workspace: {
50
- workspaceFolders: true,
51
- configuration: true,
52
- didChangeWatchedFiles: { dynamicRegistration: true },
53
- fileOperations: {
54
- dynamicRegistration: false,
55
- willRename: true,
56
- didRename: true
57
- }
58
- },
59
- textDocument: {
60
- synchronization: {
61
- dynamicRegistration: false,
62
- willSave: false,
63
- willSaveWaitUntil: false,
64
- didSave: true
65
- },
66
- completion: {
67
- dynamicRegistration: false,
68
- completionItem: { snippetSupport: false }
69
- },
70
- hover: { dynamicRegistration: false },
71
- signatureHelp: { dynamicRegistration: false },
72
- definition: { dynamicRegistration: false },
73
- typeDefinition: { dynamicRegistration: false },
74
- implementation: { dynamicRegistration: false },
75
- references: { dynamicRegistration: false },
76
- documentSymbol: { dynamicRegistration: false },
77
- codeAction: {
78
- dynamicRegistration: false,
79
- dataSupport: true,
80
- resolveSupport: { properties: ["edit", "command"] },
81
- codeActionLiteralSupport: {
82
- codeActionKind: {
83
- valueSet: [
84
- "quickfix",
85
- "refactor",
86
- "refactor.extract",
87
- "refactor.inline",
88
- "refactor.rewrite",
89
- "source",
90
- "source.organizeImports"
91
- ]
92
- }
93
- }
94
- },
95
- rename: { dynamicRegistration: false },
96
- publishDiagnostics: {
97
- relatedInformation: true,
98
- versionSupport: true
99
- }
100
- }
101
- };
102
- const NAV_REQUEST_TIMEOUT_MS = positiveIntFromEnv("DM_LENS_LSP_NAV_REQUEST_TIMEOUT_MS", 1e4);
103
- const DIAGNOSTICS_WAIT_TIMEOUT_MS = positiveIntFromEnv("DM_LENS_LSP_DIAGNOSTICS_WAIT_MS", 1e4);
104
- const PULL_DIAGNOSTICS_RETRY_INTERVAL_MS = positiveIntFromEnv("DM_LENS_LSP_PULL_RETRY_INTERVAL_MS", 250);
105
- const PULL_REQUEST_TIMEOUT_MS = positiveIntFromEnv("DM_LENS_LSP_PULL_REQUEST_TIMEOUT_MS", 1e4);
106
- const PULL_MIN_USABLE_BUDGET_MS = 5;
107
- const SHUTDOWN_REQUEST_TIMEOUT_MS = positiveIntFromEnv("DM_LENS_LSP_SHUTDOWN_TIMEOUT_MS", 1000);
108
- const EXIT_NOTIFY_TIMEOUT_MS = positiveIntFromEnv("DM_LENS_LSP_EXIT_NOTIFY_TIMEOUT_MS", 1000);
109
- const LIVENESS_PING_TIMEOUT_MS = positiveIntFromEnv("DM_LENS_LSP_LIVENESS_PING_TIMEOUT_MS", 300);
110
- const LIVENESS_PING_QUERY = "__dm_lens_liveness_ping__";
111
- const WORKSPACE_PULL_RESULT_CACHE_MAX = 4096;
112
- const WORKSPACE_PULL_SCOPE = "*workspace*";
113
- const REFRESH_REPULL_CONCURRENCY = 4;
114
- const EXECUTE_COMMAND_TIMEOUT_MS = positiveIntFromEnv("DM_LENS_LSP_EXECUTE_COMMAND_TIMEOUT_MS", 30000);
115
- const PROBE_COMMAND_TIMEOUT_MS = positiveIntFromEnv("DM_LENS_LSP_PROJECT_IDENTITY_PROBE_TIMEOUT_MS", 2500);
116
- const LSP_CRASH_CODES = new Set([
117
- "ERR_STREAM_DESTROYED",
118
- "ERR_STREAM_WRITE_AFTER_END",
119
- "EPIPE",
120
- "ECONNRESET"
121
- ]);
122
- let crashGuardInstalled = false;
123
- function isIgnorableLspRuntimeCrash(err) {
124
- if (!(err instanceof Error))
125
- return false;
126
- const code = err.code;
127
- if (code && LSP_CRASH_CODES.has(code))
128
- return true;
129
- const msg = err.message.toLowerCase();
130
- const stack = (err.stack ?? "").toLowerCase();
131
- return msg.includes("stream") || msg.includes("write after end") || stack.includes("vscode-jsonrpc/lib/node/ril.js");
132
- }
133
- function installCrashGuard() {
134
- if (crashGuardInstalled)
135
- return;
136
- crashGuardInstalled = true;
137
- process.on("uncaughtException", (err) => {
138
- if (isIgnorableLspRuntimeCrash(err)) {
139
- return;
140
- }
141
- throw err;
142
- });
143
- process.on("unhandledRejection", (reason) => {
144
- if (isIgnorableLspRuntimeCrash(reason)) {
145
- return;
146
- }
147
- throw reason instanceof Error ? reason : new Error(String(reason));
148
- });
149
- }
150
- export const MAX_INCREMENTAL_TEXT_RETAINED_ENTRIES = 128;
151
- export const MAX_INCREMENTAL_TEXT_RETAINED_BYTES = 64 * 1024 * 1024;
152
- const ACTIVE_CLIENTS_FAMILY = "lsp-client.active-clients";
153
- const ACTIVE_CLIENTS_VERSION = 1;
154
- function activeLspClientSet() {
155
- return getProcessSingleton(ACTIVE_CLIENTS_FAMILY, ACTIVE_CLIENTS_VERSION, () => new Set);
156
- }
157
- export function getLspDocumentTextRetentionSnapshot() {
158
- let entries = 0;
159
- let bytes = 0;
160
- const roots = new Set;
161
- const active = activeLspClientSet();
162
- for (const state of active) {
163
- entries += state.incrementalTextRetainedEntries ?? 0;
164
- bytes += state.incrementalTextRetainedBytes ?? 0;
165
- if (typeof state.root === "string" && state.root.length > 0) {
166
- roots.add(state.root);
167
- }
168
- }
169
- return { clients: active.size, entries, bytes, roots: roots.size };
170
- }
171
- function isClientAlive(state) {
172
- return state.isConnected && !state.isDestroyed && !state.lspProcess.process.killed;
173
- }
174
- function disposeClientConnection(state) {
175
- if (state.connectionDisposed)
176
- return;
177
- state.connectionDisposed = true;
178
- activeLspClientSet().delete(state);
179
- try {
180
- state.connection.dispose();
181
- } catch {}
182
- }
183
- export async function killProcessTree(proc, pid, options = {}) {
184
- if ((proc.exitCode != null || proc.signalCode != null) && !options.processExiting) {
185
- releaseOwnChildPid(pid);
186
- proc.unref?.();
187
- return;
188
- }
189
- if (process.platform === "win32" && pid > 0) {
190
- if (options.processExiting) {
191
- try {
192
- proc.kill();
193
- } catch {}
194
- proc.unref?.();
195
- return;
196
- }
197
- try {
198
- const taskkill = `${process.env.SystemRoot ?? "C:\\Windows"}\\System32\\taskkill.exe`;
199
- const killer = nodeSpawn(taskkill, ["/F", "/T", "/PID", String(pid)], {
200
- shell: false,
201
- windowsHide: true,
202
- stdio: "ignore",
203
- detached: !!options.fast
204
- });
205
- if (options.fast) {
206
- killer.unref();
207
- proc.unref?.();
208
- return;
209
- }
210
- await new Promise((resolve) => {
211
- killer.once("close", () => resolve());
212
- killer.once("error", (err) => {
213
- logLatency({
214
- type: "phase",
215
- phase: "lsp_kill_escalation",
216
- filePath: "",
217
- durationMs: 0,
218
- metadata: { pid, platform: "win32", taskkillError: String(err) }
219
- });
220
- resolve();
221
- });
222
- });
223
- } catch (err) {
224
- logLatency({
225
- type: "phase",
226
- phase: "lsp_kill_escalation",
227
- filePath: "",
228
- durationMs: 0,
229
- metadata: { pid, platform: "win32", taskkillSpawnError: String(err) }
230
- });
231
- }
232
- return;
233
- }
234
- const killPosixProcessGroup = (signal) => {
235
- if (!isOwnLiveChild(pid, "lsp-stop-posix-group"))
236
- return false;
237
- try {
238
- process.kill(-pid, signal);
239
- return true;
240
- } catch {
241
- return false;
242
- }
243
- };
244
- const killDirectChild = (signal) => {
245
- try {
246
- proc.kill(signal);
247
- } catch {}
248
- };
249
- try {
250
- let exited = proc.exitCode != null || proc.signalCode != null;
251
- proc.once?.("exit", () => {
252
- exited = true;
253
- });
254
- if (!killPosixProcessGroup("SIGTERM")) {
255
- killDirectChild("SIGTERM");
256
- }
257
- if (options.fast) {
258
- const timer = setTimeout(() => {
259
- if (!exited) {
260
- logLatency({
261
- type: "phase",
262
- phase: "lsp_kill_escalation",
263
- filePath: "",
264
- durationMs: 1500,
265
- metadata: { pid, platform: "posix", method: "SIGKILL", fast: true }
266
- });
267
- if (!killPosixProcessGroup("SIGKILL")) {
268
- killDirectChild("SIGKILL");
269
- }
270
- }
271
- releaseOwnChildPid(pid);
272
- }, 1500);
273
- timer.unref?.();
274
- proc.unref?.();
275
- return;
276
- }
277
- const exitedInTime = await new Promise((resolve) => {
278
- if (proc.exitCode != null || proc.signalCode != null) {
279
- resolve(true);
280
- return;
281
- }
282
- const onExit = () => {
283
- clearTimeout(timer);
284
- resolve(true);
285
- };
286
- const timer = setTimeout(() => {
287
- proc.off?.("exit", onExit);
288
- resolve(false);
289
- }, 1500);
290
- proc.once?.("exit", onExit);
291
- });
292
- if (!exitedInTime && !exited) {
293
- logLatency({
294
- type: "phase",
295
- phase: "lsp_kill_escalation",
296
- filePath: "",
297
- durationMs: 1500,
298
- metadata: { pid, platform: "posix", method: "SIGKILL", fast: false }
299
- });
300
- if (!killPosixProcessGroup("SIGKILL")) {
301
- killDirectChild("SIGKILL");
302
- }
303
- }
304
- releaseOwnChildPid(pid);
305
- } catch {}
306
- }
307
- export function stripDiagnosticNoiseLines(message) {
308
- const cleaned = message.split(/\r?\n/).filter((line) => {
309
- const trimmed = line.trim();
310
- if (/^for further information visit\b/i.test(trimmed))
311
- return false;
312
- if (/^https?:\/\/\S+$/i.test(trimmed))
313
- return false;
314
- return true;
315
- }).join(`
316
- `).trim();
317
- return cleaned || message.trim() || message;
318
- }
319
- function normalizeLspDiagnostic(diagnostic) {
320
- const message = stripDiagnosticNoiseLines(diagnostic.message);
321
- return message === diagnostic.message ? diagnostic : { ...diagnostic, message };
322
- }
323
- function normalizeLspDiagnostics(diagnostics) {
324
- return diagnostics.map(normalizeLspDiagnostic);
325
- }
326
- function mergeDiagnosticLists(...lists) {
327
- const merged = [];
328
- const seen = new Set;
329
- for (const diagnostic of lists.flatMap((list) => list ?? [])) {
330
- const key = [
331
- diagnostic.range.start.line,
332
- diagnostic.range.start.character,
333
- diagnostic.range.end.line,
334
- diagnostic.range.end.character,
335
- diagnostic.code ?? "",
336
- diagnostic.source ?? "",
337
- diagnostic.message
338
- ].join(":");
339
- if (seen.has(key))
340
- continue;
341
- seen.add(key);
342
- merged.push(diagnostic);
343
- }
344
- return merged;
345
- }
346
- function getMergedDiagnosticsForPath(state, normalizedPath) {
347
- const legacy = state;
348
- return mergeDiagnosticLists(state.pushDiagnostics?.get(normalizedPath) ?? legacy.diagnostics?.get(normalizedPath), state.documentPullDiagnostics?.get(normalizedPath));
349
- }
350
- const PULL_SOURCE_KEY_SEPARATOR = "\x00";
351
- const BARE_PULL_SOURCE = "";
352
- function pullSourceKey(normalizedPath, identifier) {
353
- return identifier === undefined ? normalizedPath : `${normalizedPath}${PULL_SOURCE_KEY_SEPARATOR}${identifier}`;
354
- }
355
- function pullSourceKeysForPath(state, normalizedPath) {
356
- const prefix = `${normalizedPath}${PULL_SOURCE_KEY_SEPARATOR}`;
357
- return [
358
- normalizedPath,
359
- ...[...state.pullResultIds?.keys() ?? []].filter((key) => key.startsWith(prefix))
360
- ];
361
- }
362
- function pullSourcesFor(state, normalizedPath) {
363
- if (!state.documentPullDiagnosticsBySource) {
364
- state.documentPullDiagnosticsBySource = new Map;
365
- }
366
- let sources = state.documentPullDiagnosticsBySource.get(normalizedPath);
367
- if (!sources) {
368
- sources = new Map;
369
- state.documentPullDiagnosticsBySource.set(normalizedPath, sources);
370
- }
371
- return sources;
372
- }
373
- function pullSourceDiagnostics(state, normalizedPath, identifier) {
374
- const sources = state.documentPullDiagnosticsBySource?.get(normalizedPath);
375
- const stored = sources?.get(identifier ?? BARE_PULL_SOURCE);
376
- if (stored)
377
- return stored;
378
- return sources && sources.size > 0 ? [] : state.documentPullDiagnostics.get(normalizedPath) ?? [];
379
- }
380
- function storePullSourceDiagnostics(state, normalizedPath, identifier, diagnostics) {
381
- const sources = pullSourcesFor(state, normalizedPath);
382
- sources.set(identifier ?? BARE_PULL_SOURCE, diagnostics);
383
- state.documentPullDiagnostics.set(normalizedPath, mergeDiagnosticLists(...sources.values()));
384
- }
385
- function pullGenerationFor(state, normalizedPath) {
386
- return state.pullGenerations?.get(normalizedPath) ?? 0;
387
- }
388
- function bumpPullGeneration(state, normalizedPath) {
389
- if (!state.pullGenerations)
390
- state.pullGenerations = new Map;
391
- state.pullGenerations.set(normalizedPath, (state.pullGenerations.get(normalizedPath) ?? 0) + 1);
392
- }
393
- function claimPullRequestSequence(state, sourceKey) {
394
- if (!state.pullRequestSequences)
395
- state.pullRequestSequences = new Map;
396
- const next = (state.pullRequestSequences.get(sourceKey) ?? 0) + 1;
397
- state.pullRequestSequences.set(sourceKey, next);
398
- return next;
399
- }
400
- function isNewestPullRequest(state, sourceKey, sequence) {
401
- return (state.pullRequestSequences?.get(sourceKey) ?? 0) === sequence;
402
- }
403
- function retirePullSource(state, identifier) {
404
- const suffix = `${PULL_SOURCE_KEY_SEPARATOR}${identifier}`;
405
- for (const source of [state.pullResultIds, state.pullRequestSequences]) {
406
- if (!source)
407
- continue;
408
- for (const key of source.keys()) {
409
- if (key.endsWith(suffix))
410
- source.delete(key);
411
- }
412
- }
413
- for (const [normalizedPath, sources] of state.documentPullDiagnosticsBySource ?? []) {
414
- if (!sources.delete(identifier))
415
- continue;
416
- state.documentPullDiagnostics.set(normalizedPath, mergeDiagnosticLists(...sources.values()));
417
- bumpDiagnosticsVersion(state, normalizedPath);
418
- state.diagnosticEmitter.emit("diagnostics", normalizedPath);
419
- }
420
- }
421
- export function pullDiagnosticSources(state) {
422
- const identifiers = new Set;
423
- for (const registration of state.dynamicRegistrations?.values() ?? []) {
424
- if (registration.method !== "textDocument/diagnostic")
425
- continue;
426
- if (registration.identifier)
427
- identifiers.add(registration.identifier);
428
- }
429
- return [undefined, ...[...identifiers].sort((a, b) => a.localeCompare(b))];
430
- }
431
- export function bumpDiagnosticsVersion(state, normalizedPath) {
432
- state.diagnosticsVersion += 1;
433
- state.diagnosticsVersionsByPath?.set(normalizedPath, state.diagnosticsVersion);
434
- }
435
- export function diagnosticsVersionForPath(state, normalizedPath) {
436
- return state.diagnosticsVersionsByPath?.get(normalizedPath) ?? 0;
437
- }
438
- export function clearDiagnosticsForPath(state, normalizedPath) {
439
- const legacy = state;
440
- state.pushDiagnostics?.delete(normalizedPath);
441
- const pending = state.pendingDiagnostics?.get(normalizedPath);
442
- if (pending)
443
- clearTimeout(pending);
444
- state.pendingDiagnostics?.delete(normalizedPath);
445
- state.pushDiagnosticTimestamps?.delete(normalizedPath);
446
- state.documentPullDiagnostics?.delete(normalizedPath);
447
- state.documentPullDiagnosticTimestamps?.delete(normalizedPath);
448
- state.diagnosticDocVersions?.delete(normalizedPath);
449
- state.diagnosticBindings?.delete(normalizedPath);
450
- state.diagnosticsVersionsByPath?.delete(normalizedPath);
451
- for (const key of pullSourceKeysForPath(state, normalizedPath)) {
452
- state.pullResultIds?.delete(key);
453
- }
454
- state.documentPullDiagnosticsBySource?.delete(normalizedPath);
455
- bumpPullGeneration(state, normalizedPath);
456
- state.workspacePullResultCache?.delete(normalizedPath);
457
- legacy.diagnostics?.delete(normalizedPath);
458
- legacy.diagnosticTimestamps?.delete(normalizedPath);
459
- }
460
- function logTypeScriptPullSettle(state, normalizedPath, durationMs, pullSettleSource) {
461
- if (state.serverId !== "typescript")
462
- return;
463
- const diagnostics = state.documentPullDiagnostics.get(normalizedPath) ?? [];
464
- const elapsedSinceDidOpenMs = Math.max(0, Date.now() - (state.documentOpenedAt.get(normalizedPath) ?? Date.now()));
465
- const diagnosticCodes = [
466
- ...new Set(diagnostics.map((diagnostic) => diagnostic.code).filter((code) => code !== undefined).map(String))
467
- ].slice(0, 8);
468
- const trackedVersion = state.diagnosticsVersionsByPath?.get(normalizedPath);
469
- logLatency({
470
- type: "phase",
471
- phase: "lsp_typescript_diagnostic_sequence",
472
- filePath: normalizedPath,
473
- durationMs,
474
- metadata: {
475
- serverId: state.serverId,
476
- outcome: "settled",
477
- launchVariant: state.launchVariant ?? "unknown",
478
- publicationIndex: state.diagnosticPublicationCounts.get(normalizedPath) ?? 0,
479
- version: trackedVersion ?? "pull-unversioned",
480
- diagnosticCount: diagnostics.length,
481
- diagnosticCodes,
482
- elapsedSinceDidOpenMs,
483
- settledReturn: true,
484
- settleSource: pullSettleSource
485
- }
486
- });
487
- }
488
- function scanSentContent(content) {
489
- let lfNewlineCount = 0;
490
- let index = 0;
491
- let start = 0;
492
- for (let i = 0;i < content.length; i++) {
493
- const code = content.charCodeAt(i);
494
- if (code !== 10 && code !== 13)
495
- continue;
496
- if (code === 10) {
497
- lfNewlineCount++;
498
- } else if (content.charCodeAt(i + 1) === 10) {
499
- lfNewlineCount++;
500
- i++;
501
- }
502
- index++;
503
- start = i + 1;
504
- }
505
- return { lfNewlineCount, lastLine: { index, start } };
506
- }
507
- function recordSentContent(state, normalizedPath, version, content, coalescedCount = 0) {
508
- const scan = scanSentContent(content);
509
- const previous = state.documentContentHashes.get(normalizedPath);
510
- if (previous && previous.version > version) {
511
- incrementDegradationCount({
512
- kind: "lsp-document-send-order",
513
- subject: `${state.serverId}:${normalizedPath}`,
514
- reason: `recorded version ${version} after newer version ${previous.version}`
515
- });
516
- return;
517
- }
518
- if (previous?.text !== undefined) {
519
- state.incrementalTextRetainedEntries = Math.max(0, (state.incrementalTextRetainedEntries ?? 1) - 1);
520
- state.incrementalTextRetainedBytes = Math.max(0, (state.incrementalTextRetainedBytes ?? previous.text.length * 2) - previous.text.length * 2);
521
- state.incrementalTextBearingPaths?.delete(normalizedPath);
522
- }
523
- state.documentContentHashes.delete(normalizedPath);
524
- state.documentContentHashes.set(normalizedPath, {
525
- version,
526
- hash: hashDiagnosticContent(content),
527
- ...state.syncKind === TEXT_DOCUMENT_SYNC_KIND_INCREMENTAL && {
528
- text: content,
529
- lastLine: scan.lastLine
530
- }
531
- });
532
- if (state.syncKind === TEXT_DOCUMENT_SYNC_KIND_INCREMENTAL) {
533
- state.incrementalTextRetainedEntries = (state.incrementalTextRetainedEntries ?? 0) + 1;
534
- state.incrementalTextRetainedBytes = (state.incrementalTextRetainedBytes ?? 0) + content.length * 2;
535
- if (!state.incrementalTextBearingPaths) {
536
- state.incrementalTextBearingPaths = new Set;
537
- }
538
- state.incrementalTextBearingPaths.add(normalizedPath);
539
- while ((state.incrementalTextRetainedEntries ?? 0) > MAX_INCREMENTAL_TEXT_RETAINED_ENTRIES || (state.incrementalTextRetainedBytes ?? 0) > MAX_INCREMENTAL_TEXT_RETAINED_BYTES) {
540
- const oldestPath = state.incrementalTextBearingPaths?.values().next().value;
541
- if (oldestPath === undefined)
542
- break;
543
- const binding = state.documentContentHashes.get(oldestPath);
544
- state.incrementalTextBearingPaths.delete(oldestPath);
545
- if (!binding || binding.text === undefined)
546
- continue;
547
- state.documentContentHashes.set(oldestPath, {
548
- version: binding.version,
549
- hash: binding.hash
550
- });
551
- state.incrementalTextRetainedEntries = Math.max(0, (state.incrementalTextRetainedEntries ?? 1) - 1);
552
- state.incrementalTextRetainedBytes = Math.max(0, (state.incrementalTextRetainedBytes ?? 0) - binding.text.length * 2);
553
- }
554
- }
555
- logLatency({
556
- type: "phase",
557
- phase: "lsp_document_send",
558
- filePath: normalizedPath,
559
- durationMs: 0,
560
- metadata: {
561
- version,
562
- contentLength: content.length,
563
- contentLineCount: scan.lfNewlineCount + 1,
564
- ...coalescedCount > 0 && { coalescedCount }
565
- }
566
- });
567
- }
568
- function buildContentChanges(state, normalizedPath, content) {
569
- if (state.syncKind !== TEXT_DOCUMENT_SYNC_KIND_INCREMENTAL) {
570
- return [{ text: content }];
571
- }
572
- const previous = state.documentContentHashes.get(normalizedPath);
573
- if (previous?.text === undefined) {
574
- return [{ text: content }];
575
- }
576
- const previousText = previous.text;
577
- const lastLine = previous.lastLine ?? scanSentContent(previousText).lastLine;
578
- const lastLineText = previousText.slice(lastLine.start);
579
- return [
580
- {
581
- range: {
582
- start: { line: 0, character: 0 },
583
- end: {
584
- line: lastLine.index,
585
- character: convertCharacterOffset(state.positionEncoding, lastLineText, lastLineText.length)
586
- }
587
- },
588
- text: content
589
- }
590
- ];
591
- }
592
- const DYNAMIC_OPERATION_METHOD_MAP = {
593
- "textDocument/definition": "definition",
594
- "textDocument/typeDefinition": "typeDefinition",
595
- "textDocument/declaration": "declaration",
596
- "textDocument/references": "references",
597
- "textDocument/hover": "hover",
598
- "textDocument/signatureHelp": "signatureHelp",
599
- "textDocument/documentSymbol": "documentSymbol",
600
- "workspace/symbol": "workspaceSymbol",
601
- "textDocument/codeAction": "codeAction",
602
- "textDocument/rename": "rename",
603
- "textDocument/implementation": "implementation",
604
- "textDocument/prepareCallHierarchy": "callHierarchy"
605
- };
606
- export function applyDynamicCapabilities(state) {
607
- const registrations = [...state.dynamicRegistrations.values()];
608
- const registeredMethods = new Set(registrations.map((r) => r.method));
609
- const hasDynamicPull = registeredMethods.has("textDocument/diagnostic") || registeredMethods.has("workspace/diagnostic");
610
- if (hasDynamicPull) {
611
- state.workspaceDiagnosticsSupport = {
612
- advertised: true,
613
- mode: "pull",
614
- workspaceDiagnostics: registrations.some((r) => r.workspaceDiagnostics === true) || registeredMethods.has("workspace/diagnostic"),
615
- diagnosticProviderKind: "dynamic"
616
- };
617
- } else if (state.staticDiagnosticsMode === "push-only" && state.workspaceDiagnosticsSupport.diagnosticProviderKind === "dynamic") {
618
- state.workspaceDiagnosticsSupport = {
619
- advertised: false,
620
- mode: "push-only",
621
- workspaceDiagnostics: false,
622
- diagnosticProviderKind: "none"
623
- };
624
- }
625
- for (const [method, key] of Object.entries(DYNAMIC_OPERATION_METHOD_MAP)) {
626
- if (registeredMethods.has(method)) {
627
- state.operationSupport[key] = true;
628
- }
629
- }
630
- }
631
- export function resolveConfigurationSection(initialization, section) {
632
- if (!initialization)
633
- return {};
634
- if (!section)
635
- return initialization;
636
- let cur = initialization;
637
- for (const part of section.split(".")) {
638
- if (typeof cur !== "object" || cur === null || !Object.hasOwn(cur, part)) {
639
- return {};
640
- }
641
- cur = cur[part];
642
- }
643
- return cur;
644
- }
645
- export function setupIncomingHandlers(state, initialization, onDiagnosticsPublished) {
646
- state.connection.onNotification("textDocument/publishDiagnostics", (params) => {
647
- const publishReceivedAt = Date.now();
648
- const filePath = uriToPath(params.uri);
649
- const normalizedPath = normalizeMapKey(filePath);
650
- if (state.closedDocuments?.has(normalizedPath))
651
- return;
652
- onDiagnosticsPublished?.(state.serverId);
653
- const newDiags = normalizeLspDiagnostics(params.diagnostics || []);
654
- const docVersion = params.version;
655
- if (PUB_DEBUG) {
656
- logExtension({
657
- subsystem: "lsp-pub",
658
- level: "debug",
659
- message: `server=${state.serverId} pubVersion=${docVersion} docVersion=${state.documentVersions?.get(normalizedPath)} diags=${newDiags.length}`
660
- });
661
- }
662
- const strategy = getStrategy(state.serverId, state.launchVariant);
663
- const isTypeScriptTelemetry = state.serverId === "typescript";
664
- const publicationIndex = isTypeScriptTelemetry ? (state.diagnosticPublicationCounts.get(normalizedPath) ?? 0) + 1 : 0;
665
- if (isTypeScriptTelemetry) {
666
- state.diagnosticPublicationCounts.set(normalizedPath, publicationIndex);
667
- }
668
- const diagnosticCodes = isTypeScriptTelemetry ? [
669
- ...new Set(newDiags.map((diagnostic) => diagnostic.code).filter((code) => code !== undefined).map(String))
670
- ].slice(0, 8) : [];
671
- const logSequence = (settledReturn, settleSource, durationMs) => {
672
- if (state.serverId !== "typescript")
673
- return;
674
- const elapsedSinceDidOpenMs = Math.max(0, Date.now() - (state.documentOpenedAt.get(normalizedPath) ?? Date.now()));
675
- logLatency({
676
- type: "phase",
677
- phase: "lsp_typescript_diagnostic_sequence",
678
- filePath: normalizedPath,
679
- durationMs,
680
- metadata: {
681
- serverId: state.serverId,
682
- outcome: settledReturn ? "settled" : "published",
683
- launchVariant: state.launchVariant ?? "unknown",
684
- publicationIndex,
685
- version: docVersion ?? "push-unversioned",
686
- diagnosticCount: newDiags.length,
687
- diagnosticCodes,
688
- elapsedSinceDidOpenMs,
689
- settledReturn,
690
- settleSource
691
- }
692
- });
693
- };
694
- const recordDocVersion = () => {
695
- if (docVersion !== undefined) {
696
- state.diagnosticDocVersions.set(normalizedPath, docVersion);
697
- }
698
- recordBinding();
699
- };
700
- const recordBinding = () => {
701
- if (docVersion === undefined) {
702
- state.diagnosticBindings.delete(normalizedPath);
703
- return;
704
- }
705
- const sent = state.documentContentHashes.get(normalizedPath);
706
- state.diagnosticBindings.set(normalizedPath, {
707
- version: docVersion,
708
- contentHash: sent && sent.version === docVersion ? sent.hash : undefined
709
- });
710
- };
711
- const isSupersededPush = () => {
712
- if (docVersion === undefined)
713
- return false;
714
- const currentVersion = state.documentVersions.get(normalizedPath);
715
- return currentVersion !== undefined && docVersion < currentVersion;
716
- };
717
- if (strategy.emptyFirstPublish === "indexing" && !state.emptyFirstPublishHoldSpent && newDiags.length === 0 && !state.pushDiagnostics.has(normalizedPath) && !state.pendingDiagnostics.has(normalizedPath)) {
718
- state.emptyFirstPublishHoldSpent = true;
719
- logLatency({
720
- type: "phase",
721
- phase: "lsp_empty_first_publish_held",
722
- filePath: normalizedPath,
723
- durationMs: Math.max(0, publishReceivedAt - (state.documentOpenedAt.get(normalizedPath) ?? publishReceivedAt)),
724
- metadata: {
725
- serverId: state.serverId,
726
- emptyFirstPublish: strategy.emptyFirstPublish,
727
- pubVersion: docVersion ?? "push-unversioned"
728
- }
729
- });
730
- return;
731
- }
732
- if (strategy.seedFirstPush && !state.pushDiagnostics.has(normalizedPath)) {
733
- if (isSupersededPush())
734
- return;
735
- state.pushDiagnostics.set(normalizedPath, newDiags);
736
- state.pushDiagnosticTimestamps.set(normalizedPath, Date.now());
737
- recordDocVersion();
738
- bumpDiagnosticsVersion(state, normalizedPath);
739
- state.diagnosticEmitter.emit("diagnostics", normalizedPath);
740
- logSequence(true, "first-push", 0);
741
- return;
742
- }
743
- logSequence(false, "publication", 0);
744
- const existingTimer = state.pendingDiagnostics.get(normalizedPath);
745
- if (existingTimer)
746
- clearTimeout(existingTimer);
747
- const timer = setTimeout(() => {
748
- state.pendingDiagnostics.delete(normalizedPath);
749
- if (isSupersededPush())
750
- return;
751
- state.pushDiagnostics.set(normalizedPath, newDiags);
752
- state.pushDiagnosticTimestamps.set(normalizedPath, Date.now());
753
- recordDocVersion();
754
- bumpDiagnosticsVersion(state, normalizedPath);
755
- state.diagnosticEmitter.emit("diagnostics", normalizedPath);
756
- logSequence(true, "quiet-window", Date.now() - publishReceivedAt);
757
- }, strategy.debounceMs);
758
- state.pendingDiagnostics.set(normalizedPath, timer);
759
- });
760
- state.connection.onRequest("workspace/workspaceFolders", () => [
761
- { name: "workspace", uri: pathToFileURL(state.root).href }
762
- ]);
763
- state.connection.onRequest("client/registerCapability", async (params) => {
764
- for (const reg of params?.registrations ?? []) {
765
- const options = reg.registerOptions;
766
- const commands = Array.isArray(options?.commands) ? options.commands.filter((cmd) => typeof cmd === "string") : undefined;
767
- if (reg.id && reg.method) {
768
- state.dynamicRegistrations.set(reg.id, {
769
- method: reg.method,
770
- ...typeof options?.identifier === "string" && options.identifier ? { identifier: options.identifier } : {},
771
- ...typeof options?.workspaceDiagnostics === "boolean" ? { workspaceDiagnostics: options.workspaceDiagnostics } : {},
772
- ...commands ? { commands } : {}
773
- });
774
- }
775
- if (reg.method === "workspace/executeCommand" && commands) {
776
- for (const cmd of commands)
777
- state.advertisedCommands.add(cmd);
778
- }
779
- }
780
- applyDynamicCapabilities(state);
781
- });
782
- state.connection.onRequest("client/unregisterCapability", async (params) => {
783
- const retiredIdentifiers = new Set;
784
- for (const unreg of params?.unregisterations ?? []) {
785
- if (!unreg.id)
786
- continue;
787
- const registration = state.dynamicRegistrations.get(unreg.id);
788
- state.dynamicRegistrations.delete(unreg.id);
789
- if (registration?.method === "textDocument/diagnostic" && registration.identifier) {
790
- retiredIdentifiers.add(registration.identifier);
791
- }
792
- }
793
- const stillRegistered = new Set([...state.dynamicRegistrations.values()].filter((r) => r.method === "textDocument/diagnostic").map((r) => r.identifier));
794
- for (const identifier of retiredIdentifiers) {
795
- if (!stillRegistered.has(identifier)) {
796
- retirePullSource(state, identifier);
797
- }
798
- }
799
- applyDynamicCapabilities(state);
800
- });
801
- state.connection.onRequest("workspace/applyEdit", async (params) => {
802
- if (state.serverEditsAllowed <= 0 || !params?.edit) {
803
- return { applied: false, failureReason: "edit not solicited" };
804
- }
805
- const context = state.activeMutationContext;
806
- const telemetryContext = context ?? {
807
- cwd: state.root,
808
- correlationId: newLspMutationCorrelationId(),
809
- tool: "lsp-workspace-applyEdit",
810
- source: "lsp-execute-command"
811
- };
812
- try {
813
- await applyWorkspaceEdit(params.edit, state.root, {
814
- positionEncoding: state.positionEncoding,
815
- documentVersions: state.documentVersions,
816
- mutationContext: telemetryContext
817
- });
818
- return { applied: true };
819
- } catch (err) {
820
- return {
821
- applied: false,
822
- failureReason: err instanceof Error ? err.message : String(err)
823
- };
824
- }
825
- });
826
- state.connection.onRequest("workspace/configuration", async (params) => {
827
- const items = params?.items ?? [];
828
- return items.map((item) => resolveConfigurationSection(initialization, item?.section));
829
- });
830
- state.connection.onRequest("window/workDoneProgress/create", async () => {});
831
- let refreshRepullRunning = false;
832
- let refreshRepullRerunRequested = false;
833
- const runRefreshRepullPool = async () => {
834
- do {
835
- refreshRepullRerunRequested = false;
836
- const toRepull = state.workspaceDiagnosticsSupport.mode === "pull" ? [...state.openDocuments] : [];
837
- if (toRepull.length > 0) {
838
- try {
839
- await mapWithConcurrency(toRepull, REFRESH_REPULL_CONCURRENCY, async (normalizedPath) => {
840
- const uri = state.openDocumentUris?.get(normalizedPath);
841
- const filePath = uri ? uriToPath(uri) : normalizedPath;
842
- await clientRequestPullDiagnostics(state, filePath);
843
- });
844
- } catch (err) {
845
- incrementDegradationCount({
846
- kind: "lsp-pull-unconfirmed",
847
- subject: state.serverId,
848
- reason: `refresh re-pull threw: ${err instanceof Error ? err.message : String(err)}`
849
- });
850
- }
851
- }
852
- } while (refreshRepullRerunRequested);
853
- refreshRepullRunning = false;
854
- };
855
- state.connection.onRequest("workspace/diagnostic/refresh", async () => {
856
- state.workspacePullResultCache.clear();
857
- clearAllWorkspaceDiagnosticsCaches();
858
- clearWorkspaceDiagnosticsCacheAtAndAbove(state.root);
859
- for (const normalizedPath of state.openDocuments) {
860
- clearDiagnosticsForPath(state, normalizedPath);
861
- }
862
- if (state.workspaceDiagnosticsSupport.mode === "pull" && state.openDocuments.size > 0) {
863
- if (refreshRepullRunning) {
864
- refreshRepullRerunRequested = true;
865
- } else {
866
- refreshRepullRunning = true;
867
- setImmediate(() => {
868
- runRefreshRepullPool();
869
- });
870
- }
871
- }
872
- return null;
873
- });
874
- }
875
- function markExitedIfUnset(state) {
876
- if (state.exitedAt === undefined) {
877
- state.exitedAt = Date.now();
878
- }
879
- }
880
- function setupConnectionLifecycle(state, recentStderr) {
881
- state.connection.onError(([error]) => {
882
- state.lastError = error instanceof Error ? error : new Error(String(error));
883
- state.isConnected = false;
884
- state.isDestroyed = true;
885
- markExitedIfUnset(state);
886
- disposeClientConnection(state);
887
- });
888
- state.connection.onClose(() => {
889
- state.isConnected = false;
890
- state.isDestroyed = true;
891
- markExitedIfUnset(state);
892
- disposeClientConnection(state);
893
- });
894
- state.lspProcess.process.on("exit", (code, signal) => {
895
- const wasIntentional = state.shutdownRequested;
896
- state.isConnected = false;
897
- state.isDestroyed = true;
898
- markExitedIfUnset(state);
899
- disposeClientConnection(state);
900
- if (!wasIntentional) {
901
- logLatency({
902
- type: "phase",
903
- phase: "lsp_server_unexpected_exit",
904
- filePath: state.root,
905
- durationMs: 0,
906
- metadata: {
907
- serverId: state.serverId,
908
- pid: state.lspProcess.pid,
909
- exitCode: code ?? null,
910
- exitSignal: signal ?? null,
911
- stderrTail: recentStderr(20)
912
- }
913
- });
914
- }
915
- });
916
- state.lspProcess.process.on("close", (code, signal) => {
917
- if (state.shutdownRequested)
918
- return;
919
- try {
920
- const stderrTail = recentStderr(20);
921
- incrementDegradationCount({
922
- kind: "lsp-server-unexpected-close",
923
- subject: state.serverId,
924
- reason: `closed unprompted: code=${code ?? "none"} signal=${signal ?? "none"} ` + `stderr=${stderrTail.length > 0 ? `present(${stderrTail.length}b)` : "empty"} root=${state.root}`
925
- });
926
- } catch {}
927
- });
928
- }
929
- const PULL_RACE_BACKSTOP_MARGIN_MS = 25;
930
- async function clientRequestPullDiagnostics(state, filePath, budgetMs = PULL_REQUEST_TIMEOUT_MS) {
931
- if (!isClientAlive(state))
932
- return { status: "unavailable" };
933
- const sources = pullDiagnosticSources(state);
934
- if (sources.length === 1) {
935
- return aggregatePullOutcomes(state, filePath, [
936
- await pullDiagnosticSource(state, filePath, budgetMs, undefined)
937
- ]);
938
- }
939
- const attempts = sources.map((identifier) => pullDiagnosticSource(state, filePath, budgetMs, identifier));
940
- const settled = await raceToCompletion(attempts, (results) => results.some((r) => r.status === "found" && r.primaryCount > 0), {
941
- timeoutMs: Math.max(1, Math.min(PULL_REQUEST_TIMEOUT_MS, budgetMs)) + PULL_RACE_BACKSTOP_MARGIN_MS
942
- });
943
- return aggregatePullOutcomes(state, filePath, settled);
944
- }
945
- function aggregatePullOutcomes(state, filePath, outcomes) {
946
- const found = outcomes.filter((o) => o.status === "found");
947
- if (found.length > 0) {
948
- const normalizedPath = normalizeMapKey(filePath);
949
- const unionCount = state.documentPullDiagnostics.get(normalizedPath)?.length ?? 0;
950
- return {
951
- status: "found",
952
- count: Math.max(unionCount, ...found.map((o) => o.count))
953
- };
954
- }
955
- if (outcomes.some((o) => o.status === "unavailable")) {
956
- return { status: "unavailable" };
957
- }
958
- return outcomes.some((o) => o.status === "clean") ? { status: "clean" } : { status: "unavailable" };
959
- }
960
- async function pullDiagnosticSource(state, filePath, budgetMs, identifier) {
961
- if (!isClientAlive(state))
962
- return { status: "unavailable" };
963
- const normalizedPath = normalizeMapKey(filePath);
964
- if (budgetMs < PULL_MIN_USABLE_BUDGET_MS) {
965
- emitBounded("lsp_pull_skipped_budget_exhausted", `${state.serverId}::${pullSourceKey(normalizedPath, identifier)}`, {
966
- type: "phase",
967
- filePath: normalizedPath,
968
- durationMs: 0,
969
- metadata: {
970
- identifier: identifier ?? "bare",
971
- remainingBudgetMs: budgetMs,
972
- server: state.serverId
973
- }
974
- }, {
975
- ledgerKind: "lsp-pull-skipped-budget-exhausted",
976
- reason: `pull skipped on ${state.serverId}: budget already exhausted (${budgetMs}ms remaining)`
977
- });
978
- return { status: "unavailable" };
979
- }
980
- const uri = pathToFileURL(filePath).href;
981
- const sourceKey = pullSourceKey(normalizedPath, identifier);
982
- if (state.abandonedPullRequests?.has(sourceKey)) {
983
- return { status: "unavailable" };
984
- }
985
- const previousResultId = state.pullResultIds.get(sourceKey);
986
- const generation = pullGenerationFor(state, normalizedPath);
987
- const requestSequence = claimPullRequestSequence(state, sourceKey);
988
- const requestStartedAt = Date.now();
989
- const effectiveTimeoutMs = Math.max(1, Math.min(PULL_REQUEST_TIMEOUT_MS, budgetMs));
990
- const pullAbort = new AbortController;
991
- const pullSettlement = { cancelled: false };
992
- const requestPromise = safeSendRequest(state.connection, "textDocument/diagnostic", {
993
- textDocument: { uri },
994
- ...identifier !== undefined && { identifier },
995
- ...previousResultId !== undefined && { previousResultId }
996
- }, pullAbort.signal, pullSettlement);
997
- try {
998
- const report = await withTimeout(requestPromise, effectiveTimeoutMs);
999
- if (!report) {
1000
- recordPullFailure(state, "textDocument/diagnostic", new Error("empty response"));
1001
- return { status: "unavailable" };
1002
- }
1003
- const now = Date.now();
1004
- const sentHash = state.documentContentHashes.get(normalizedPath)?.hash;
1005
- if (pullGenerationFor(state, normalizedPath) !== generation || !isNewestPullRequest(state, sourceKey, requestSequence)) {
1006
- return { status: "unavailable" };
1007
- }
1008
- let primaryCount;
1009
- if (report.kind === "unchanged") {
1010
- primaryCount = pullSourceDiagnostics(state, normalizedPath, identifier).length;
1011
- state.documentPullDiagnosticTimestamps.set(normalizedPath, now);
1012
- } else {
1013
- const primaryItems = normalizeLspDiagnostics(report.items ?? []);
1014
- storePullSourceDiagnostics(state, normalizedPath, identifier, primaryItems);
1015
- state.documentPullDiagnosticTimestamps.set(normalizedPath, now);
1016
- bumpDiagnosticsVersion(state, normalizedPath);
1017
- state.diagnosticBindings.set(normalizedPath, { contentHash: sentHash });
1018
- primaryCount = primaryItems.length;
1019
- }
1020
- let totalCount = primaryCount;
1021
- if (report.resultId !== undefined) {
1022
- state.pullResultIds.set(sourceKey, report.resultId);
1023
- } else {
1024
- state.pullResultIds.delete(sourceKey);
1025
- }
1026
- if (report.relatedDocuments) {
1027
- for (const [relatedUri, related] of Object.entries(report.relatedDocuments)) {
1028
- const relatedPath = uriToPath(relatedUri);
1029
- const relatedNormalized = normalizeMapKey(relatedPath);
1030
- if (related?.kind === "unchanged") {
1031
- totalCount += pullSourceDiagnostics(state, relatedNormalized, identifier).length;
1032
- state.documentPullDiagnosticTimestamps.set(relatedNormalized, now);
1033
- } else {
1034
- const relatedItems = normalizeLspDiagnostics(related?.items ?? []);
1035
- storePullSourceDiagnostics(state, relatedNormalized, identifier, relatedItems);
1036
- state.documentPullDiagnosticTimestamps.set(relatedNormalized, now);
1037
- state.diagnosticBindings.delete(relatedNormalized);
1038
- totalCount += relatedItems.length;
1039
- }
1040
- if (related?.resultId !== undefined) {
1041
- state.pullResultIds.set(pullSourceKey(relatedNormalized, identifier), related.resultId);
1042
- }
1043
- }
1044
- }
1045
- state.diagnosticEmitter.emit("diagnostics", normalizedPath);
1046
- return totalCount > 0 ? { status: "found", count: totalCount, primaryCount } : { status: "clean" };
1047
- } catch (err) {
1048
- if (isPullTimeoutError(err, effectiveTimeoutMs)) {
1049
- trackAbandonedPullRequest(state, sourceKey, requestPromise);
1050
- pullAbort.abort();
1051
- recordPullTimeoutTelemetry({
1052
- scope: normalizedPath,
1053
- identifier,
1054
- effectiveBudgetMs: effectiveTimeoutMs,
1055
- hadPreviousResultId: previousResultId !== undefined,
1056
- elapsedMs: Date.now() - requestStartedAt,
1057
- server: state.serverId
1058
- });
1059
- armLateAnswerTelemetry({
1060
- requestPromise,
1061
- scope: normalizedPath,
1062
- identifier,
1063
- subject: sourceKey,
1064
- requestStartedAt,
1065
- server: state.serverId,
1066
- settlement: pullSettlement
1067
- });
1068
- }
1069
- recordPullFailure(state, "textDocument/diagnostic", err);
1070
- return { status: "unavailable" };
1071
- }
1072
- }
1073
- function trackAbandonedPullRequest(state, sourceKey, requestPromise) {
1074
- if (!state.abandonedPullRequests)
1075
- state.abandonedPullRequests = new Map;
1076
- state.abandonedPullRequests.set(sourceKey, requestPromise);
1077
- const release = () => {
1078
- if (state.abandonedPullRequests?.get(sourceKey) === requestPromise) {
1079
- state.abandonedPullRequests.delete(sourceKey);
1080
- }
1081
- };
1082
- requestPromise.then(release, release);
1083
- }
1084
- function isPullTimeoutError(err, timeoutMs) {
1085
- return err instanceof Error && err.message === `Timeout after ${timeoutMs}ms`;
1086
- }
1087
- function recordPullTimeoutTelemetry(args) {
1088
- emitBounded("lsp_pull_diagnostic_timeout", `${args.server}::${args.scope}::${args.identifier ?? "bare"}`, {
1089
- type: "phase",
1090
- filePath: args.scope,
1091
- durationMs: args.elapsedMs,
1092
- metadata: {
1093
- identifier: args.identifier ?? "bare",
1094
- effectiveBudgetMs: args.effectiveBudgetMs,
1095
- hadPreviousResultId: args.hadPreviousResultId,
1096
- server: args.server
1097
- }
1098
- }, {
1099
- ledgerKind: "lsp-pull-diagnostic-timeout",
1100
- reason: `pull timeout on ${args.server} after ${args.elapsedMs}ms (budget ${args.effectiveBudgetMs}ms)`
1101
- });
1102
- }
1103
- function armLateAnswerTelemetry(args) {
1104
- args.requestPromise.then(() => {
1105
- if (args.settlement.cancelled)
1106
- return;
1107
- try {
1108
- const elapsedMs = Date.now() - args.requestStartedAt;
1109
- emitBounded("lsp_pull_late_answer_discarded", args.subject, {
1110
- type: "phase",
1111
- filePath: args.scope,
1112
- durationMs: elapsedMs,
1113
- metadata: { identifier: args.identifier ?? "bare" }
1114
- }, {
1115
- ledgerKind: "lsp-pull-late-answer",
1116
- reason: `late pull answer discarded after ${elapsedMs}ms`
1117
- });
1118
- } catch {}
1119
- }, (err) => {
1120
- try {
1121
- const elapsedMs = Date.now() - args.requestStartedAt;
1122
- const candidate = err;
1123
- const code = typeof candidate?.code === "number" || typeof candidate?.code === "string" ? candidate.code : undefined;
1124
- emitBounded("lsp_pull_late_rejection", `${args.server}::${args.subject}`, {
1125
- type: "phase",
1126
- filePath: args.scope,
1127
- durationMs: elapsedMs,
1128
- metadata: {
1129
- identifier: args.identifier ?? "bare",
1130
- server: args.server,
1131
- ...code !== undefined && { code }
1132
- }
1133
- }, {
1134
- ledgerKind: "lsp-pull-late-rejection",
1135
- reason: `late pull rejection ${elapsedMs}ms after timeout${code !== undefined ? ` (code ${code})` : ""}`
1136
- });
1137
- } catch {}
1138
- });
1139
- }
1140
- const PULL_FAILURE_HISTORY_LIMIT = 10;
1141
- function recordPullFailure(state, method, error) {
1142
- const candidate = error;
1143
- const message = typeof candidate.message === "string" ? candidate.message : "";
1144
- const unsupportedMessage = /^(?:method not found|unknown method|unsupported method)(?::|$)/i;
1145
- if (candidate.code === -32601 || candidate.code === "-32601" || unsupportedMessage.test(message.trim()))
1146
- return;
1147
- state.pullFailureHistory.push({
1148
- timestamp: Date.now(),
1149
- method,
1150
- ...typeof candidate.code === "number" || typeof candidate.code === "string" ? { code: candidate.code } : {},
1151
- message: typeof candidate.message === "string" ? candidate.message : String(error)
1152
- });
1153
- if (state.pullFailureHistory.length > PULL_FAILURE_HISTORY_LIMIT) {
1154
- state.pullFailureHistory.splice(0, state.pullFailureHistory.length - PULL_FAILURE_HISTORY_LIMIT);
1155
- }
1156
- }
1157
- export async function clientRequestWorkspaceDiagnostics(state, budgetMs) {
1158
- if (!isClientAlive(state))
1159
- return;
1160
- if (!state.workspaceDiagnosticsSupport.workspaceDiagnostics)
1161
- return;
1162
- if (state.abandonedPullRequests?.has(WORKSPACE_PULL_SCOPE))
1163
- return;
1164
- const previousResultIds = Array.from(state.workspacePullResultCache.values()).map((entry) => ({ uri: entry.uri, value: entry.resultId }));
1165
- if (budgetMs < PULL_MIN_USABLE_BUDGET_MS) {
1166
- emitBounded("lsp_pull_skipped_budget_exhausted", `${state.serverId}::${WORKSPACE_PULL_SCOPE}`, {
1167
- type: "phase",
1168
- filePath: WORKSPACE_PULL_SCOPE,
1169
- durationMs: 0,
1170
- metadata: {
1171
- identifier: "bare",
1172
- remainingBudgetMs: budgetMs,
1173
- server: state.serverId
1174
- }
1175
- }, {
1176
- ledgerKind: "lsp-pull-skipped-budget-exhausted",
1177
- reason: `workspace pull skipped on ${state.serverId}: budget already exhausted (${budgetMs}ms remaining)`
1178
- });
1179
- return;
1180
- }
1181
- const workspacePullStartedAt = Date.now();
1182
- const workspacePullTimeoutMs = Math.max(1, budgetMs);
1183
- const workspacePullAbort = new AbortController;
1184
- const workspacePullSettlement = { cancelled: false };
1185
- const workspaceRequestPromise = safeSendRequest(state.connection, "workspace/diagnostic", { previousResultIds }, workspacePullAbort.signal, workspacePullSettlement);
1186
- try {
1187
- const report = await withTimeout(workspaceRequestPromise, workspacePullTimeoutMs);
1188
- if (!report || !Array.isArray(report.items))
1189
- return;
1190
- const out = [];
1191
- const fallbackPullDeadline = Date.now() + Math.max(1, budgetMs);
1192
- for (const item of report.items) {
1193
- if (!item?.uri)
1194
- continue;
1195
- const filePath = uriToPath(item.uri);
1196
- const normalizedPath = normalizeMapKey(filePath);
1197
- if (item.kind === "unchanged") {
1198
- const prior = state.workspacePullResultCache.get(normalizedPath);
1199
- if (!prior) {
1200
- const remainingMs = fallbackPullDeadline - Date.now();
1201
- if (remainingMs <= 0) {
1202
- incrementDegradationCount({
1203
- kind: "lsp-pull-unconfirmed",
1204
- subject: state.serverId,
1205
- reason: "unchanged report with no workspacePullResultCache basis; the shared fallback-pull deadline was already exhausted by earlier files this sweep"
1206
- });
1207
- continue;
1208
- }
1209
- const outcome = await clientRequestPullDiagnostics(state, filePath, remainingMs);
1210
- if (outcome.status === "found") {
1211
- out.push({
1212
- filePath,
1213
- diagnostics: state.documentPullDiagnostics.get(normalizedPath) ?? [],
1214
- contentHash: state.diagnosticBindings.get(normalizedPath)?.contentHash
1215
- });
1216
- } else if (outcome.status === "unavailable") {
1217
- incrementDegradationCount({
1218
- kind: "lsp-pull-unconfirmed",
1219
- subject: state.serverId,
1220
- reason: "unchanged report with no workspacePullResultCache basis, and the per-file fallback pull was unavailable"
1221
- });
1222
- }
1223
- continue;
1224
- }
1225
- if (item.resultId !== undefined) {
1226
- state.workspacePullResultCache.set(normalizedPath, {
1227
- ...prior,
1228
- resultId: item.resultId
1229
- });
1230
- }
1231
- out.push({
1232
- filePath,
1233
- diagnostics: prior.diagnostics,
1234
- contentHash: prior.contentHash
1235
- });
1236
- continue;
1237
- }
1238
- const diagnostics = normalizeLspDiagnostics(item.items ?? []);
1239
- let contentHash;
1240
- try {
1241
- contentHash = hashDiagnosticContent(await readFile(filePath, "utf-8"));
1242
- } catch {
1243
- contentHash = undefined;
1244
- }
1245
- if (item.resultId !== undefined) {
1246
- if (state.workspacePullResultCache.size >= WORKSPACE_PULL_RESULT_CACHE_MAX) {
1247
- state.workspacePullResultCache.clear();
1248
- }
1249
- state.workspacePullResultCache.set(normalizedPath, {
1250
- uri: item.uri,
1251
- resultId: item.resultId,
1252
- diagnostics,
1253
- contentHash
1254
- });
1255
- } else {
1256
- state.workspacePullResultCache.delete(normalizedPath);
1257
- }
1258
- out.push({ filePath, diagnostics, contentHash });
1259
- }
1260
- return out;
1261
- } catch (err) {
1262
- if (isPullTimeoutError(err, workspacePullTimeoutMs)) {
1263
- trackAbandonedPullRequest(state, WORKSPACE_PULL_SCOPE, workspaceRequestPromise);
1264
- workspacePullAbort.abort();
1265
- recordPullTimeoutTelemetry({
1266
- scope: WORKSPACE_PULL_SCOPE,
1267
- identifier: undefined,
1268
- effectiveBudgetMs: workspacePullTimeoutMs,
1269
- hadPreviousResultId: previousResultIds.length > 0,
1270
- elapsedMs: Date.now() - workspacePullStartedAt,
1271
- server: state.serverId
1272
- });
1273
- armLateAnswerTelemetry({
1274
- requestPromise: workspaceRequestPromise,
1275
- scope: WORKSPACE_PULL_SCOPE,
1276
- identifier: undefined,
1277
- subject: WORKSPACE_PULL_SCOPE,
1278
- requestStartedAt: workspacePullStartedAt,
1279
- server: state.serverId,
1280
- settlement: workspacePullSettlement
1281
- });
1282
- }
1283
- recordPullFailure(state, "workspace/diagnostic", err);
1284
- return;
1285
- }
1286
- }
1287
- export async function clientWaitForDiagnostics(state, filePath, timeoutMs, options = {}) {
1288
- const normalizedPath = normalizeMapKey(filePath);
1289
- const minVersion = options.minVersion;
1290
- const pullSettleSource = options.pullSettleSource ?? "pull";
1291
- const hasFreshDiagnostics = () => minVersion === undefined || diagnosticsVersionForPath(state, normalizedPath) > minVersion;
1292
- const isVersionStale = () => {
1293
- const cachedVersion = state.diagnosticDocVersions?.get(normalizedPath);
1294
- if (cachedVersion === undefined)
1295
- return false;
1296
- const currentVersion = state.documentVersions?.get(normalizedPath);
1297
- return currentVersion !== undefined && cachedVersion < currentVersion;
1298
- };
1299
- if (state.workspaceDiagnosticsSupport.mode === "pull") {
1300
- const pullSettleStartedAt = Date.now();
1301
- let outcome = await clientRequestPullDiagnostics(state, filePath, timeoutMs);
1302
- if (outcome.status === "found") {
1303
- logTypeScriptPullSettle(state, normalizedPath, Date.now() - pullSettleStartedAt, pullSettleSource);
1304
- return;
1305
- }
1306
- let sawClean = outcome.status === "clean";
1307
- const strategy = getStrategy(state.serverId, state.launchVariant);
1308
- const retryBudgetMs = strategy.pullRetryBudgetMs > 0 ? Math.min(timeoutMs, strategy.pullRetryBudgetMs) : 0;
1309
- const startedAt = Date.now();
1310
- while (outcome.status !== "found" && Date.now() - startedAt < retryBudgetMs) {
1311
- await new Promise((resolve) => setTimeout(resolve, PULL_DIAGNOSTICS_RETRY_INTERVAL_MS));
1312
- outcome = await clientRequestPullDiagnostics(state, filePath, Math.max(0, retryBudgetMs - (Date.now() - startedAt)));
1313
- if (outcome.status === "clean")
1314
- sawClean = true;
1315
- }
1316
- if (options.pullOnly) {
1317
- if (outcome.status === "found" || sawClean) {
1318
- logTypeScriptPullSettle(state, normalizedPath, Date.now() - pullSettleStartedAt, pullSettleSource);
1319
- }
1320
- return;
1321
- }
1322
- if (outcome.status === "found" || sawClean) {
1323
- logTypeScriptPullSettle(state, normalizedPath, Date.now() - pullSettleStartedAt, pullSettleSource);
1324
- return;
1325
- }
1326
- }
1327
- if (hasFreshDiagnostics() && !isVersionStale() && getMergedDiagnosticsForPath(state, normalizedPath).length > 0) {
1328
- return;
1329
- }
1330
- return new Promise((resolve) => {
1331
- let debounceTimer;
1332
- const onDiagnostics = (fp) => {
1333
- if (normalizeMapKey(fp) !== normalizedPath)
1334
- return;
1335
- if (!hasFreshDiagnostics() || isVersionStale())
1336
- return;
1337
- if (debounceTimer)
1338
- clearTimeout(debounceTimer);
1339
- const strategy = getStrategy(state.serverId, state.launchVariant);
1340
- const hit = state.pushDiagnosticTimestamps.get(normalizedPath);
1341
- const timeSincePush = hit ? Date.now() - hit : 1 / 0;
1342
- const remaining = Math.max(0, strategy.debounceMs - timeSincePush);
1343
- debounceTimer = setTimeout(() => {
1344
- state.diagnosticEmitter.off("diagnostics", onDiagnostics);
1345
- clearTimeout(timeout);
1346
- resolve();
1347
- }, remaining);
1348
- };
1349
- state.diagnosticEmitter.on("diagnostics", onDiagnostics);
1350
- const timeout = setTimeout(() => {
1351
- if (debounceTimer)
1352
- clearTimeout(debounceTimer);
1353
- state.diagnosticEmitter.off("diagnostics", onDiagnostics);
1354
- resolve();
1355
- }, timeoutMs);
1356
- });
1357
- }
1358
- export function handleNotifyExternalChange(state, filePath, type) {
1359
- if (!isClientAlive(state))
1360
- return;
1361
- const normalizedPath = normalizeMapKey(filePath);
1362
- const uri = state.openDocumentUris?.get(normalizedPath) ?? pathToFileURL(filePath).href;
1363
- state.watchQueue.enqueue(uri, type);
1364
- }
1365
- async function sendDidSave(state, uri, content) {
1366
- const save = state.saveOptions;
1367
- if (!save)
1368
- return;
1369
- if (!isClientAlive(state))
1370
- return;
1371
- const limit = save.includeText ? exceedsLspSyncLimits(content) : { tooLarge: false, reason: "" };
1372
- if (limit.tooLarge) {
1373
- recordDegradationOnce({
1374
- kind: "lsp-did-save-text-omitted",
1375
- subject: state.serverId,
1376
- reason: limit.reason
1377
- });
1378
- }
1379
- await safeSendNotification(state.connection, "textDocument/didSave", {
1380
- textDocument: { uri },
1381
- ...save.includeText && !limit.tooLarge ? { text: content } : {}
1382
- });
1383
- }
1384
- async function handleNotifyOpenOnce(state, filePath, content, languageId, preserveDiagnostics = false, silent = false, coalescedCount = 0, saved = false) {
1385
- if (!isClientAlive(state))
1386
- return;
1387
- const normalizedPath = normalizeMapKey(filePath);
1388
- const uri = state.openDocumentUris?.get(normalizedPath) ?? pathToFileURL(filePath).href;
1389
- if (state.openDocuments.has(normalizedPath) || state.pendingOpens.has(normalizedPath)) {
1390
- const version = (state.documentVersions.get(normalizedPath) ?? 0) + 1;
1391
- state.documentVersions.set(normalizedPath, version);
1392
- if (!preserveDiagnostics) {
1393
- clearDiagnosticsForPath(state, normalizedPath);
1394
- }
1395
- if (getStrategy(state.serverId, state.launchVariant).reopenOnResync) {
1396
- await safeSendNotification(state.connection, "textDocument/didClose", {
1397
- textDocument: { uri }
1398
- });
1399
- state.openDocuments.delete(normalizedPath);
1400
- state.openDocumentUris?.delete(normalizedPath);
1401
- state.documentVersions.set(normalizedPath, version);
1402
- state.documentOpenedAt.set(normalizedPath, Date.now());
1403
- state.diagnosticPublicationCounts.set(normalizedPath, 0);
1404
- if (!isClientAlive(state))
1405
- return;
1406
- const reopenSent = await safeSendNotification(state.connection, "textDocument/didOpen", { textDocument: { uri, languageId, version, text: content } });
1407
- if (reopenSent)
1408
- recordSentContent(state, normalizedPath, version, content, coalescedCount);
1409
- state.openDocuments.add(normalizedPath);
1410
- state.openDocumentUris?.set(normalizedPath, uri);
1411
- if (saved && reopenSent)
1412
- await sendDidSave(state, uri, content);
1413
- return;
1414
- }
1415
- const changeSent = await safeSendNotification(state.connection, "textDocument/didChange", {
1416
- textDocument: { uri, version },
1417
- contentChanges: buildContentChanges(state, normalizedPath, content)
1418
- });
1419
- if (changeSent)
1420
- recordSentContent(state, normalizedPath, version, content, coalescedCount);
1421
- if (saved && changeSent)
1422
- await sendDidSave(state, uri, content);
1423
- return;
1424
- }
1425
- state.pendingOpens.add(normalizedPath);
1426
- state.documentVersions.set(normalizedPath, 0);
1427
- state.documentOpenedAt.set(normalizedPath, Date.now());
1428
- state.diagnosticPublicationCounts.set(normalizedPath, 0);
1429
- clearDiagnosticsForPath(state, normalizedPath);
1430
- if (!silent) {
1431
- let fileExists = true;
1432
- try {
1433
- await access(filePath);
1434
- } catch {
1435
- fileExists = false;
1436
- }
1437
- state.watchQueue.enqueue(uri, fileExists ? 2 : 1);
1438
- }
1439
- if (!isClientAlive(state))
1440
- return;
1441
- const openSent = await safeSendNotification(state.connection, "textDocument/didOpen", { textDocument: { uri, languageId, version: 0, text: content } });
1442
- if (openSent)
1443
- recordSentContent(state, normalizedPath, 0, content, coalescedCount);
1444
- state.pendingOpens.delete(normalizedPath);
1445
- state.openDocuments.add(normalizedPath);
1446
- state.closedDocuments?.delete(normalizedPath);
1447
- state.openDocumentUris?.set(normalizedPath, uri);
1448
- if (saved && openSent)
1449
- await sendDidSave(state, uri, content);
1450
- probeTsserverProjectIdentity({
1451
- serverId: state.serverId,
1452
- launchVariant: state.launchVariant,
1453
- clientRoot: state.root,
1454
- file: filePath,
1455
- normalizedFile: normalizedPath,
1456
- probedFiles: state.projectIdentityProbedFiles ?? (state.projectIdentityProbedFiles = new Set),
1457
- commandChannel: {
1458
- executeCommand: (command, args) => runReadOnlyServerCommand(state, command, args)
1459
- }
1460
- });
1461
- }
1462
- function enqueueDocumentNotify(state, normalizedPath, run, saved = false) {
1463
- let queue = state.notifyChangeQueues.get(normalizedPath);
1464
- if (!queue) {
1465
- queue = { running: false };
1466
- state.notifyChangeQueues.set(normalizedPath, queue);
1467
- }
1468
- return new Promise((resolve, reject) => {
1469
- const previous = queue?.pending;
1470
- const waiters = previous?.waiters ?? [];
1471
- waiters.push({ resolve, reject });
1472
- queue.pending = {
1473
- run,
1474
- waiters,
1475
- coalescedCount: (previous?.coalescedCount ?? 0) + (previous ? 1 : 0),
1476
- saved: saved || previous?.saved === true
1477
- };
1478
- if (queue.running)
1479
- return;
1480
- queue.running = true;
1481
- Promise.resolve().then(async () => {
1482
- try {
1483
- for (;; ) {
1484
- const next = queue.pending;
1485
- if (!next)
1486
- break;
1487
- queue.pending = undefined;
1488
- try {
1489
- await next.run(next.coalescedCount, next.saved);
1490
- for (const waiter of next.waiters)
1491
- waiter.resolve();
1492
- } catch (error) {
1493
- for (const waiter of next.waiters)
1494
- waiter.reject(error);
1495
- }
1496
- }
1497
- } finally {
1498
- queue.running = false;
1499
- if (!queue.pending && state.notifyChangeQueues.get(normalizedPath) === queue) {
1500
- state.notifyChangeQueues.delete(normalizedPath);
1501
- }
1502
- }
1503
- });
1504
- });
1505
- }
1506
- function cancelDocumentNotifyQueues(state) {
1507
- for (const queue of state.notifyChangeQueues.values()) {
1508
- for (const waiter of queue.pending?.waiters ?? [])
1509
- waiter.resolve();
1510
- queue.pending = undefined;
1511
- }
1512
- state.notifyChangeQueues.clear();
1513
- }
1514
- export function handleNotifyOpen(state, filePath, content, languageId, preserveDiagnostics = false, silent = false, saved = false) {
1515
- if (!isClientAlive(state))
1516
- return Promise.resolve();
1517
- const normalizedPath = normalizeMapKey(filePath);
1518
- return enqueueDocumentNotify(state, normalizedPath, (coalescedCount, queuedSaved) => handleNotifyOpenOnce(state, filePath, content, languageId, preserveDiagnostics, silent, coalescedCount, queuedSaved), saved);
1519
- }
1520
- async function handleNotifyChangeOnce(state, filePath, content, normalizedPath, coalescedCount = 0) {
1521
- if (!isClientAlive(state))
1522
- return;
1523
- const uri = state.openDocumentUris?.get(normalizedPath) ?? pathToFileURL(filePath).href;
1524
- if (!state.openDocuments.has(normalizedPath)) {
1525
- const fallbackOpenSent = await safeSendNotification(state.connection, "textDocument/didOpen", {
1526
- textDocument: {
1527
- uri,
1528
- languageId: "plaintext",
1529
- version: 0,
1530
- text: content
1531
- }
1532
- });
1533
- state.documentVersions.set(normalizedPath, 0);
1534
- state.documentOpenedAt.set(normalizedPath, Date.now());
1535
- state.diagnosticPublicationCounts.set(normalizedPath, 0);
1536
- if (fallbackOpenSent)
1537
- recordSentContent(state, normalizedPath, 0, content, coalescedCount);
1538
- state.openDocuments.add(normalizedPath);
1539
- state.openDocumentUris?.set(normalizedPath, uri);
1540
- return;
1541
- }
1542
- const version = (state.documentVersions.get(normalizedPath) ?? 0) + 1;
1543
- state.documentVersions.set(normalizedPath, version);
1544
- clearDiagnosticsForPath(state, normalizedPath);
1545
- const changeSent = await safeSendNotification(state.connection, "textDocument/didChange", {
1546
- textDocument: { uri, version },
1547
- contentChanges: buildContentChanges(state, normalizedPath, content)
1548
- });
1549
- if (changeSent)
1550
- recordSentContent(state, normalizedPath, version, content, coalescedCount);
1551
- }
1552
- export function handleNotifyChange(state, filePath, content) {
1553
- if (!isClientAlive(state))
1554
- return Promise.resolve();
1555
- const normalizedPath = normalizeMapKey(filePath);
1556
- return enqueueDocumentNotify(state, normalizedPath, (coalescedCount) => handleNotifyChangeOnce(state, filePath, content, normalizedPath, coalescedCount));
1557
- }
1558
- export async function closeDocument(state, filePath) {
1559
- if (!isClientAlive(state))
1560
- return;
1561
- const normalizedPath = normalizeMapKey(filePath);
1562
- if (!state.openDocuments.has(normalizedPath))
1563
- return;
1564
- await safeSendNotification(state.connection, "textDocument/didClose", {
1565
- textDocument: {
1566
- uri: state.openDocumentUris?.get(normalizedPath) ?? pathToFileURL(filePath).href
1567
- }
1568
- });
1569
- state.openDocuments.delete(normalizedPath);
1570
- state.closedDocuments?.add(normalizedPath);
1571
- state.openDocumentUris?.delete(normalizedPath);
1572
- state.documentVersions.delete(normalizedPath);
1573
- state.documentOpenedAt.delete(normalizedPath);
1574
- state.diagnosticPublicationCounts.delete(normalizedPath);
1575
- state.projectIdentityProbedFiles?.delete(normalizedPath);
1576
- const retained = state.documentContentHashes.get(normalizedPath);
1577
- if (retained?.text !== undefined) {
1578
- state.incrementalTextRetainedEntries = Math.max(0, (state.incrementalTextRetainedEntries ?? 1) - 1);
1579
- state.incrementalTextRetainedBytes = Math.max(0, (state.incrementalTextRetainedBytes ?? retained.text.length * 2) - retained.text.length * 2);
1580
- state.incrementalTextBearingPaths?.delete(normalizedPath);
1581
- }
1582
- state.documentContentHashes.delete(normalizedPath);
1583
- clearDiagnosticsForPath(state, normalizedPath);
1584
- }
1585
- function isAtLeastAsAggressiveShutdown(existing, requested) {
1586
- return !!existing.fast >= !!requested.fast && !!existing.processExiting >= !!requested.processExiting;
1587
- }
1588
- export function clientShutdown(state, options = {}) {
1589
- if (state.shutdownPromise && state.shutdownOptions && isAtLeastAsAggressiveShutdown(state.shutdownOptions, options)) {
1590
- return state.shutdownPromise;
1591
- }
1592
- state.shutdownOptions = options;
1593
- const attempt = clientShutdownOnce(state, options);
1594
- state.shutdownPromise = attempt;
1595
- attempt.catch(() => {
1596
- if (state.shutdownPromise === attempt) {
1597
- state.shutdownPromise = undefined;
1598
- state.shutdownOptions = undefined;
1599
- }
1600
- });
1601
- return attempt;
1602
- }
1603
- async function clientShutdownOnce(state, options) {
1604
- const shutdownStart = Date.now();
1605
- state.shutdownRequested = true;
1606
- state.isConnected = false;
1607
- state.isDestroyed = true;
1608
- for (const timer of state.pendingDiagnostics.values()) {
1609
- clearTimeout(timer);
1610
- }
1611
- state.pendingDiagnostics.clear();
1612
- state.pendingOpens.clear();
1613
- state.openDocuments.clear();
1614
- state.openDocumentUris?.clear();
1615
- cancelDocumentNotifyQueues(state);
1616
- state.projectIdentityProbedFiles?.clear();
1617
- state.watchQueue?.cancel();
1618
- state.diagnosticEmitter.removeAllListeners();
1619
- let shutdownRequestTimedOut = false;
1620
- let exitNotifyTimedOut = false;
1621
- let shutdownRequestUndelivered = false;
1622
- let exitNotifyUndelivered = false;
1623
- try {
1624
- if (!options.fast) {
1625
- try {
1626
- const shutdownAck = await withTimeout(safeSendRequest(state.connection, "shutdown", {}), SHUTDOWN_REQUEST_TIMEOUT_MS);
1627
- if (shutdownAck === undefined)
1628
- shutdownRequestUndelivered = true;
1629
- } catch (err) {
1630
- if (isShutdownTimeoutError(err, SHUTDOWN_REQUEST_TIMEOUT_MS)) {
1631
- shutdownRequestTimedOut = true;
1632
- } else {
1633
- shutdownRequestUndelivered = true;
1634
- }
1635
- }
1636
- try {
1637
- const exitSent = await withTimeout(safeSendNotification(state.connection, "exit", {}), EXIT_NOTIFY_TIMEOUT_MS);
1638
- if (exitSent === false)
1639
- exitNotifyUndelivered = true;
1640
- } catch (err) {
1641
- if (isShutdownTimeoutError(err, EXIT_NOTIFY_TIMEOUT_MS)) {
1642
- exitNotifyTimedOut = true;
1643
- } else {
1644
- exitNotifyUndelivered = true;
1645
- }
1646
- }
1647
- }
1648
- } finally {
1649
- disposeClientConnection(state);
1650
- const pid = state.lspProcess.pid;
1651
- logLatency({
1652
- type: "phase",
1653
- phase: "lsp_client_shutdown",
1654
- filePath: state.root,
1655
- durationMs: Date.now() - shutdownStart,
1656
- metadata: {
1657
- serverId: state.serverId,
1658
- pid,
1659
- fast: !!options.fast,
1660
- processExiting: !!options.processExiting,
1661
- shutdownRequestTimedOut,
1662
- exitNotifyTimedOut,
1663
- shutdownRequestUndelivered,
1664
- exitNotifyUndelivered,
1665
- shutdownOutcome: options.fast ? "fast" : shutdownRequestTimedOut || exitNotifyTimedOut || shutdownRequestUndelivered || exitNotifyUndelivered ? "forced" : "graceful"
1666
- }
1667
- });
1668
- removeLspChild(pid, extractSpawnMarker(state.lspProcess.args)).catch((err) => {
1669
- logLatency({
1670
- type: "phase",
1671
- phase: "lsp_registry_write_failed",
1672
- filePath: "",
1673
- durationMs: 0,
1674
- metadata: { op: "remove", pid, error: String(err) }
1675
- });
1676
- });
1677
- await killProcessTree(state.lspProcess.process, pid, options);
1678
- }
1679
- }
1680
- async function toWirePosition(state, filePath, line, character) {
1681
- if (state.positionEncoding === "utf-16")
1682
- return { line, character };
1683
- try {
1684
- const content = await readFile(filePath, "utf8");
1685
- return {
1686
- line,
1687
- character: convertCharacterOffset(state.positionEncoding, lineTextAt(content, line), character)
1688
- };
1689
- } catch {
1690
- return { line, character };
1691
- }
1692
- }
1693
- function navStaleDropEnabled() {
1694
- return process.env.DM_LENS_LSP_NAV_STALE_DROP !== "0";
1695
- }
1696
- export async function navRequest(state, method, params, staleCheckPath, timeoutMs = NAV_REQUEST_TIMEOUT_MS, signal = getAmbientAbortSignal()) {
1697
- if (!isClientAlive(state))
1698
- return null;
1699
- const normalizedPath = staleCheckPath !== undefined ? normalizeMapKey(staleCheckPath) : undefined;
1700
- const requestVersion = normalizedPath !== undefined ? state.documentVersions.get(normalizedPath) : undefined;
1701
- const requestStartedAt = Date.now();
1702
- const requestPromise = safeSendRequest(state.connection, method, params, signal);
1703
- const result = await withTimeout(requestPromise, timeoutMs).catch((err) => {
1704
- if (isNavTimeoutError(err, timeoutMs)) {
1705
- recordNavTimeoutTelemetry({
1706
- method,
1707
- scope: normalizedPath,
1708
- budgetMs: timeoutMs,
1709
- elapsedMs: Date.now() - requestStartedAt
1710
- });
1711
- armNavLateAnswerTelemetry({
1712
- requestPromise,
1713
- method,
1714
- scope: normalizedPath,
1715
- requestStartedAt
1716
- });
1717
- return;
1718
- }
1719
- if (err instanceof Error && err.message.startsWith("Timeout after")) {
1720
- return;
1721
- }
1722
- throw err;
1723
- });
1724
- if (normalizedPath !== undefined && requestVersion !== undefined && navStaleDropEnabled()) {
1725
- const currentVersion = state.documentVersions.get(normalizedPath);
1726
- if (currentVersion !== undefined && currentVersion > requestVersion) {
1727
- return;
1728
- }
1729
- }
1730
- return result;
1731
- }
1732
- function isNavTimeoutError(err, timeoutMs) {
1733
- return err instanceof Error && err.message === `Timeout after ${timeoutMs}ms`;
1734
- }
1735
- function isShutdownTimeoutError(err, timeoutMs) {
1736
- return err instanceof Error && err.message === `Timeout after ${timeoutMs}ms`;
1737
- }
1738
- const NAV_REQUEST_NO_PATH_SCOPE = "*no-path*";
1739
- function recordNavTimeoutTelemetry(args) {
1740
- emitBounded("lsp_nav_request_timeout", `${args.method}:${args.scope ?? NAV_REQUEST_NO_PATH_SCOPE}`, {
1741
- type: "phase",
1742
- filePath: args.scope ?? NAV_REQUEST_NO_PATH_SCOPE,
1743
- durationMs: args.elapsedMs,
1744
- metadata: { method: args.method, effectiveBudgetMs: args.budgetMs }
1745
- }, {
1746
- ledgerKind: "lsp-nav-request-timeout",
1747
- risingEdgePer: "identity",
1748
- reason: `timeout budget=${args.budgetMs}ms elapsed=${args.elapsedMs}ms`
1749
- });
1750
- }
1751
- function armNavLateAnswerTelemetry(args) {
1752
- args.requestPromise.then(() => {
1753
- try {
1754
- const elapsedMs = Date.now() - args.requestStartedAt;
1755
- emitBounded("lsp_nav_late_answer_discarded", `${args.method}:${args.scope ?? NAV_REQUEST_NO_PATH_SCOPE}`, {
1756
- type: "phase",
1757
- filePath: args.scope ?? NAV_REQUEST_NO_PATH_SCOPE,
1758
- durationMs: elapsedMs,
1759
- metadata: { method: args.method }
1760
- }, {
1761
- ledgerKind: "lsp-nav-late-answer",
1762
- risingEdgePer: "identity",
1763
- reason: `late nav answer discarded after ${elapsedMs}ms`
1764
- });
1765
- } catch {}
1766
- }, () => {});
1767
- }
1768
- function chooseLivenessProbe(state) {
1769
- if (state.operationSupport?.workspaceSymbol === true) {
1770
- return {
1771
- method: "workspace/symbol",
1772
- params: { query: LIVENESS_PING_QUERY }
1773
- };
1774
- }
1775
- const openUri = firstOpenDocumentUri(state);
1776
- if (openUri === undefined)
1777
- return;
1778
- if (state.operationSupport?.documentSymbol === true) {
1779
- return {
1780
- method: "textDocument/documentSymbol",
1781
- params: { textDocument: { uri: openUri } }
1782
- };
1783
- }
1784
- if (state.operationSupport?.hover === true) {
1785
- return {
1786
- method: "textDocument/hover",
1787
- params: {
1788
- textDocument: { uri: openUri },
1789
- position: { line: 0, character: 0 }
1790
- }
1791
- };
1792
- }
1793
- return;
1794
- }
1795
- function firstOpenDocumentUri(state) {
1796
- for (const normalizedPath of state.openDocuments) {
1797
- const uri = state.openDocumentUris?.get(normalizedPath);
1798
- if (uri !== undefined)
1799
- return uri;
1800
- }
1801
- return;
1802
- }
1803
- async function clientPingLiveness(state, timeoutMs = LIVENESS_PING_TIMEOUT_MS) {
1804
- if (!isClientAlive(state))
1805
- return false;
1806
- const probe = chooseLivenessProbe(state);
1807
- if (probe === undefined) {
1808
- try {
1809
- incrementDegradationCount({
1810
- kind: "lsp-liveness-probe-unsupported",
1811
- subject: state.serverId,
1812
- reason: "no advertised request method to probe with (no " + "workspaceSymbolProvider, and no open document with " + "documentSymbolProvider or hoverProvider); liveness from " + "process and connection state only"
1813
- });
1814
- } catch {}
1815
- return isClientAlive(state);
1816
- }
1817
- try {
1818
- await withTimeout(safeSendRequest(state.connection, probe.method, probe.params), timeoutMs);
1819
- } catch (err) {
1820
- if (err instanceof Error && err.message.startsWith("Timeout after")) {
1821
- return false;
1822
- }
1823
- }
1824
- return isClientAlive(state);
1825
- }
1826
- function syncMutationContextSlot(state) {
1827
- state.activeMutationContext = state.activeMutationDepth === 1 ? state.mutationContextOwner : undefined;
1828
- }
1829
- export async function runServerCommand(state, command, args, timeoutMs = EXECUTE_COMMAND_TIMEOUT_MS, mutationContext) {
1830
- if (!isClientAlive(state)) {
1831
- return { executed: false, reason: "lsp client not alive" };
1832
- }
1833
- if (!state.advertisedCommands.has(command)) {
1834
- return {
1835
- executed: false,
1836
- reason: `command "${command}" is not advertised by the ${state.serverId} server`
1837
- };
1838
- }
1839
- state.serverEditsAllowed += 1;
1840
- state.activeMutationDepth = (state.activeMutationDepth ?? 0) + 1;
1841
- const isMutationContextOwner = state.activeMutationDepth === 1;
1842
- if (isMutationContextOwner) {
1843
- state.mutationContextOwner = mutationContext;
1844
- }
1845
- syncMutationContextSlot(state);
1846
- try {
1847
- let result;
1848
- try {
1849
- result = await withTimeout(safeSendRequest(state.connection, "workspace/executeCommand", {
1850
- command,
1851
- arguments: args ?? []
1852
- }), timeoutMs);
1853
- } catch (err) {
1854
- if (err instanceof Error && err.message.startsWith("Timeout after")) {
1855
- return {
1856
- executed: false,
1857
- reason: `workspace/executeCommand timed out after ${timeoutMs}ms — the command may still be applying server-side`
1858
- };
1859
- }
1860
- throw err;
1861
- }
1862
- return { executed: true, result };
1863
- } finally {
1864
- state.serverEditsAllowed -= 1;
1865
- state.activeMutationDepth = Math.max(0, (state.activeMutationDepth ?? 0) - 1);
1866
- if (isMutationContextOwner) {
1867
- state.mutationContextOwner = undefined;
1868
- }
1869
- syncMutationContextSlot(state);
1870
- }
1871
- }
1872
- export async function runReadOnlyServerCommand(state, command, args, timeoutMs = PROBE_COMMAND_TIMEOUT_MS) {
1873
- if (!isClientAlive(state)) {
1874
- return { executed: false, reason: "lsp client not alive" };
1875
- }
1876
- if (!state.advertisedCommands.has(command)) {
1877
- return {
1878
- executed: false,
1879
- reason: `command "${command}" is not advertised by the ${state.serverId} server`
1880
- };
1881
- }
1882
- try {
1883
- const result = await withTimeout(safeSendRequest(state.connection, "workspace/executeCommand", {
1884
- command,
1885
- arguments: args ?? []
1886
- }), timeoutMs);
1887
- return { executed: true, result };
1888
- } catch (err) {
1889
- if (err instanceof Error && err.message.startsWith("Timeout after")) {
1890
- return {
1891
- executed: false,
1892
- reason: `workspace/executeCommand timed out after ${timeoutMs}ms`
1893
- };
1894
- }
1895
- throw err;
1896
- }
1897
- }
1898
- function validateWorkspaceEditVersions(state, edit) {
1899
- for (const change of edit.documentChanges ?? []) {
1900
- if (typeof change !== "object" || change === null || !("textDocument" in change))
1901
- continue;
1902
- const textDocument = change.textDocument;
1903
- if (!textDocument || typeof textDocument.uri !== "string" || textDocument.version == null)
1904
- continue;
1905
- const current = state.documentVersions.get(normalizeMapKey(uriToPath(textDocument.uri)));
1906
- if (current === undefined || current !== textDocument.version) {
1907
- throw new Error(`stale workspace edit document version for ${textDocument.uri}`);
1908
- }
1909
- }
1910
- }
1911
- function stripDocumentVersions(edit) {
1912
- if (!Array.isArray(edit.documentChanges))
1913
- return edit;
1914
- const documentChanges = edit.documentChanges.map((change) => {
1915
- if (typeof change === "object" && change !== null && "textDocument" in change && "edits" in change) {
1916
- const textDocument = change.textDocument;
1917
- if (textDocument && typeof textDocument.version === "number") {
1918
- return {
1919
- ...change,
1920
- textDocument: { ...textDocument, version: null }
1921
- };
1922
- }
1923
- }
1924
- return change;
1925
- });
1926
- return { ...edit, documentChanges };
1927
- }
1928
- export async function normalizeClientWorkspaceEdit(state, edit) {
1929
- validateWorkspaceEditVersions(state, edit);
1930
- const normalized = await normalizeWorkspaceEditToUtf16(edit, state.positionEncoding, state.root);
1931
- return stripDocumentVersions(normalized);
1932
- }
1933
- async function resolveCodeActionBestEffort(state, action) {
1934
- if (!isClientAlive(state))
1935
- return action;
1936
- if (action.edit) {
1937
- return {
1938
- ...action,
1939
- edit: await normalizeClientWorkspaceEdit(state, action.edit)
1940
- };
1941
- }
1942
- if (!state.operationSupport.codeActionResolve) {
1943
- recordDegradationOnce({
1944
- kind: "lsp-capability-skip",
1945
- subject: `${state.serverId}:codeAction/resolve`,
1946
- reason: "server did not advertise codeActionProvider.resolveProvider"
1947
- });
1948
- return action;
1949
- }
1950
- let resolved;
1951
- try {
1952
- resolved = await withTimeout(safeSendRequest(state.connection, "codeAction/resolve", action), NAV_REQUEST_TIMEOUT_MS);
1953
- } catch {
1954
- return action;
1955
- }
1956
- if (!resolved || typeof resolved !== "object")
1957
- return action;
1958
- const merged = { ...action, ...resolved };
1959
- return merged.edit ? {
1960
- ...merged,
1961
- edit: await normalizeClientWorkspaceEdit(state, merged.edit)
1962
- } : merged;
1963
- }
1964
- export async function createLSPClient(options) {
1965
- installCrashGuard();
1966
- const { serverId, process: lspProcess, root, sessionCwd, initialization, initializeTimeoutMs = INITIALIZE_TIMEOUT_MS, launchVariant, onDiagnosticsPublished } = options;
1967
- recordLspChild({
1968
- pid: lspProcess.pid,
1969
- serverId,
1970
- command: lspProcess.command,
1971
- marker: extractSpawnMarker(lspProcess.args),
1972
- sessionIdentity: {
1973
- projectRoot: sessionCwd ?? process.cwd(),
1974
- rootSource: sessionCwd ? "service-cwd" : "lsp-fallback",
1975
- startedAt: new Date(workspaceDiagnosticsCacheSessionStart()).toISOString()
1976
- }
1977
- }).catch((err) => {
1978
- logLatency({
1979
- type: "phase",
1980
- phase: "lsp_registry_write_failed",
1981
- filePath: "",
1982
- durationMs: 0,
1983
- metadata: { op: "record", pid: lspProcess.pid, error: String(err) }
1984
- });
1985
- });
1986
- const startupState = {
1987
- exitCode: null,
1988
- exitSignal: null,
1989
- closeCode: null,
1990
- closeSignal: null,
1991
- stderr: ""
1992
- };
1993
- const stderrRing = [];
1994
- const MAX_STDERR_LINES = 100;
1995
- const onStderr = (chunk) => {
1996
- stderrRing.push(chunk.toString());
1997
- if (stderrRing.length > MAX_STDERR_LINES)
1998
- stderrRing.shift();
1999
- if (startupState.stderr.length < 4096) {
2000
- startupState.stderr += chunk.toString();
2001
- }
2002
- };
2003
- const recentStderr = (lines = 10) => stderrRing.slice(-lines).join("").trim();
2004
- const checkProcessAlive = () => {
2005
- const exited = lspProcess.process.exitCode;
2006
- if (exited !== null) {
2007
- const tail = recentStderr(20);
2008
- return `LSP server ${serverId} exited with code ${exited}${tail ? `. stderr: ${tail}` : ""}`;
2009
- }
2010
- if (lspProcess.process.killed) {
2011
- return `LSP server ${serverId} was killed`;
2012
- }
2013
- return;
2014
- };
2015
- const onProcessExit = (code, signal) => {
2016
- startupState.exitCode = code;
2017
- startupState.exitSignal = signal;
2018
- };
2019
- const onProcessClose = (code, signal) => {
2020
- startupState.closeCode = code;
2021
- startupState.closeSignal = signal;
2022
- };
2023
- lspProcess.stderr.on("data", onStderr);
2024
- lspProcess.process.on("exit", onProcessExit);
2025
- lspProcess.process.on("close", onProcessClose);
2026
- const streamErrorHandler = (_label) => (err) => {
2027
- if (err.code === "ERR_STREAM_DESTROYED" || err.code === "ERR_STREAM_WRITE_AFTER_END" || err.code === "EPIPE" || err.code === "ECONNRESET")
2028
- return;
2029
- };
2030
- lspProcess.stdin.on("error", streamErrorHandler("stdin"));
2031
- lspProcess.stdout.on("error", streamErrorHandler("stdout"));
2032
- lspProcess.stderr.on("error", streamErrorHandler("stderr"));
2033
- const connection = createMessageConnection(new StreamMessageReader(lspProcess.stdout), new StreamMessageWriter(lspProcess.stdin));
2034
- const diagnosticEmitter = new EventEmitter;
2035
- diagnosticEmitter.setMaxListeners(50);
2036
- const state = {
2037
- isConnected: true,
2038
- isDestroyed: false,
2039
- shutdownRequested: false,
2040
- shutdownPromise: undefined,
2041
- shutdownOptions: undefined,
2042
- exitedAt: undefined,
2043
- connectionDisposed: false,
2044
- lastError: undefined,
2045
- connection,
2046
- pushDiagnostics: new Map,
2047
- pushDiagnosticTimestamps: new Map,
2048
- documentPullDiagnostics: new Map,
2049
- documentPullDiagnosticTimestamps: new Map,
2050
- pullFailureHistory: [],
2051
- pendingDiagnostics: new Map,
2052
- diagnosticPublicationCounts: new Map,
2053
- documentOpenedAt: new Map,
2054
- diagnosticEmitter,
2055
- diagnosticsVersion: 0,
2056
- diagnosticsVersionsByPath: new Map,
2057
- documentVersions: new Map,
2058
- notifyChangeQueues: new Map,
2059
- diagnosticDocVersions: new Map,
2060
- documentContentHashes: new Map,
2061
- incrementalTextRetainedEntries: 0,
2062
- incrementalTextBearingPaths: new Set,
2063
- incrementalTextRetainedBytes: 0,
2064
- diagnosticBindings: new Map,
2065
- pullResultIds: new Map,
2066
- documentPullDiagnosticsBySource: new Map,
2067
- pullGenerations: new Map,
2068
- pullRequestSequences: new Map,
2069
- workspacePullResultCache: new Map,
2070
- openDocuments: new Set,
2071
- emptyFirstPublishHoldSpent: false,
2072
- closedDocuments: new Set,
2073
- openDocumentUris: new Map,
2074
- pendingOpens: new Set,
2075
- projectIdentityProbedFiles: new Set,
2076
- workspaceDiagnosticsSupport: undefined,
2077
- operationSupport: undefined,
2078
- staticDiagnosticsMode: "push-only",
2079
- positionEncoding: "utf-16",
2080
- syncKind: TEXT_DOCUMENT_SYNC_KIND_FULL,
2081
- dynamicRegistrations: new Map,
2082
- advertisedCommands: new Set,
2083
- serverEditsAllowed: 0,
2084
- activeMutationDepth: 0,
2085
- serverId,
2086
- launchVariant,
2087
- root,
2088
- lspProcess,
2089
- watchQueue: undefined
2090
- };
2091
- activeLspClientSet().add(state);
2092
- state.watchQueue = new WatchedFilesQueue((changes) => {
2093
- if (!isClientAlive(state))
2094
- return;
2095
- safeSendNotification(state.connection, "workspace/didChangeWatchedFiles", { changes });
2096
- });
2097
- setupIncomingHandlers(state, initialization, onDiagnosticsPublished);
2098
- connection.listen();
2099
- setupConnectionLifecycle(state, recentStderr);
2100
- let initResult;
2101
- try {
2102
- initResult = await withTimeout(safeSendRequest(connection, "initialize", {
2103
- processId: process.pid,
2104
- rootUri: pathToFileURL(root).href,
2105
- workspaceFolders: [
2106
- { name: "workspace", uri: pathToFileURL(root).href }
2107
- ],
2108
- capabilities: CLIENT_CAPABILITIES,
2109
- initializationOptions: initialization
2110
- }), initializeTimeoutMs);
2111
- } catch (err) {
2112
- state.shutdownRequested = true;
2113
- const pid = lspProcess.pid;
2114
- killProcessTree(lspProcess.process, pid);
2115
- removeLspChild(pid, extractSpawnMarker(lspProcess.args)).catch((err) => {
2116
- logLatency({
2117
- type: "phase",
2118
- phase: "lsp_registry_write_failed",
2119
- filePath: "",
2120
- durationMs: 0,
2121
- metadata: { op: "remove", pid, error: String(err) }
2122
- });
2123
- });
2124
- setTimeout(() => {
2125
- if (lspProcess.process.exitCode === null && lspProcess.process.signalCode === null && process.platform !== "win32") {
2126
- lspProcess.process.kill("SIGKILL");
2127
- }
2128
- }, 2000);
2129
- throw err;
2130
- } finally {
2131
- lspProcess.stderr.off("data", onStderr);
2132
- }
2133
- if (initResult === undefined) {
2134
- const compactStderr = startupState.stderr.replace(/\s+/g, " ").trim().slice(0, 320);
2135
- const reinstallHint = serverId === "cpp" ? "Install clangd (LLVM/clang-tools) and ensure clangd.exe is on PATH." : `Try reinstalling: npm install -g ${serverId}-language-server.`;
2136
- const telemetry = [
2137
- `pid=${lspProcess.pid}`,
2138
- `exitCode=${startupState.exitCode ?? "none"}`,
2139
- `exitSignal=${startupState.exitSignal ?? "none"}`,
2140
- `closeCode=${startupState.closeCode ?? "none"}`,
2141
- `closeSignal=${startupState.closeSignal ?? "none"}`,
2142
- `root=${root}`,
2143
- compactStderr ? `stderr=${compactStderr}` : "stderr=<empty>"
2144
- ].join(" ");
2145
- throw new Error(`[lsp] ${serverId} failed to initialize - stream may have been destroyed. ` + `The server binary may be missing or crashed immediately. ${reinstallHint} ` + `telemetry: ${telemetry}`);
2146
- }
2147
- state.workspaceDiagnosticsSupport = detectWorkspaceDiagnosticsSupport(initResult);
2148
- state.operationSupport = detectOperationSupport(initResult);
2149
- const capabilities = initResult?.capabilities ?? {};
2150
- const workspace = isCapabilityRecord(capabilities.workspace) ? capabilities.workspace : undefined;
2151
- const fileOperations = isCapabilityRecord(workspace) ? workspace.fileOperations : undefined;
2152
- const malformedFileOperationRegistrations = new Set;
2153
- if (isCapabilityRecord(fileOperations)) {
2154
- for (const operation of ["willRename", "didRename"]) {
2155
- if (fileOperations[operation] !== undefined && parseFileOperationFilters(fileOperations[operation]) === undefined) {
2156
- malformedFileOperationRegistrations.add(operation);
2157
- }
2158
- }
2159
- }
2160
- state.fileOperationMalformedRegistrations = malformedFileOperationRegistrations;
2161
- if (isCapabilityRecord(fileOperations)) {
2162
- state.fileOperationFilters = {
2163
- willRename: parseFileOperationFilters(fileOperations.willRename),
2164
- didRename: parseFileOperationFilters(fileOperations.didRename)
2165
- };
2166
- }
2167
- state.positionEncoding = negotiatePositionEncoding(initResult?.capabilities);
2168
- state.syncKind = negotiateSyncKind(initResult?.capabilities);
2169
- state.saveOptions = negotiateSaveOptions(initResult?.capabilities);
2170
- state.rawCapabilityKeys = Object.keys(initResult?.capabilities ?? {}).sort((a, b) => a.localeCompare(b));
2171
- for (const cmd of detectExecuteCommands(initResult)) {
2172
- state.advertisedCommands.add(cmd);
2173
- }
2174
- state.staticDiagnosticsMode = state.workspaceDiagnosticsSupport.mode;
2175
- await safeSendNotification(connection, "initialized", {});
2176
- if (initialization) {
2177
- await safeSendNotification(connection, "workspace/didChangeConfiguration", {
2178
- settings: initialization
2179
- });
2180
- }
2181
- return {
2182
- serverId,
2183
- root,
2184
- connection,
2185
- isAlive: () => isClientAlive(state),
2186
- processExited: () => lspProcess.process.exitCode !== null || lspProcess.process.killed === true,
2187
- wasShutdownIntentional: () => state.shutdownRequested,
2188
- getExitedAt: () => state.exitedAt,
2189
- recentStderr: (lines) => recentStderr(lines),
2190
- getPullFailureHistory: () => state.pullFailureHistory.map((entry) => ({
2191
- ...entry,
2192
- message: entry.message.slice(0, 200)
2193
- })),
2194
- checkAlive: () => checkProcessAlive(),
2195
- pingLiveness: (timeoutMs) => clientPingLiveness(state, timeoutMs),
2196
- getProcessPid: () => lspProcess.pid,
2197
- notify: {
2198
- async open(filePath, content, languageId, preserveDiagnostics, silent, saved) {
2199
- return handleNotifyOpen(state, filePath, content, languageId, preserveDiagnostics, silent, saved);
2200
- },
2201
- async change(filePath, content) {
2202
- return handleNotifyChange(state, filePath, content);
2203
- },
2204
- watchedFileChange(filePath, type) {
2205
- handleNotifyExternalChange(state, filePath, type);
2206
- }
2207
- },
2208
- getDiagnostics(filePath) {
2209
- return getMergedDiagnosticsForPath(state, normalizeMapKey(filePath));
2210
- },
2211
- getDiagnosticBinding(filePath) {
2212
- return state.diagnosticBindings.get(normalizeMapKey(filePath));
2213
- },
2214
- getDiagnosticsVersionForPath(filePath) {
2215
- return diagnosticsVersionForPath(state, normalizeMapKey(filePath));
2216
- },
2217
- getAllDiagnostics() {
2218
- const result = new Map;
2219
- const keys = new Set([
2220
- ...state.pushDiagnostics.keys(),
2221
- ...state.documentPullDiagnostics.keys()
2222
- ]);
2223
- for (const key of keys) {
2224
- result.set(key, {
2225
- diags: getMergedDiagnosticsForPath(state, key),
2226
- ts: Math.max(state.pushDiagnosticTimestamps.get(key) ?? 0, state.documentPullDiagnosticTimestamps.get(key) ?? 0),
2227
- binding: state.diagnosticBindings.get(key)
2228
- });
2229
- }
2230
- return result;
2231
- },
2232
- getTrackedDiagnosticPaths() {
2233
- return [
2234
- ...new Set([
2235
- ...state.pushDiagnostics.keys(),
2236
- ...state.documentPullDiagnostics.keys()
2237
- ])
2238
- ].map((filePath) => process.platform === "win32" ? filePath.replace(/\//g, "\\") : filePath);
2239
- },
2240
- pruneDiagnostics(predicate) {
2241
- let removed = 0;
2242
- const keys = new Set([
2243
- ...state.pushDiagnostics.keys(),
2244
- ...state.documentPullDiagnostics.keys()
2245
- ]);
2246
- for (const key of keys) {
2247
- const diags = getMergedDiagnosticsForPath(state, key);
2248
- const ts = Math.max(state.pushDiagnosticTimestamps.get(key) ?? 0, state.documentPullDiagnosticTimestamps.get(key) ?? 0);
2249
- if (!predicate(key, ts, diags))
2250
- continue;
2251
- clearDiagnosticsForPath(state, key);
2252
- removed++;
2253
- }
2254
- return removed;
2255
- },
2256
- getWorkspaceDiagnosticsSupport() {
2257
- return state.workspaceDiagnosticsSupport;
2258
- },
2259
- requestWorkspaceDiagnostics(budgetMs) {
2260
- return clientRequestWorkspaceDiagnostics(state, budgetMs);
2261
- },
2262
- getOperationSupport() {
2263
- return state.operationSupport;
2264
- },
2265
- getMalformedFileOperationRegistrations() {
2266
- return state.fileOperationMalformedRegistrations ?? new Set;
2267
- },
2268
- getAdvertisedCommands() {
2269
- return [...state.advertisedCommands];
2270
- },
2271
- getRawCapabilityKeys() {
2272
- return state.rawCapabilityKeys ?? [];
2273
- },
2274
- getLaunchVariant() {
2275
- return state.launchVariant;
2276
- },
2277
- async executeCommand(command, args, mutationContext) {
2278
- return runServerCommand(state, command, args, EXECUTE_COMMAND_TIMEOUT_MS, mutationContext);
2279
- },
2280
- async executeReadOnlyCommand(command, args) {
2281
- return runReadOnlyServerCommand(state, command, args);
2282
- },
2283
- get diagnosticsVersion() {
2284
- return state.diagnosticsVersion;
2285
- },
2286
- async waitForDiagnostics(filePath, timeoutMs = DIAGNOSTICS_WAIT_TIMEOUT_MS, options) {
2287
- return clientWaitForDiagnostics(state, filePath, timeoutMs, options);
2288
- },
2289
- async definition(filePath, line, character) {
2290
- const result = await navRequest(state, "textDocument/definition", {
2291
- textDocument: { uri: pathToFileURL(filePath).href },
2292
- position: await toWirePosition(state, filePath, line, character)
2293
- }, filePath);
2294
- if (!result)
2295
- return [];
2296
- return Array.isArray(result) ? result : [result];
2297
- },
2298
- async typeDefinition(filePath, line, character) {
2299
- const result = await navRequest(state, "textDocument/typeDefinition", {
2300
- textDocument: { uri: pathToFileURL(filePath).href },
2301
- position: await toWirePosition(state, filePath, line, character)
2302
- }, filePath);
2303
- if (!result)
2304
- return [];
2305
- return Array.isArray(result) ? result : [result];
2306
- },
2307
- async declaration(filePath, line, character) {
2308
- const result = await navRequest(state, "textDocument/declaration", {
2309
- textDocument: { uri: pathToFileURL(filePath).href },
2310
- position: await toWirePosition(state, filePath, line, character)
2311
- }, filePath);
2312
- if (!result)
2313
- return [];
2314
- return Array.isArray(result) ? result : [result];
2315
- },
2316
- async references(filePath, line, character, includeDeclaration = true) {
2317
- const result = await navRequest(state, "textDocument/references", {
2318
- textDocument: { uri: pathToFileURL(filePath).href },
2319
- position: await toWirePosition(state, filePath, line, character),
2320
- context: { includeDeclaration }
2321
- }, filePath);
2322
- return result ?? [];
2323
- },
2324
- async hover(filePath, line, character) {
2325
- const result = await navRequest(state, "textDocument/hover", {
2326
- textDocument: { uri: pathToFileURL(filePath).href },
2327
- position: await toWirePosition(state, filePath, line, character)
2328
- }, filePath);
2329
- return result ?? null;
2330
- },
2331
- async signatureHelp(filePath, line, character) {
2332
- const result = await navRequest(state, "textDocument/signatureHelp", {
2333
- textDocument: { uri: pathToFileURL(filePath).href },
2334
- position: await toWirePosition(state, filePath, line, character)
2335
- }, filePath);
2336
- return result ?? null;
2337
- },
2338
- async documentSymbol(filePath) {
2339
- const result = await navRequest(state, "textDocument/documentSymbol", { textDocument: { uri: pathToFileURL(filePath).href } }, filePath);
2340
- return result ?? [];
2341
- },
2342
- isDocumentOpen(filePath) {
2343
- return state.openDocuments.has(normalizeMapKey(filePath));
2344
- },
2345
- openDocumentPaths() {
2346
- return [...state.openDocuments];
2347
- },
2348
- isBusy() {
2349
- return (activeRequestsByConnection.get(connection) ?? 0) > 0;
2350
- },
2351
- getDocumentUri(filePath) {
2352
- return state.openDocumentUris?.get(normalizeMapKey(filePath));
2353
- },
2354
- async workspaceSymbol(query) {
2355
- if (!isClientAlive(state))
2356
- return [];
2357
- const result = await navRequest(state, "workspace/symbol", {
2358
- query
2359
- });
2360
- return result ?? [];
2361
- },
2362
- async codeAction(filePath, line, character, endLine, endCharacter) {
2363
- if (!isClientAlive(state))
2364
- return [];
2365
- const uri = pathToFileURL(filePath).href;
2366
- const result = await navRequest(state, "textDocument/codeAction", {
2367
- textDocument: { uri },
2368
- range: {
2369
- start: await toWirePosition(state, filePath, line, character),
2370
- end: await toWirePosition(state, filePath, endLine, endCharacter)
2371
- },
2372
- context: {
2373
- diagnostics: getMergedDiagnosticsForPath(state, normalizeMapKey(filePath))
2374
- }
2375
- }, filePath);
2376
- if (!result || !Array.isArray(result))
2377
- return [];
2378
- const actions = result.filter((item) => typeof item === "object" && item !== null && ("title" in item));
2379
- return Promise.all(actions.map((action) => resolveCodeActionBestEffort(state, action)));
2380
- },
2381
- async rename(filePath, line, character, newName) {
2382
- const result = await navRequest(state, "textDocument/rename", {
2383
- textDocument: { uri: pathToFileURL(filePath).href },
2384
- position: await toWirePosition(state, filePath, line, character),
2385
- newName
2386
- }, filePath);
2387
- return result ? await normalizeClientWorkspaceEdit(state, result) : null;
2388
- },
2389
- closeDocument: (filePath) => closeDocument(state, filePath),
2390
- async willRenameFiles(oldFilePath, newFilePath) {
2391
- if (!isClientAlive(state))
2392
- return null;
2393
- const oldUri = pathToFileURL(oldFilePath).href;
2394
- const newUri = pathToFileURL(newFilePath).href;
2395
- if (!await fileOperationFiltersMatch(state.fileOperationFilters?.willRename, oldUri, newUri, oldFilePath, newFilePath)) {
2396
- recordDegradationOnce({
2397
- kind: "lsp-capability-skip",
2398
- subject: `${state.serverId}:workspace/willRenameFiles:filter`,
2399
- reason: "filter-mismatch"
2400
- });
2401
- return null;
2402
- }
2403
- const result = await navRequest(state, "workspace/willRenameFiles", {
2404
- files: [
2405
- {
2406
- oldUri,
2407
- newUri
2408
- }
2409
- ]
2410
- });
2411
- return result ? await normalizeClientWorkspaceEdit(state, result) : null;
2412
- },
2413
- async didRenameFiles(oldFilePath, newFilePath, oldUri, newUri) {
2414
- if (!isClientAlive(state))
2415
- return;
2416
- const wireOldUri = oldUri ?? pathToFileURL(oldFilePath).href;
2417
- const wireNewUri = newUri ?? pathToFileURL(newFilePath).href;
2418
- if (!await fileOperationFiltersMatch(state.fileOperationFilters?.didRename, wireOldUri, wireNewUri, oldFilePath, newFilePath)) {
2419
- recordDegradationOnce({
2420
- kind: "lsp-capability-skip",
2421
- subject: `${state.serverId}:workspace/didRenameFiles:filter`,
2422
- reason: "filter-mismatch"
2423
- });
2424
- return;
2425
- }
2426
- await safeSendNotification(state.connection, "workspace/didRenameFiles", {
2427
- files: [
2428
- {
2429
- oldUri: wireOldUri,
2430
- newUri: wireNewUri
2431
- }
2432
- ]
2433
- });
2434
- },
2435
- async implementation(filePath, line, character) {
2436
- const result = await navRequest(state, "textDocument/implementation", {
2437
- textDocument: { uri: pathToFileURL(filePath).href },
2438
- position: await toWirePosition(state, filePath, line, character)
2439
- }, filePath);
2440
- if (!result)
2441
- return [];
2442
- return Array.isArray(result) ? result : [result];
2443
- },
2444
- async prepareCallHierarchy(filePath, line, character) {
2445
- const result = await navRequest(state, "textDocument/prepareCallHierarchy", {
2446
- textDocument: { uri: pathToFileURL(filePath).href },
2447
- position: await toWirePosition(state, filePath, line, character)
2448
- }, filePath);
2449
- if (!result)
2450
- return [];
2451
- return Array.isArray(result) ? result : [result];
2452
- },
2453
- async incomingCalls(item) {
2454
- const result = await navRequest(state, "callHierarchy/incomingCalls", { item });
2455
- return result ?? [];
2456
- },
2457
- async outgoingCalls(item) {
2458
- const result = await navRequest(state, "callHierarchy/outgoingCalls", { item });
2459
- return result ?? [];
2460
- },
2461
- async shutdown(options) {
2462
- return clientShutdown(state, options);
2463
- }
2464
- };
2465
- }
2466
- async function safeSendNotification(connection, method, params) {
2467
- try {
2468
- await connection.sendNotification(method, params);
2469
- return true;
2470
- } catch (err) {
2471
- if (isStreamError(err)) {
2472
- return false;
2473
- }
2474
- throw err;
2475
- }
2476
- }
2477
- const activeRequestsByConnection = new WeakMap;
2478
- async function safeSendRequest(connection, method, params, signal, settlement) {
2479
- if (signal?.aborted)
2480
- return;
2481
- let tokenSource;
2482
- let onAbort;
2483
- if (signal) {
2484
- tokenSource = new CancellationTokenSource;
2485
- onAbort = () => tokenSource?.cancel();
2486
- signal.addEventListener("abort", onAbort, { once: true });
2487
- }
2488
- const send = () => tokenSource ? connection.sendRequest(method, params, tokenSource.token) : connection.sendRequest(method, params);
2489
- activeRequestsByConnection.set(connection, (activeRequestsByConnection.get(connection) ?? 0) + 1);
2490
- try {
2491
- const MAX_ATTEMPTS = 2;
2492
- for (let attempt = 1;; attempt++) {
2493
- try {
2494
- return await send();
2495
- } catch (err) {
2496
- if (isCancellationError(err)) {
2497
- if (settlement)
2498
- settlement.cancelled = true;
2499
- return;
2500
- }
2501
- if (isStreamError(err)) {
2502
- return;
2503
- }
2504
- if (isContentModifiedError(err)) {
2505
- if (attempt < MAX_ATTEMPTS && !signal?.aborted)
2506
- continue;
2507
- return;
2508
- }
2509
- throw err;
2510
- }
2511
- }
2512
- } finally {
2513
- const remaining = (activeRequestsByConnection.get(connection) ?? 1) - 1;
2514
- if (remaining > 0)
2515
- activeRequestsByConnection.set(connection, remaining);
2516
- else
2517
- activeRequestsByConnection.delete(connection);
2518
- if (signal && onAbort)
2519
- signal.removeEventListener("abort", onAbort);
2520
- tokenSource?.dispose();
2521
- }
2522
- }
2523
- function isCancellationError(err) {
2524
- const code = err?.code;
2525
- return code === -32800 || code === -32802;
2526
- }
2527
- function isContentModifiedError(err) {
2528
- return err?.code === -32801;
2529
- }
2530
- function isStreamError(err) {
2531
- if (!(err instanceof Error))
2532
- return false;
2533
- const msg = err.message.toLowerCase();
2534
- return msg.includes("stream") || msg.includes("destroyed") || msg.includes("closed") || msg.includes("disposed") || msg.includes("cancelled") || err.code === "ERR_STREAM_DESTROYED" || err.code === "ERR_STREAM_WRITE_AFTER_END" || err.code === "EPIPE";
2535
- }
2536
- function positiveIntFromEnv(name, fallback) {
2537
- const raw = process.env[name];
2538
- if (!raw)
2539
- return fallback;
2540
- const parsed = Number.parseInt(raw, 10);
2541
- if (!Number.isFinite(parsed) || parsed <= 0)
2542
- return fallback;
2543
- return parsed;
2544
- }
2545
- function detectWorkspaceDiagnosticsSupport(initResult) {
2546
- const capabilities = typeof initResult === "object" && initResult !== null ? initResult.capabilities : undefined;
2547
- const diagnosticProvider = capabilities?.diagnosticProvider;
2548
- if (!diagnosticProvider) {
2549
- return {
2550
- advertised: false,
2551
- mode: "push-only",
2552
- workspaceDiagnostics: false,
2553
- diagnosticProviderKind: "none"
2554
- };
2555
- }
2556
- if (typeof diagnosticProvider === "boolean") {
2557
- return {
2558
- advertised: diagnosticProvider,
2559
- mode: diagnosticProvider ? "pull" : "push-only",
2560
- workspaceDiagnostics: false,
2561
- diagnosticProviderKind: "boolean"
2562
- };
2563
- }
2564
- if (typeof diagnosticProvider === "object") {
2565
- return {
2566
- advertised: true,
2567
- mode: "pull",
2568
- workspaceDiagnostics: diagnosticProvider.workspaceDiagnostics === true,
2569
- diagnosticProviderKind: "object"
2570
- };
2571
- }
2572
- return {
2573
- advertised: false,
2574
- mode: "push-only",
2575
- workspaceDiagnostics: false,
2576
- diagnosticProviderKind: typeof diagnosticProvider
2577
- };
2578
- }
2579
- function detectExecuteCommands(initResult) {
2580
- const capabilities = typeof initResult === "object" && initResult !== null ? initResult.capabilities : undefined;
2581
- const provider = capabilities?.executeCommandProvider;
2582
- if (typeof provider !== "object" || provider === null)
2583
- return [];
2584
- const commands = provider.commands;
2585
- if (!Array.isArray(commands))
2586
- return [];
2587
- return commands.filter((cmd) => typeof cmd === "string");
2588
- }
2589
- function detectOperationSupport(initResult) {
2590
- const capabilities = typeof initResult === "object" && initResult !== null ? initResult.capabilities : undefined;
2591
- const hasProvider = (key) => {
2592
- const value = capabilities?.[key];
2593
- if (value === undefined || value === null)
2594
- return false;
2595
- if (typeof value === "boolean")
2596
- return value;
2597
- return isCapabilityRecord(value);
2598
- };
2599
- const codeActionProvider = capabilities?.codeActionProvider;
2600
- const workspace = capabilities?.workspace;
2601
- const fileOperations = isCapabilityRecord(workspace) ? workspace.fileOperations : undefined;
2602
- return {
2603
- definition: hasProvider("definitionProvider"),
2604
- typeDefinition: hasProvider("typeDefinitionProvider"),
2605
- declaration: hasProvider("declarationProvider"),
2606
- references: hasProvider("referencesProvider"),
2607
- hover: hasProvider("hoverProvider"),
2608
- signatureHelp: hasProvider("signatureHelpProvider"),
2609
- documentSymbol: hasProvider("documentSymbolProvider"),
2610
- workspaceSymbol: hasProvider("workspaceSymbolProvider"),
2611
- codeAction: hasProvider("codeActionProvider"),
2612
- codeActionResolve: isCapabilityRecord(codeActionProvider) && codeActionProvider.resolveProvider === true,
2613
- rename: hasProvider("renameProvider"),
2614
- willRenameFiles: isCapabilityRecord(fileOperations) && isFileOperationRegistrationOptions(fileOperations.willRename),
2615
- didRenameFiles: isCapabilityRecord(fileOperations) && isFileOperationRegistrationOptions(fileOperations.didRename),
2616
- implementation: hasProvider("implementationProvider"),
2617
- callHierarchy: hasProvider("callHierarchyProvider")
2618
- };
2619
- }
2620
- function isCapabilityRecord(value) {
2621
- return typeof value === "object" && value !== null && !Array.isArray(value);
2622
- }
2623
- function isFileOperationRegistrationOptions(value) {
2624
- return parseFileOperationFilters(value) !== undefined;
2625
- }
2626
- function parseFileOperationFilters(value) {
2627
- if (!isCapabilityRecord(value) || !Array.isArray(value.filters)) {
2628
- return;
2629
- }
2630
- const filters = [];
2631
- for (const entry of value.filters) {
2632
- if (!isCapabilityRecord(entry))
2633
- return;
2634
- const pattern = entry.pattern;
2635
- if (!isCapabilityRecord(pattern) || typeof pattern.glob !== "string" || pattern.glob.trim() === "") {
2636
- return;
2637
- }
2638
- if (entry.scheme !== undefined && (typeof entry.scheme !== "string" || entry.scheme.trim() === "" || !/^[A-Za-z][A-Za-z0-9+.-]*$/.test(entry.scheme))) {
2639
- return;
2640
- }
2641
- const matches = pattern.matches;
2642
- if (matches !== undefined && matches !== "file" && matches !== "folder") {
2643
- return;
2644
- }
2645
- if (pattern.options !== undefined && !isCapabilityRecord(pattern.options)) {
2646
- return;
2647
- }
2648
- const options = isCapabilityRecord(pattern.options) ? pattern.options : undefined;
2649
- if (options?.ignoreCase !== undefined && typeof options.ignoreCase !== "boolean") {
2650
- return;
2651
- }
2652
- filters.push({
2653
- scheme: entry.scheme?.toLowerCase(),
2654
- glob: pattern.glob,
2655
- matches: matches === "file" || matches === "folder" ? matches : undefined,
2656
- ignoreCase: options?.ignoreCase === true
2657
- });
2658
- }
2659
- return filters;
2660
- }
2661
- async function fileOperationFiltersMatch(filters, oldUri, newUri, oldFilePath, newFilePath) {
2662
- if (!filters || filters.length === 0)
2663
- return false;
2664
- const candidates = [oldUri, newUri].flatMap(fileOperationUriCandidates);
2665
- const entityKind = filters.some((filter) => filter.matches !== undefined) ? await probeRenameEntityKind(oldFilePath, newFilePath) : undefined;
2666
- for (const filter of filters) {
2667
- if (filter.scheme !== undefined && filter.scheme !== "file")
2668
- continue;
2669
- if (filter.matches !== undefined && filter.matches !== entityKind)
2670
- continue;
2671
- for (const candidate of candidates) {
2672
- try {
2673
- if (minimatch(candidate, filter.glob, {
2674
- nocase: filter.ignoreCase,
2675
- dot: true
2676
- })) {
2677
- return true;
2678
- }
2679
- } catch {}
2680
- }
2681
- }
2682
- return false;
2683
- }
2684
- function fileOperationUriCandidates(uri) {
2685
- let parsed;
2686
- try {
2687
- parsed = new URL(uri);
2688
- } catch {
2689
- return [];
2690
- }
2691
- if (parsed.protocol.toLowerCase() !== "file:")
2692
- return [];
2693
- let uriPath;
2694
- try {
2695
- uriPath = decodeURIComponent(parsed.pathname).replace(/\\/g, "/");
2696
- } catch {
2697
- return [];
2698
- }
2699
- return [uriPath];
2700
- }
2701
- async function probeRenameEntityKind(oldFilePath, newFilePath) {
2702
- for (const filePath of [oldFilePath, newFilePath]) {
2703
- try {
2704
- const info = await lstat(filePath);
2705
- return info.isDirectory() ? "folder" : "file";
2706
- } catch {}
2707
- }
2708
- return;
2709
- }