lazycodex-ai 5.1.47 → 5.1.51

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 (438) hide show
  1. package/dist/cli/index.js +1194 -752
  2. package/dist/cli/service-auth/accounts-gate.d.ts +11 -0
  3. package/dist/cli/service-auth/commands.d.ts +2 -4
  4. package/dist/cli/service-auth/index.d.ts +1 -1
  5. package/dist/cli/service-auth/keystore.d.ts +26 -2
  6. package/dist/cli/service-auth/protocol.d.ts +7 -1
  7. package/dist/cli/service-auth/session.d.ts +6 -0
  8. package/dist/cli/service-auth/signed-out-marker.d.ts +11 -0
  9. package/dist/cli-node/index.js +1194 -752
  10. package/package.json +3 -1
  11. package/packages/lsp-core/package.json +45 -0
  12. package/packages/lsp-core/src/index.ts +30 -0
  13. package/packages/lsp-core/src/lsp/bun-command-output.ts +82 -0
  14. package/packages/lsp-core/src/lsp/bun-project-checks.test.ts +170 -0
  15. package/packages/lsp-core/src/lsp/bun-project-checks.ts +223 -0
  16. package/packages/lsp-core/src/lsp/cleanup-errors.test.ts +18 -0
  17. package/packages/lsp-core/src/lsp/cleanup-errors.ts +14 -0
  18. package/packages/lsp-core/src/lsp/client-diagnostics-concurrency.integration.test.ts +52 -0
  19. package/packages/lsp-core/src/lsp/client-diagnostics-freshness.integration.test.ts +471 -0
  20. package/packages/lsp-core/src/lsp/client-diagnostics-pull-timeout.test.ts +64 -0
  21. package/packages/lsp-core/src/lsp/client-wrapper-outside-cwd.test.ts +78 -0
  22. package/packages/lsp-core/src/lsp/client-wrapper.test.ts +213 -0
  23. package/packages/lsp-core/src/lsp/client-wrapper.ts +290 -0
  24. package/packages/lsp-core/src/lsp/client.ts +398 -0
  25. package/packages/lsp-core/src/lsp/config-loader.ts +254 -0
  26. package/packages/lsp-core/src/lsp/connection.ts +95 -0
  27. package/packages/lsp-core/src/lsp/constants.ts +17 -0
  28. package/packages/lsp-core/src/lsp/controlled-clock-test-support.ts +90 -0
  29. package/packages/lsp-core/src/lsp/directory-diagnostics.test.ts +221 -0
  30. package/packages/lsp-core/src/lsp/directory-diagnostics.ts +187 -0
  31. package/packages/lsp-core/src/lsp/effective-extension.ts +10 -0
  32. package/packages/lsp-core/src/lsp/errors.ts +89 -0
  33. package/packages/lsp-core/src/lsp/fake-bun-test-support.ts +102 -0
  34. package/packages/lsp-core/src/lsp/fixtures/diagnostics-freshness-contract-probe.ts +283 -0
  35. package/packages/lsp-core/src/lsp/fixtures/disposed-stdin-epipe-probe.ts +28 -0
  36. package/packages/lsp-core/src/lsp/fixtures/workspace-edit-contract-probe.ts +196 -0
  37. package/packages/lsp-core/src/lsp/fixtures/workspace-edit-server.mjs +234 -0
  38. package/packages/lsp-core/src/lsp/format-document.test.ts +143 -0
  39. package/packages/lsp-core/src/lsp/format-document.ts +90 -0
  40. package/packages/lsp-core/src/lsp/formatters.ts +144 -0
  41. package/packages/lsp-core/src/lsp/infer-extension.ts +66 -0
  42. package/packages/lsp-core/src/lsp/json-rpc-connection-cancellation.test.ts +97 -0
  43. package/packages/lsp-core/src/lsp/json-rpc-connection.ts +369 -0
  44. package/packages/lsp-core/src/lsp/language-mappings.ts +173 -0
  45. package/packages/lsp-core/src/lsp/manager-lifecycle.test.ts +262 -0
  46. package/packages/lsp-core/src/lsp/manager-max-clients.test.ts +151 -0
  47. package/packages/lsp-core/src/lsp/manager.ts +495 -0
  48. package/packages/lsp-core/src/lsp/outside-context-workspace.ts +33 -0
  49. package/packages/lsp-core/src/lsp/process-pipe-errors.test.ts +21 -0
  50. package/packages/lsp-core/src/lsp/process-signal-cleanup.ts +21 -0
  51. package/packages/lsp-core/src/lsp/process.ts +221 -0
  52. package/packages/lsp-core/src/lsp/server-definitions.ts +205 -0
  53. package/packages/lsp-core/src/lsp/server-install-state.ts +67 -0
  54. package/packages/lsp-core/src/lsp/server-installation.test.ts +376 -0
  55. package/packages/lsp-core/src/lsp/server-installation.ts +218 -0
  56. package/packages/lsp-core/src/lsp/server-resolution-local-binary.test.ts +170 -0
  57. package/packages/lsp-core/src/lsp/server-resolution.ts +117 -0
  58. package/packages/lsp-core/src/lsp/startup-failure.ts +1 -0
  59. package/packages/lsp-core/src/lsp/timer-provider.ts +13 -0
  60. package/packages/lsp-core/src/lsp/transport-protocol.ts +52 -0
  61. package/packages/lsp-core/src/lsp/transport-request-timeout.test.ts +73 -0
  62. package/packages/lsp-core/src/lsp/transport.ts +339 -0
  63. package/packages/lsp-core/src/lsp/types.ts +134 -0
  64. package/packages/lsp-core/src/lsp/utils.test.ts +72 -0
  65. package/packages/lsp-core/src/lsp/utils.ts +40 -0
  66. package/packages/lsp-core/src/lsp/workspace-apply-edit-failure.ts +19 -0
  67. package/packages/lsp-core/src/lsp/workspace-apply-edit-lease.integration.test.ts +218 -0
  68. package/packages/lsp-core/src/lsp/workspace-apply-edit-sync.integration.test.ts +113 -0
  69. package/packages/lsp-core/src/lsp/workspace-apply-edit-test-support.ts +194 -0
  70. package/packages/lsp-core/src/lsp/workspace-apply-edit.integration.test.ts +163 -0
  71. package/packages/lsp-core/src/lsp/workspace-document-state.test.ts +150 -0
  72. package/packages/lsp-core/src/lsp/workspace-document-state.ts +392 -0
  73. package/packages/lsp-core/src/lsp/workspace-edit-adversarial.test.ts +132 -0
  74. package/packages/lsp-core/src/lsp/workspace-edit-commit.test.ts +140 -0
  75. package/packages/lsp-core/src/lsp/workspace-edit-commit.ts +220 -0
  76. package/packages/lsp-core/src/lsp/workspace-edit-contract-evidence.test.ts +56 -0
  77. package/packages/lsp-core/src/lsp/workspace-edit-contract-evidence.ts +30 -0
  78. package/packages/lsp-core/src/lsp/workspace-edit-fingerprint.ts +44 -0
  79. package/packages/lsp-core/src/lsp/workspace-edit-options.test.ts +147 -0
  80. package/packages/lsp-core/src/lsp/workspace-edit-parse-helpers.ts +59 -0
  81. package/packages/lsp-core/src/lsp/workspace-edit-parser.ts +130 -0
  82. package/packages/lsp-core/src/lsp/workspace-edit-path.ts +98 -0
  83. package/packages/lsp-core/src/lsp/workspace-edit-plan-types.ts +60 -0
  84. package/packages/lsp-core/src/lsp/workspace-edit-plan.ts +73 -0
  85. package/packages/lsp-core/src/lsp/workspace-edit-prevalidation.test.ts +174 -0
  86. package/packages/lsp-core/src/lsp/workspace-edit-resource-parser.ts +89 -0
  87. package/packages/lsp-core/src/lsp/workspace-edit-simulation.ts +183 -0
  88. package/packages/lsp-core/src/lsp/workspace-edit-snapshot.ts +53 -0
  89. package/packages/lsp-core/src/lsp/workspace-edit-text.ts +125 -0
  90. package/packages/lsp-core/src/lsp/workspace-edit-types.ts +121 -0
  91. package/packages/lsp-core/src/lsp/workspace-edit.characterization.test.ts +95 -0
  92. package/packages/lsp-core/src/lsp/workspace-edit.ts +55 -0
  93. package/packages/lsp-core/src/lsp/workspace-markers.ts +18 -0
  94. package/packages/lsp-core/src/lsp/workspace-mutation-controller.ts +182 -0
  95. package/packages/lsp-core/src/mcp-protocol-pin.test.ts +97 -0
  96. package/packages/lsp-core/src/mcp.ts +122 -0
  97. package/packages/lsp-core/src/missing-dependency-result.test.ts +135 -0
  98. package/packages/lsp-core/src/missing-dependency-result.ts +79 -0
  99. package/packages/lsp-core/src/post-edit/file-location.ts +55 -0
  100. package/packages/lsp-core/src/post-edit/index.ts +3 -0
  101. package/packages/lsp-core/src/post-edit/not-installed-guidance.ts +36 -0
  102. package/packages/lsp-core/src/post-edit/not-installed.test.ts +224 -0
  103. package/packages/lsp-core/src/post-edit/orchestration.test.ts +157 -0
  104. package/packages/lsp-core/src/post-edit/orchestration.ts +205 -0
  105. package/packages/lsp-core/src/request-context.test.ts +200 -0
  106. package/packages/lsp-core/src/request-context.ts +235 -0
  107. package/packages/lsp-core/src/tool-surface.test.ts +173 -0
  108. package/packages/lsp-core/src/tools/bun-directory-diagnostics.test.ts +113 -0
  109. package/packages/lsp-core/src/tools/bun-directory-diagnostics.ts +75 -0
  110. package/packages/lsp-core/src/tools/definitions.ts +156 -0
  111. package/packages/lsp-core/src/tools/diagnostics.ts +133 -0
  112. package/packages/lsp-core/src/tools/format.test.ts +56 -0
  113. package/packages/lsp-core/src/tools/format.ts +56 -0
  114. package/packages/lsp-core/src/tools/index.ts +11 -0
  115. package/packages/lsp-core/src/tools/install-decision.ts +39 -0
  116. package/packages/lsp-core/src/tools/navigation.ts +88 -0
  117. package/packages/lsp-core/src/tools/parameters.test.ts +51 -0
  118. package/packages/lsp-core/src/tools/parameters.ts +49 -0
  119. package/packages/lsp-core/src/tools/rename.ts +69 -0
  120. package/packages/lsp-core/src/tools/result.ts +5 -0
  121. package/packages/lsp-core/src/tools/runtime.ts +21 -0
  122. package/packages/lsp-core/src/tools/schema.ts +9 -0
  123. package/packages/lsp-core/src/tools/status.ts +28 -0
  124. package/packages/lsp-core/src/tools/symbols.ts +99 -0
  125. package/packages/lsp-core/src/tools/types.ts +116 -0
  126. package/packages/lsp-core/src/tools.ts +1 -0
  127. package/packages/omo-codex/plugin/.codex-plugin/plugin.json +1 -1
  128. package/packages/omo-codex/plugin/README.md +1 -1
  129. package/packages/omo-codex/plugin/components/bootstrap/hooks/hooks.json +1 -1
  130. package/packages/omo-codex/plugin/components/bootstrap/package.json +1 -1
  131. package/packages/omo-codex/plugin/components/comment-checker/hooks/hooks.json +1 -1
  132. package/packages/omo-codex/plugin/components/comment-checker/package.json +1 -1
  133. package/packages/omo-codex/plugin/components/git-bash/hooks/hooks.json +2 -2
  134. package/packages/omo-codex/plugin/components/git-bash/package.json +1 -1
  135. package/packages/omo-codex/plugin/components/lazycodex-executor-verify/hooks/hooks.json +1 -1
  136. package/packages/omo-codex/plugin/components/lazycodex-executor-verify/package.json +1 -1
  137. package/packages/omo-codex/plugin/components/lcx/skills/lcx-contribute-bug-fix/SKILL.md +51 -55
  138. package/packages/omo-codex/plugin/components/lcx/skills/lcx-contribute-bug-fix/agents/openai.yaml +1 -1
  139. package/packages/omo-codex/plugin/components/lcx/skills/lcx-report-bug/SKILL.md +7 -7
  140. package/packages/omo-codex/plugin/components/lcx/skills/lcx-report-bug/agents/openai.yaml +1 -1
  141. package/packages/omo-codex/plugin/components/lsp/dist/.omo-runtime-manifest.json +2 -2
  142. package/packages/omo-codex/plugin/components/lsp/hooks/hooks.json +2 -2
  143. package/packages/omo-codex/plugin/components/lsp/package.json +1 -1
  144. package/packages/omo-codex/plugin/components/rules/hooks/hooks.json +4 -4
  145. package/packages/omo-codex/plugin/components/rules/package.json +1 -1
  146. package/packages/omo-codex/plugin/components/teammode/hooks/hooks.json +1 -1
  147. package/packages/omo-codex/plugin/components/teammode/package.json +2 -2
  148. package/packages/omo-codex/plugin/components/telemetry/README.md +2 -2
  149. package/packages/omo-codex/plugin/components/telemetry/dist/cli.js +52 -15
  150. package/packages/omo-codex/plugin/components/telemetry/dist/posthog.js +52 -19
  151. package/packages/omo-codex/plugin/components/telemetry/hooks/hooks.json +1 -1
  152. package/packages/omo-codex/plugin/components/telemetry/package.json +1 -1
  153. package/packages/omo-codex/plugin/components/telemetry/src/codex-hook.ts +2 -9
  154. package/packages/omo-codex/plugin/components/telemetry/src/posthog.ts +4 -13
  155. package/packages/omo-codex/plugin/components/telemetry/src/product-identity.ts +0 -2
  156. package/packages/omo-codex/plugin/components/telemetry/test/codex-hook-diagnostics.test.ts +0 -3
  157. package/packages/omo-codex/plugin/components/telemetry/test/codex-hook.test.ts +3 -8
  158. package/packages/omo-codex/plugin/components/ultrawork/dist/cli.js +3 -0
  159. package/packages/omo-codex/plugin/components/ultrawork/hooks/hooks.json +1 -1
  160. package/packages/omo-codex/plugin/components/ultrawork/package.json +1 -1
  161. package/packages/omo-codex/plugin/components/ultrawork/src/directive-content.ts +1 -1
  162. package/packages/omo-codex/plugin/components/ulw-execute-continuation/hooks/hooks.json +1 -1
  163. package/packages/omo-codex/plugin/components/ulw-execute-continuation/package.json +1 -1
  164. package/packages/omo-codex/plugin/components/ulw-loop/directive.md +3 -0
  165. package/packages/omo-codex/plugin/components/ulw-loop/hooks/hooks.json +5 -5
  166. package/packages/omo-codex/plugin/components/ulw-loop/package.json +1 -1
  167. package/packages/omo-codex/plugin/hooks/post-compact-resetting-git-bash-mcp-reminder.json +1 -1
  168. package/packages/omo-codex/plugin/hooks/post-compact-resetting-lsp-diagnostics-cache.json +1 -1
  169. package/packages/omo-codex/plugin/hooks/post-compact-resetting-project-rule-cache.json +1 -1
  170. package/packages/omo-codex/plugin/hooks/post-tool-use-checking-comments.json +1 -1
  171. package/packages/omo-codex/plugin/hooks/post-tool-use-checking-lsp-diagnostics.json +1 -1
  172. package/packages/omo-codex/plugin/hooks/post-tool-use-checking-thread-title-hygiene.json +1 -1
  173. package/packages/omo-codex/plugin/hooks/post-tool-use-matching-project-rules.json +1 -1
  174. package/packages/omo-codex/plugin/hooks/post-tool-use-recording-spawn-admission.json +1 -1
  175. package/packages/omo-codex/plugin/hooks/pre-tool-use-enforcing-unlimited-goal-budget.json +1 -1
  176. package/packages/omo-codex/plugin/hooks/pre-tool-use-guarding-ulw-loop-spawns.json +1 -1
  177. package/packages/omo-codex/plugin/hooks/pre-tool-use-recommending-git-bash-mcp.json +1 -1
  178. package/packages/omo-codex/plugin/hooks/session-start-checking-auto-update.json +1 -1
  179. package/packages/omo-codex/plugin/hooks/session-start-checking-bootstrap-provisioning.json +1 -1
  180. package/packages/omo-codex/plugin/hooks/session-start-loading-project-rules.json +1 -1
  181. package/packages/omo-codex/plugin/hooks/session-start-recording-session-telemetry.json +1 -1
  182. package/packages/omo-codex/plugin/hooks/stop-checking-ulw-execute-continuation.json +1 -1
  183. package/packages/omo-codex/plugin/hooks/stop-checking-ulw-loop-resume.json +1 -1
  184. package/packages/omo-codex/plugin/hooks/subagent-stop-verifying-lazycodex-executor-evidence.json +1 -1
  185. package/packages/omo-codex/plugin/hooks/user-prompt-submit-checking-ultrawork-trigger.json +1 -1
  186. package/packages/omo-codex/plugin/hooks/user-prompt-submit-checking-ulw-loop-steering.json +1 -1
  187. package/packages/omo-codex/plugin/hooks/user-prompt-submit-loading-project-rules.json +1 -1
  188. package/packages/omo-codex/plugin/package-lock.json +16 -16
  189. package/packages/omo-codex/plugin/package.json +1 -1
  190. package/packages/omo-codex/plugin/shared/package.json +1 -1
  191. package/packages/omo-codex/plugin/skills/ast-grep/README.md +1 -1
  192. package/packages/omo-codex/plugin/skills/ast-grep/install.ps1 +5 -3
  193. package/packages/omo-codex/plugin/skills/ast-grep/install.sh +4 -5
  194. package/packages/omo-codex/plugin/skills/ast-grep/references/install.md +2 -2
  195. package/packages/omo-codex/plugin/skills/ast-grep/scripts/ast_grep_helper.py +13 -3
  196. package/packages/omo-codex/plugin/skills/browser/runtime/omowright/manifest.json +1 -1
  197. package/packages/omo-codex/plugin/skills/coding-agent-sessions/AGENTS.md +5 -4
  198. package/packages/omo-codex/plugin/skills/coding-agent-sessions/SKILL.md +11 -11
  199. package/packages/omo-codex/plugin/skills/coding-agent-sessions/references/all-platforms.md +2 -2
  200. package/packages/omo-codex/plugin/skills/coding-agent-sessions/references/codex.md +4 -4
  201. package/packages/omo-codex/plugin/skills/coding-agent-sessions/scripts/agent_sessions/cli.py +1 -1
  202. package/packages/omo-codex/plugin/skills/coding-agent-sessions/scripts/find-agent-sessions.py +6 -3
  203. package/packages/omo-codex/plugin/skills/frontend/ATTRIBUTION.md +1 -1
  204. package/packages/omo-codex/plugin/skills/frontend/SKILL.md +34 -12
  205. package/packages/omo-codex/plugin/skills/frontend/references/design/README.md +2 -2
  206. package/packages/omo-codex/plugin/skills/frontend/references/design/_INDEX.md +2 -1
  207. package/packages/omo-codex/plugin/skills/frontend/references/design/component-catalogs.md +14 -10
  208. package/packages/omo-codex/plugin/skills/frontend/references/design/design-system-architecture.md +19 -6
  209. package/packages/omo-codex/plugin/skills/frontend/references/design/grounding.md +29 -0
  210. package/packages/omo-codex/plugin/skills/frontend/references/ui-ux-db/scripts/design_system.py +2 -0
  211. package/packages/omo-codex/plugin/skills/frontend/references/ui-ux-db/scripts/search.py +2 -0
  212. package/packages/omo-codex/plugin/skills/lcx-contribute-bug-fix/SKILL.md +51 -55
  213. package/packages/omo-codex/plugin/skills/lcx-contribute-bug-fix/agents/openai.yaml +1 -1
  214. package/packages/omo-codex/plugin/skills/lcx-report-bug/SKILL.md +7 -7
  215. package/packages/omo-codex/plugin/skills/lcx-report-bug/agents/openai.yaml +1 -1
  216. package/packages/omo-codex/plugin/skills/ultimate-browsing/SKILL.md +5 -4
  217. package/packages/omo-codex/plugin/skills/ultimate-browsing/engine/AGENTS.md +2 -2
  218. package/packages/omo-codex/plugin/skills/ultimate-browsing/engine/__main__.py +9 -6
  219. package/packages/omo-codex/plugin/skills/ultimate-browsing/engine/summary.py +1 -1
  220. package/packages/omo-codex/plugin/skills/ultimate-browsing/references/insane-search/README.md +4 -4
  221. package/packages/omo-codex/plugin/skills/ultimate-browsing/scripts/extract_cookies.py +4 -2
  222. package/packages/omo-codex/plugin/skills/ultrawork/SKILL.md +3 -0
  223. package/packages/omo-codex/plugin/skills/ulw-research/AGENTS.md +8 -4
  224. package/packages/omo-codex/plugin/skills/ulw-research/SKILL.md +7 -259
  225. package/packages/omo-codex/plugin/skills/ulw-research/references/deliverable-phase.md +68 -24
  226. package/packages/omo-codex/plugin/skills/ulw-research/references/fact-ledger-grammar.md +7 -3
  227. package/packages/omo-codex/plugin/skills/ulw-research/references/fact-ledger.md +42 -8
  228. package/packages/omo-codex/plugin/skills/ulw-research/references/fidelity-claim-kinds.md +1 -1
  229. package/packages/omo-codex/plugin/skills/ulw-research/references/markdown-blocks.md +12 -0
  230. package/packages/omo-codex/plugin/skills/ulw-research/references/report-gates.md +14 -6
  231. package/packages/omo-codex/plugin/skills/ulw-research/references/research-collection.md +195 -0
  232. package/packages/omo-codex/plugin/skills/ulw-research/references/research-delivery.md +123 -0
  233. package/packages/omo-codex/plugin/skills/ulw-research/scripts/claim-kinds.mjs +33 -5
  234. package/packages/omo-codex/plugin/skills/ulw-research/scripts/contracts.mjs +16 -15
  235. package/packages/omo-codex/plugin/skills/ulw-research/scripts/conversion-probe.mjs +229 -0
  236. package/packages/omo-codex/plugin/skills/ulw-research/scripts/css-hiding.mjs +158 -0
  237. package/packages/omo-codex/plugin/skills/ulw-research/scripts/css-lite.mjs +4 -2
  238. package/packages/omo-codex/plugin/skills/ulw-research/scripts/entities.mjs +13 -4
  239. package/packages/omo-codex/plugin/skills/ulw-research/scripts/fact-commands-fill.mjs +96 -0
  240. package/packages/omo-codex/plugin/skills/ulw-research/scripts/fact-commands-meaning.mjs +26 -30
  241. package/packages/omo-codex/plugin/skills/ulw-research/scripts/fact-commands-polish.mjs +46 -19
  242. package/packages/omo-codex/plugin/skills/ulw-research/scripts/fact-commands-verify.mjs +37 -6
  243. package/packages/omo-codex/plugin/skills/ulw-research/scripts/fact-commands.mjs +40 -62
  244. package/packages/omo-codex/plugin/skills/ulw-research/scripts/fact-derive.mjs +7 -2
  245. package/packages/omo-codex/plugin/skills/ulw-research/scripts/fact-fill.mjs +9 -6
  246. package/packages/omo-codex/plugin/skills/ulw-research/scripts/fact-ledger-kinds.mjs +6 -7
  247. package/packages/omo-codex/plugin/skills/ulw-research/scripts/fact-locate.mjs +15 -9
  248. package/packages/omo-codex/plugin/skills/ulw-research/scripts/fidelity-claims.mjs +4 -3
  249. package/packages/omo-codex/plugin/skills/ulw-research/scripts/fidelity-csv.mjs +32 -0
  250. package/packages/omo-codex/plugin/skills/ulw-research/scripts/fidelity-lexicon.mjs +1 -1
  251. package/packages/omo-codex/plugin/skills/ulw-research/scripts/fidelity-originals.mjs +161 -0
  252. package/packages/omo-codex/plugin/skills/ulw-research/scripts/fidelity-policy.mjs +183 -0
  253. package/packages/omo-codex/plugin/skills/ulw-research/scripts/fidelity-records.mjs +81 -14
  254. package/packages/omo-codex/plugin/skills/ulw-research/scripts/fidelity-snapshot-readability.mjs +49 -0
  255. package/packages/omo-codex/plugin/skills/ulw-research/scripts/fidelity-sources.mjs +76 -0
  256. package/packages/omo-codex/plugin/skills/ulw-research/scripts/fidelity-trace.mjs +25 -11
  257. package/packages/omo-codex/plugin/skills/ulw-research/scripts/fidelity-value-unit.mjs +202 -0
  258. package/packages/omo-codex/plugin/skills/ulw-research/scripts/fidelity-values.mjs +40 -39
  259. package/packages/omo-codex/plugin/skills/ulw-research/scripts/gates-fidelity.mjs +8 -6
  260. package/packages/omo-codex/plugin/skills/ulw-research/scripts/gates-static.mjs +10 -1
  261. package/packages/omo-codex/plugin/skills/ulw-research/scripts/html-lite.mjs +6 -2
  262. package/packages/omo-codex/plugin/skills/ulw-research/scripts/html-markup.mjs +2 -2
  263. package/packages/omo-codex/plugin/skills/ulw-research/scripts/html-text-map.mjs +140 -0
  264. package/packages/omo-codex/plugin/skills/ulw-research/scripts/markdown-closers.mjs +126 -0
  265. package/packages/omo-codex/plugin/skills/ulw-research/scripts/md-lite.mjs +1 -1
  266. package/packages/omo-codex/plugin/skills/ulw-research/scripts/number-grammar.mjs +33 -0
  267. package/packages/omo-codex/plugin/skills/ulw-research/scripts/numerals.mjs +18 -7
  268. package/packages/omo-codex/plugin/skills/ulw-research/scripts/outcome-start.mjs +66 -0
  269. package/packages/omo-codex/plugin/skills/ulw-research/scripts/outcome.mjs +11 -22
  270. package/packages/omo-codex/plugin/skills/ulw-research/scripts/placeholder.mjs +18 -6
  271. package/packages/omo-codex/plugin/skills/ulw-research/scripts/polish-apply.mjs +3 -2
  272. package/packages/omo-codex/plugin/skills/ulw-research/scripts/raw-decode.mjs +110 -0
  273. package/packages/omo-codex/plugin/skills/ulw-research/scripts/raw-locator.mjs +47 -0
  274. package/packages/omo-codex/plugin/skills/ulw-research/scripts/report-tools-commands.mjs +1 -1
  275. package/packages/omo-codex/plugin/skills/ulw-research/scripts/report-tools.mjs +7 -1
  276. package/packages/omo-codex/plugin/skills/ulw-research/scripts/source-commands.mjs +87 -29
  277. package/packages/omo-codex/plugin/skills/ulw-research/scripts/source-refresh.mjs +82 -0
  278. package/packages/omo-codex/plugin/skills/ulw-research/scripts/source-snapshot.mjs +73 -69
  279. package/packages/omo-codex/plugin/skills/ulw-research/scripts/source-view.mjs +89 -0
  280. package/packages/omo-codex/plugin/skills/ulw-research/scripts/sources-citation.mjs +203 -0
  281. package/packages/omo-codex/plugin/skills/ulw-research/scripts/units.mjs +14 -3
  282. package/packages/omo-codex/plugin/test/payload-equivalence.test.mjs +6 -4
  283. package/packages/omo-codex/plugin/test/sync-skills.test.mjs +4 -3
  284. package/packages/omo-codex/scripts/install-dist/install-local.mjs +338 -237
  285. package/packages/prompts-core/prompts/ultrawork/codex.md +3 -0
  286. package/packages/shared-skills/skill-source-filter.mjs +6 -2
  287. package/packages/shared-skills/skills/ast-grep/README.md +1 -1
  288. package/packages/shared-skills/skills/ast-grep/install.ps1 +5 -3
  289. package/packages/shared-skills/skills/ast-grep/install.sh +4 -5
  290. package/packages/shared-skills/skills/ast-grep/references/install.md +2 -2
  291. package/packages/shared-skills/skills/ast-grep/scripts/ast_grep_helper.py +13 -3
  292. package/packages/shared-skills/skills/browser/runtime/omowright/manifest.json +1 -1
  293. package/packages/shared-skills/skills/coding-agent-sessions/AGENTS.md +5 -4
  294. package/packages/shared-skills/skills/coding-agent-sessions/SKILL.md +11 -11
  295. package/packages/shared-skills/skills/coding-agent-sessions/references/all-platforms.md +2 -2
  296. package/packages/shared-skills/skills/coding-agent-sessions/references/codex.md +4 -4
  297. package/packages/shared-skills/skills/coding-agent-sessions/scripts/agent_sessions/cli.py +1 -1
  298. package/packages/shared-skills/skills/coding-agent-sessions/scripts/find-agent-sessions.py +6 -3
  299. package/packages/shared-skills/skills/frontend/ATTRIBUTION.md +1 -1
  300. package/packages/shared-skills/skills/frontend/SKILL.md +34 -12
  301. package/packages/shared-skills/skills/frontend/references/design/README.md +2 -2
  302. package/packages/shared-skills/skills/frontend/references/design/_INDEX.md +2 -1
  303. package/packages/shared-skills/skills/frontend/references/design/component-catalogs.md +14 -10
  304. package/packages/shared-skills/skills/frontend/references/design/design-system-architecture.md +19 -6
  305. package/packages/shared-skills/skills/frontend/references/design/grounding.md +29 -0
  306. package/packages/shared-skills/skills/frontend/references/ui-ux-db/scripts/design_system.py +2 -0
  307. package/packages/shared-skills/skills/frontend/references/ui-ux-db/scripts/search.py +2 -0
  308. package/packages/shared-skills/skills/ultimate-browsing/SKILL.md +5 -4
  309. package/packages/shared-skills/skills/ultimate-browsing/engine/AGENTS.md +2 -2
  310. package/packages/shared-skills/skills/ultimate-browsing/engine/__main__.py +9 -6
  311. package/packages/shared-skills/skills/ultimate-browsing/engine/summary.py +1 -1
  312. package/packages/shared-skills/skills/ultimate-browsing/references/insane-search/README.md +4 -4
  313. package/packages/shared-skills/skills/ultimate-browsing/scripts/extract_cookies.py +4 -2
  314. package/packages/shared-skills/skills/ulw-research/AGENTS.md +8 -4
  315. package/packages/shared-skills/skills/ulw-research/SKILL.md +7 -259
  316. package/packages/shared-skills/skills/ulw-research/references/deliverable-phase.md +68 -24
  317. package/packages/shared-skills/skills/ulw-research/references/fact-ledger-grammar.md +7 -3
  318. package/packages/shared-skills/skills/ulw-research/references/fact-ledger.md +42 -8
  319. package/packages/shared-skills/skills/ulw-research/references/fidelity-claim-kinds.md +1 -1
  320. package/packages/shared-skills/skills/ulw-research/references/markdown-blocks.md +12 -0
  321. package/packages/shared-skills/skills/ulw-research/references/report-gates.md +14 -6
  322. package/packages/shared-skills/skills/ulw-research/references/research-collection.md +195 -0
  323. package/packages/shared-skills/skills/ulw-research/references/research-delivery.md +123 -0
  324. package/packages/shared-skills/skills/ulw-research/scripts/claim-kinds.mjs +33 -5
  325. package/packages/shared-skills/skills/ulw-research/scripts/claim-kinds.test.ts +37 -2
  326. package/packages/shared-skills/skills/ulw-research/scripts/claim-prefix.test.ts +76 -0
  327. package/packages/shared-skills/skills/ulw-research/scripts/contracts-validation.test.ts +83 -0
  328. package/packages/shared-skills/skills/ulw-research/scripts/contracts.mjs +16 -15
  329. package/packages/shared-skills/skills/ulw-research/scripts/contracts.test.ts +6 -109
  330. package/packages/shared-skills/skills/ulw-research/scripts/conversion-altered.test.ts +154 -0
  331. package/packages/shared-skills/skills/ulw-research/scripts/conversion-originals.test.ts +297 -0
  332. package/packages/shared-skills/skills/ulw-research/scripts/conversion-probe-classes.test.ts +361 -0
  333. package/packages/shared-skills/skills/ulw-research/scripts/conversion-probe.mjs +229 -0
  334. package/packages/shared-skills/skills/ulw-research/scripts/conversion-probe.test.ts +218 -0
  335. package/packages/shared-skills/skills/ulw-research/scripts/copy-returns-fidelity-policy.test.ts +156 -0
  336. package/packages/shared-skills/skills/ulw-research/scripts/copy-returns-polish.test.ts +10 -9
  337. package/packages/shared-skills/skills/ulw-research/scripts/css-hiding.mjs +158 -0
  338. package/packages/shared-skills/skills/ulw-research/scripts/css-lite.mjs +4 -2
  339. package/packages/shared-skills/skills/ulw-research/scripts/delivery-barrier-meaning.test.ts +186 -0
  340. package/packages/shared-skills/skills/ulw-research/scripts/delivery-barrier.test.ts +40 -87
  341. package/packages/shared-skills/skills/ulw-research/scripts/entities.mjs +13 -4
  342. package/packages/shared-skills/skills/ulw-research/scripts/fact-commands-fill.mjs +96 -0
  343. package/packages/shared-skills/skills/ulw-research/scripts/fact-commands-meaning.mjs +26 -30
  344. package/packages/shared-skills/skills/ulw-research/scripts/fact-commands-polish.mjs +46 -19
  345. package/packages/shared-skills/skills/ulw-research/scripts/fact-commands-verify.mjs +37 -6
  346. package/packages/shared-skills/skills/ulw-research/scripts/fact-commands.mjs +40 -62
  347. package/packages/shared-skills/skills/ulw-research/scripts/fact-derive-2.test.ts +149 -0
  348. package/packages/shared-skills/skills/ulw-research/scripts/fact-derive.mjs +7 -2
  349. package/packages/shared-skills/skills/ulw-research/scripts/fact-derive.test.ts +7 -192
  350. package/packages/shared-skills/skills/ulw-research/scripts/fact-fill.mjs +9 -6
  351. package/packages/shared-skills/skills/ulw-research/scripts/fact-ledger-kinds.mjs +6 -7
  352. package/packages/shared-skills/skills/ulw-research/scripts/fact-ledger-kinds.test.ts +2 -1
  353. package/packages/shared-skills/skills/ulw-research/scripts/fact-ledger-legacy.test.ts +2 -1
  354. package/packages/shared-skills/skills/ulw-research/scripts/fact-locate.mjs +15 -9
  355. package/packages/shared-skills/skills/ulw-research/scripts/fact-unit-dimensions-2.test.ts +149 -0
  356. package/packages/shared-skills/skills/ulw-research/scripts/fact-unit-dimensions.test.ts +4 -168
  357. package/packages/shared-skills/skills/ulw-research/scripts/fact-unit-rules.test.ts +3 -229
  358. package/packages/shared-skills/skills/ulw-research/scripts/fidelity-claims.mjs +4 -3
  359. package/packages/shared-skills/skills/ulw-research/scripts/fidelity-csv.mjs +32 -0
  360. package/packages/shared-skills/skills/ulw-research/scripts/fidelity-lexicon.mjs +1 -1
  361. package/packages/shared-skills/skills/ulw-research/scripts/fidelity-originals.mjs +161 -0
  362. package/packages/shared-skills/skills/ulw-research/scripts/fidelity-policy.mjs +183 -0
  363. package/packages/shared-skills/skills/ulw-research/scripts/fidelity-records.mjs +81 -14
  364. package/packages/shared-skills/skills/ulw-research/scripts/fidelity-snapshot-readability.mjs +49 -0
  365. package/packages/shared-skills/skills/ulw-research/scripts/fidelity-sources.mjs +76 -0
  366. package/packages/shared-skills/skills/ulw-research/scripts/fidelity-trace.mjs +25 -11
  367. package/packages/shared-skills/skills/ulw-research/scripts/fidelity-value-unit.mjs +202 -0
  368. package/packages/shared-skills/skills/ulw-research/scripts/fidelity-values.mjs +40 -39
  369. package/packages/shared-skills/skills/ulw-research/scripts/fidelity-values.test.ts +8 -29
  370. package/packages/shared-skills/skills/ulw-research/scripts/gates-fidelity.mjs +8 -6
  371. package/packages/shared-skills/skills/ulw-research/scripts/gates-static-headings.test.ts +17 -0
  372. package/packages/shared-skills/skills/ulw-research/scripts/gates-static.mjs +10 -1
  373. package/packages/shared-skills/skills/ulw-research/scripts/html-lite.mjs +6 -2
  374. package/packages/shared-skills/skills/ulw-research/scripts/html-markup.mjs +2 -2
  375. package/packages/shared-skills/skills/ulw-research/scripts/html-text-map.mjs +140 -0
  376. package/packages/shared-skills/skills/ulw-research/scripts/html-text-map.test.ts +148 -0
  377. package/packages/shared-skills/skills/ulw-research/scripts/markdown-closers.mjs +126 -0
  378. package/packages/shared-skills/skills/ulw-research/scripts/md-lite-boundaries.test.ts +46 -0
  379. package/packages/shared-skills/skills/ulw-research/scripts/md-lite.mjs +1 -1
  380. package/packages/shared-skills/skills/ulw-research/scripts/number-grammar.mjs +33 -0
  381. package/packages/shared-skills/skills/ulw-research/scripts/number-grammar.test.ts +36 -0
  382. package/packages/shared-skills/skills/ulw-research/scripts/numerals.mjs +18 -7
  383. package/packages/shared-skills/skills/ulw-research/scripts/numerals.test.ts +3 -0
  384. package/packages/shared-skills/skills/ulw-research/scripts/outcome-start.mjs +66 -0
  385. package/packages/shared-skills/skills/ulw-research/scripts/outcome-start.test.ts +109 -0
  386. package/packages/shared-skills/skills/ulw-research/scripts/outcome.mjs +11 -22
  387. package/packages/shared-skills/skills/ulw-research/scripts/page-source-locator.test.ts +187 -0
  388. package/packages/shared-skills/skills/ulw-research/scripts/placeholder.mjs +18 -6
  389. package/packages/shared-skills/skills/ulw-research/scripts/polish-apply.mjs +3 -2
  390. package/packages/shared-skills/skills/ulw-research/scripts/polish-markup.test.ts +15 -1
  391. package/packages/shared-skills/skills/ulw-research/scripts/polish-partial.test.ts +42 -0
  392. package/packages/shared-skills/skills/ulw-research/scripts/raw-decode.mjs +110 -0
  393. package/packages/shared-skills/skills/ulw-research/scripts/raw-locator.mjs +47 -0
  394. package/packages/shared-skills/skills/ulw-research/scripts/raw-snapshot.test.ts +139 -0
  395. package/packages/shared-skills/skills/ulw-research/scripts/report-tools-2.test.ts +233 -0
  396. package/packages/shared-skills/skills/ulw-research/scripts/report-tools-3.test.ts +141 -0
  397. package/packages/shared-skills/skills/ulw-research/scripts/report-tools-4.test.ts +135 -0
  398. package/packages/shared-skills/skills/ulw-research/scripts/report-tools-5.test.ts +231 -0
  399. package/packages/shared-skills/skills/ulw-research/scripts/report-tools-commands.mjs +1 -1
  400. package/packages/shared-skills/skills/ulw-research/scripts/report-tools.mjs +7 -1
  401. package/packages/shared-skills/skills/ulw-research/scripts/report-tools.test.ts +6 -560
  402. package/packages/shared-skills/skills/ulw-research/scripts/snapshot-readability.test.ts +116 -0
  403. package/packages/shared-skills/skills/ulw-research/scripts/source-commands.mjs +87 -29
  404. package/packages/shared-skills/skills/ulw-research/scripts/source-integrity.test.ts +243 -0
  405. package/packages/shared-skills/skills/ulw-research/scripts/source-refresh.mjs +82 -0
  406. package/packages/shared-skills/skills/ulw-research/scripts/source-snapshot.mjs +73 -69
  407. package/packages/shared-skills/skills/ulw-research/scripts/source-snapshot.test.ts +7 -4
  408. package/packages/shared-skills/skills/ulw-research/scripts/source-view.mjs +89 -0
  409. package/packages/shared-skills/skills/ulw-research/scripts/sources-citation.mjs +203 -0
  410. package/packages/shared-skills/skills/ulw-research/scripts/sources-citation.test.ts +236 -0
  411. package/packages/shared-skills/skills/ulw-research/scripts/tests/contracts-support.ts +147 -0
  412. package/packages/shared-skills/skills/ulw-research/scripts/tests/delivery-barrier-session.ts +59 -0
  413. package/packages/shared-skills/skills/ulw-research/scripts/tests/derive-clock.ts +4 -0
  414. package/packages/shared-skills/skills/ulw-research/scripts/tests/fact-derive-support.ts +65 -0
  415. package/packages/shared-skills/skills/ulw-research/scripts/tests/fact-unit-dimensions-support.ts +41 -0
  416. package/packages/shared-skills/skills/ulw-research/scripts/tests/fact-unit-rules-support.ts +241 -0
  417. package/packages/shared-skills/skills/ulw-research/scripts/tests/fidelity-values-support.ts +30 -0
  418. package/packages/shared-skills/skills/ulw-research/scripts/tests/fixtures/conversion-probe.html +14 -0
  419. package/packages/shared-skills/skills/ulw-research/scripts/tests/fixtures/sources-shapes.html +20 -0
  420. package/packages/shared-skills/skills/ulw-research/scripts/tests/numeral-classes.ts +196 -0
  421. package/packages/shared-skills/skills/ulw-research/scripts/tests/report-tools-support.ts +182 -0
  422. package/packages/shared-skills/skills/ulw-research/scripts/tests/value-mode-support.ts +48 -0
  423. package/packages/shared-skills/skills/ulw-research/scripts/units.mjs +14 -3
  424. package/packages/shared-skills/skills/ulw-research/scripts/units.test.ts +10 -0
  425. package/packages/shared-skills/skills/ulw-research/scripts/value-mode-unit-classes.test.ts +255 -0
  426. package/packages/shared-skills/skills/ulw-research/scripts/value-mode-unit.test.ts +179 -0
  427. package/packages/shared-skills/skills/ulw-research/scripts/value-rules-cli.test.ts +157 -0
  428. package/packages/shared-skills/skills/ulw-research/scripts/value-rules-followups.test.ts +72 -0
  429. package/packages/shared-skills/skills/ulw-research/scripts/value-rules-priority.test.ts +80 -0
  430. package/packages/omo-codex/plugin/skills/ultimate-browsing/engine/tests/fixtures/amp_redirect_stub.html +0 -7
  431. package/packages/omo-codex/plugin/skills/ultimate-browsing/engine/tests/fixtures/search_interstitial.html +0 -19
  432. package/packages/omo-codex/plugin/skills/ultimate-browsing/engine/tests/fixtures/wayback_available.json +0 -1
  433. package/packages/omo-codex/plugin/skills/ultimate-browsing/engine/tests/fixtures/wayback_snapshot.html +0 -1128
  434. package/packages/omo-codex/plugin/skills/ultimate-browsing/engine/tests/test_fetch_chain.py +0 -77
  435. package/packages/omo-codex/plugin/skills/ultimate-browsing/engine/tests/test_playwright_stealth.py +0 -86
  436. package/packages/omo-codex/plugin/skills/ultimate-browsing/engine/tests/test_playwright_templates.py +0 -279
  437. package/packages/omo-codex/plugin/skills/ultimate-browsing/engine/tests/test_surrogate.py +0 -252
  438. package/packages/omo-codex/plugin/skills/ultimate-browsing/engine/tests/test_surrogate_validators.py +0 -78
@@ -0,0 +1,113 @@
1
+ import { afterEach, describe, expect, it } from "bun:test";
2
+ import { join } from "node:path";
3
+
4
+ import { __resetBunCommandProbeCacheForTests } from "../lsp/bun-project-checks.js";
5
+ import { createFakeBun, createProject, type FakeBun, removeFakeBunFixtures } from "../lsp/fake-bun-test-support.js";
6
+ import { createStandaloneMcpRequestContext, runWithRequestContext } from "../request-context.js";
7
+ import { runBunDirectoryDiagnostics } from "./bun-directory-diagnostics.js";
8
+ import { executeLspDiagnostics } from "./diagnostics.js";
9
+ import type { LspDiagnosticsDetails } from "./types.js";
10
+
11
+ afterEach(() => {
12
+ __resetBunCommandProbeCacheForTests();
13
+ removeFakeBunFixtures();
14
+ });
15
+
16
+ const CHECK_ERROR = "src/x.ts(1,7): error TS2322: Type 'string' is not assignable to type 'number'.\n";
17
+ const LINT_REPORT = (root: string) =>
18
+ JSON.stringify([{ filePath: join(root, "src", "x.ts"), messages: [{ ruleId: "prefer-const", severity: 2, message: "Use const", line: 1, column: 1 }] }]);
19
+
20
+ function diagnose(root: string, bun: FakeBun) {
21
+ return runWithRequestContext(createStandaloneMcpRequestContext({ cwd: root }), () =>
22
+ executeLspDiagnostics({ filePath: root, severity: "all" }, undefined, { resolveBun: () => bun.path }),
23
+ );
24
+ }
25
+
26
+ function commandsRun(bun: FakeBun): string[] {
27
+ return bun.calls().map((call) => call.args.join(" "));
28
+ }
29
+
30
+ describe("lsp_diagnostics on a directory of a Bun project", () => {
31
+ it("#given a Bun project and a bun with check #when diagnosed #then bun check is the typecheck", async () => {
32
+ const root = createProject({ "bun.lock": "", "src/x.ts": 'const n: number = "s";\n' });
33
+ const bun = createFakeBun({ commands: ["check"], checkStdout: CHECK_ERROR, checkExitCode: 1 });
34
+
35
+ const result = await diagnose(root, bun);
36
+ const details = result.details as LspDiagnosticsDetails;
37
+
38
+ expect(result.content[0]?.text).toContain("Typecheck: bun check");
39
+ expect(result.content[0]?.text).toContain(`${join(root, "src", "x.ts")}: error[bun check] (TS2322) at 1:6:`);
40
+ expect(details.totalDiagnostics).toBe(1);
41
+ expect(details.projectCommands).toEqual(["bun check"]);
42
+ expect(commandsRun(bun)).toEqual(["check --help", "check --no-pretty .", "lint --help"]);
43
+ });
44
+
45
+ it("#given a bun without lint #when diagnosed #then lint is neither run nor reported", async () => {
46
+ const root = createProject({ "bun.lock": "", "src/x.ts": "" });
47
+ const bun = createFakeBun({ commands: ["check"] });
48
+
49
+ const result = await diagnose(root, bun);
50
+
51
+ expect(result.content[0]?.text).not.toContain("Lint:");
52
+ expect(commandsRun(bun)).not.toContain("lint -f json .");
53
+ });
54
+
55
+ it("#given a bun with lint #when diagnosed #then bun lint diagnostics join the typecheck", async () => {
56
+ const root = createProject({ "bun.lock": "", "src/x.ts": "let a = 1\n" });
57
+ const bun = createFakeBun({ commands: ["check", "lint"], lintStdout: LINT_REPORT(root), lintExitCode: 1 });
58
+
59
+ const result = await diagnose(root, bun);
60
+ const details = result.details as LspDiagnosticsDetails;
61
+
62
+ expect(result.content[0]?.text).toContain("Lint: bun lint");
63
+ expect(result.content[0]?.text).toContain("error[bun lint] (prefer-const) at 1:0: Use const");
64
+ expect(details.projectCommands).toEqual(["bun check", "bun lint"]);
65
+ expect(commandsRun(bun)).toContain("lint -f json .");
66
+ });
67
+
68
+ it("#given a bun lint that cannot lint #when diagnosed #then the typecheck stands and the lint failure is named", async () => {
69
+ const root = createProject({ "bun.lock": "", "src/x.ts": "" });
70
+ const bun = createFakeBun({ commands: ["check", "lint"], lintStdout: "", lintExitCode: 2 });
71
+
72
+ const result = await diagnose(root, bun);
73
+
74
+ expect(result.content[0]?.text).toContain("Typecheck: bun check");
75
+ expect(result.content[0]?.text).toContain("Lint: bun lint could not lint (exit 2)");
76
+ });
77
+ });
78
+
79
+ describe("fallback to the language server path", () => {
80
+ it("#given a non-Bun project #when the Bun path is consulted #then it declines without running bun", async () => {
81
+ const root = createProject({ "package.json": "{}", "src/x.ts": "" });
82
+ const bun = createFakeBun({ commands: ["check", "lint"] });
83
+
84
+ expect(await runBunDirectoryDiagnostics(root, ".ts", "all", undefined, { resolveBun: () => bun.path })).toBeUndefined();
85
+ expect(bun.calls()).toEqual([]);
86
+ });
87
+
88
+ it("#given a project script named check #when the Bun path is consulted #then it declines without running bun check", async () => {
89
+ const root = createProject({ "bun.lock": "", "package.json": '{"scripts":{"check":"tsc --noEmit"}}', "src/x.ts": "" });
90
+ const bun = createFakeBun({ commands: ["check"] });
91
+
92
+ expect(await runBunDirectoryDiagnostics(root, ".ts", "all", undefined, { resolveBun: () => bun.path })).toBeUndefined();
93
+ expect(bun.calls()).toEqual([]);
94
+ });
95
+
96
+ it("#given a bun without check, or a bun check that fails to run #when consulted #then it declines", async () => {
97
+ const root = createProject({ "bun.lock": "", "src/x.ts": "" });
98
+ const old = createFakeBun({ commands: [] });
99
+ const broken = createFakeBun({ commands: ["check"], checkStdout: "error: tsconfig.json not found\n", checkExitCode: 1 });
100
+
101
+ expect(await runBunDirectoryDiagnostics(root, ".ts", "all", undefined, { resolveBun: () => old.path })).toBeUndefined();
102
+ expect(await runBunDirectoryDiagnostics(root, ".ts", "all", undefined, { resolveBun: () => broken.path })).toBeUndefined();
103
+ });
104
+
105
+ it("#given a JavaScript directory #when consulted #then the Bun typecheck path is not used", async () => {
106
+ const root = createProject({ "bun.lock": "", "src/x.js": "" });
107
+ const bun = createFakeBun({ commands: ["check"] });
108
+
109
+ expect(await runBunDirectoryDiagnostics(root, ".js", "all", undefined, { resolveBun: () => bun.path })).toBeUndefined();
110
+ expect(bun.calls()).toEqual([]);
111
+ });
112
+ });
113
+
@@ -0,0 +1,75 @@
1
+ import { parseBunCheckOutput, parseBunLintJson, type FileDiagnostic } from "../lsp/bun-command-output.js";
2
+ import { type BunProjectChecksOptions, resolveBunProjectCommand, runBunCommand } from "../lsp/bun-project-checks.js";
3
+ import { DEFAULT_MAX_DIAGNOSTICS } from "../lsp/constants.js";
4
+ import { filterDiagnosticsBySeverity, formatDiagnostic } from "../lsp/formatters.js";
5
+ import type { SeverityFilter } from "../lsp/types.js";
6
+
7
+ const TYPESCRIPT_EXTENSIONS = new Set([".ts", ".tsx", ".mts", ".cts"]);
8
+
9
+ export interface BunDirectoryDiagnostics {
10
+ readonly output: string;
11
+ readonly diagnostics: readonly FileDiagnostic[];
12
+ readonly projectCommands: readonly string[];
13
+ }
14
+
15
+ export async function runBunDirectoryDiagnostics(
16
+ absDir: string,
17
+ extension: string,
18
+ severity: SeverityFilter | undefined,
19
+ signal: AbortSignal | undefined,
20
+ options: BunProjectChecksOptions = {},
21
+ ): Promise<BunDirectoryDiagnostics | undefined> {
22
+ if (!TYPESCRIPT_EXTENSIONS.has(extension)) return undefined;
23
+ const checkBun = await resolveBunProjectCommand("check", absDir, options);
24
+ if (checkBun === undefined) return undefined;
25
+
26
+ let typecheck: FileDiagnostic[];
27
+ try {
28
+ const run = await runBunCommand(checkBun, ["check", "--no-pretty", "."], absDir, signal);
29
+ typecheck = parseBunCheckOutput(run.stdout, absDir);
30
+ const failedWithoutDiagnostics = run.exitCode === 1 && typecheck.length === 0;
31
+ if ((run.exitCode !== 0 && run.exitCode !== 1) || failedWithoutDiagnostics) return undefined;
32
+ } catch (error) {
33
+ if (signal?.aborted) throw error;
34
+ return undefined;
35
+ }
36
+
37
+ const header = [`Directory: ${absDir}`, "Typecheck: bun check (files in this directory and everything they import)"];
38
+ const projectCommands = ["bun check"];
39
+ const collected = [...typecheck];
40
+ const lintBun = await resolveBunProjectCommand("lint", absDir, options);
41
+ if (lintBun !== undefined) {
42
+ const lint = await runBunLint(lintBun, absDir, signal);
43
+ header.push(lint.status);
44
+ projectCommands.push("bun lint");
45
+ collected.push(...lint.diagnostics);
46
+ }
47
+
48
+ const diagnostics = collected.filter(({ diagnostic }) => filterDiagnosticsBySeverity([diagnostic], severity).length > 0);
49
+ const lines = [...header, `Total diagnostics: ${diagnostics.length}`];
50
+ const shown = diagnostics.slice(0, DEFAULT_MAX_DIAGNOSTICS);
51
+ if (shown.length > 0) {
52
+ lines.push("", ...shown.map(({ file, diagnostic }) => `${file}: ${formatDiagnostic(diagnostic)}`));
53
+ if (diagnostics.length > shown.length) {
54
+ lines.push("", `... (${diagnostics.length - shown.length} more diagnostics not shown)`);
55
+ }
56
+ }
57
+ return { output: lines.join("\n"), diagnostics, projectCommands };
58
+ }
59
+
60
+ async function runBunLint(
61
+ bunPath: string,
62
+ absDir: string,
63
+ signal: AbortSignal | undefined,
64
+ ): Promise<{ status: string; diagnostics: FileDiagnostic[] }> {
65
+ try {
66
+ const run = await runBunCommand(bunPath, ["lint", "-f", "json", "."], absDir, signal);
67
+ const diagnostics = run.exitCode === 0 || run.exitCode === 1 ? parseBunLintJson(run.stdout) : undefined;
68
+ if (diagnostics !== undefined) return { status: "Lint: bun lint", diagnostics };
69
+ const reason = run.stderr.trim().split(/\r?\n/)[0] ?? "";
70
+ return { status: `Lint: bun lint could not lint (exit ${run.exitCode ?? "signal"})${reason ? `: ${reason}` : ""}`, diagnostics: [] };
71
+ } catch (error) {
72
+ if (signal?.aborted) throw error;
73
+ return { status: `Lint: bun lint could not run: ${error instanceof Error ? error.message : String(error)}`, diagnostics: [] };
74
+ }
75
+ }
@@ -0,0 +1,156 @@
1
+ import { executeLspDiagnostics } from "./diagnostics.js";
2
+ import { executeLspFormat } from "./format.js";
3
+ import { executeLspInstallDecision } from "./install-decision.js";
4
+ import { executeLspFindReferences, executeLspGotoDefinition } from "./navigation.js";
5
+ import { executeLspPrepareRename, executeLspRename } from "./rename.js";
6
+ import { objectSchema } from "./schema.js";
7
+ import { executeLspStatus } from "./status.js";
8
+ import { executeLspSymbols } from "./symbols.js";
9
+ import type { LspMcpTool } from "./types.js";
10
+
11
+ export const LSP_MCP_TOOLS: LspMcpTool[] = [
12
+ {
13
+ name: "status",
14
+ aliases: ["lsp_status"],
15
+ title: "LSP Status",
16
+ description: "List configured and active LSP servers without starting a new language server.",
17
+ inputSchema: objectSchema({}),
18
+ execute: executeLspStatus,
19
+ },
20
+ {
21
+ name: "diagnostics",
22
+ aliases: ["lsp_diagnostics"],
23
+ title: "LSP Diagnostics",
24
+ description:
25
+ "Get errors, warnings, and hints for a source file or directory. In a Bun project, a TypeScript directory is typechecked with `bun check`, plus `bun lint` when the installed Bun has it.",
26
+ inputSchema: objectSchema(
27
+ {
28
+ filePath: { type: "string", description: "File or directory path to check." },
29
+ severity: {
30
+ type: "string",
31
+ enum: ["error", "warning", "information", "hint", "all"],
32
+ description: "Severity filter. Defaults to all.",
33
+ },
34
+ },
35
+ ["filePath"],
36
+ ),
37
+ execute: executeLspDiagnostics,
38
+ },
39
+ {
40
+ name: "goto_definition",
41
+ aliases: ["lsp_goto_definition"],
42
+ title: "LSP Goto Definition",
43
+ description: "Find where a symbol is defined.",
44
+ inputSchema: objectSchema(
45
+ {
46
+ filePath: { type: "string", description: "Source file containing the symbol." },
47
+ line: { type: "number", description: "1-based line number." },
48
+ character: { type: "number", description: "0-based column." },
49
+ },
50
+ ["filePath", "line", "character"],
51
+ ),
52
+ execute: executeLspGotoDefinition,
53
+ },
54
+ {
55
+ name: "find_references",
56
+ aliases: ["lsp_find_references"],
57
+ title: "LSP Find References",
58
+ description: "Find references of a symbol across the workspace.",
59
+ inputSchema: objectSchema(
60
+ {
61
+ filePath: { type: "string", description: "Source file containing the symbol." },
62
+ line: { type: "number", description: "1-based line number." },
63
+ character: { type: "number", description: "0-based column." },
64
+ includeDeclaration: { type: "boolean", description: "Include the declaration. Defaults to true." },
65
+ },
66
+ ["filePath", "line", "character"],
67
+ ),
68
+ execute: executeLspFindReferences,
69
+ },
70
+ {
71
+ name: "symbols",
72
+ aliases: ["lsp_symbols"],
73
+ title: "LSP Symbols",
74
+ description: "List document symbols or search workspace symbols.",
75
+ inputSchema: objectSchema(
76
+ {
77
+ filePath: { type: "string", description: "File path used as LSP context." },
78
+ scope: {
79
+ type: "string",
80
+ enum: ["document", "workspace"],
81
+ description: "Use document for file outline or workspace for project-wide search.",
82
+ },
83
+ query: { type: "string", description: "Workspace symbol query." },
84
+ limit: { type: "number", description: "Maximum number of symbols to return." },
85
+ },
86
+ ["filePath", "scope"],
87
+ ),
88
+ execute: executeLspSymbols,
89
+ },
90
+ {
91
+ name: "prepare_rename",
92
+ aliases: ["lsp_prepare_rename"],
93
+ title: "LSP Prepare Rename",
94
+ description: "Check whether a symbol can be renamed at a position.",
95
+ inputSchema: objectSchema(
96
+ {
97
+ filePath: { type: "string", description: "Source file path." },
98
+ line: { type: "number", description: "1-based line number." },
99
+ character: { type: "number", description: "0-based column." },
100
+ },
101
+ ["filePath", "line", "character"],
102
+ ),
103
+ execute: executeLspPrepareRename,
104
+ },
105
+ {
106
+ name: "rename",
107
+ aliases: ["lsp_rename"],
108
+ title: "LSP Rename",
109
+ description: "Rename a symbol across the workspace and apply the returned workspace edit.",
110
+ inputSchema: objectSchema(
111
+ {
112
+ filePath: { type: "string", description: "Source file path." },
113
+ line: { type: "number", description: "1-based line number." },
114
+ character: { type: "number", description: "0-based column." },
115
+ newName: { type: "string", description: "New symbol name." },
116
+ },
117
+ ["filePath", "line", "character", "newName"],
118
+ ),
119
+ execute: executeLspRename,
120
+ },
121
+ {
122
+ name: "format",
123
+ aliases: ["lsp_format"],
124
+ title: "LSP Format",
125
+ description: "Format a source file with its language server and write the returned edits to disk.",
126
+ inputSchema: objectSchema(
127
+ {
128
+ filePath: { type: "string", description: "Source file path to format." },
129
+ },
130
+ ["filePath"],
131
+ ),
132
+ execute: executeLspFormat,
133
+ },
134
+ {
135
+ name: "install_decision",
136
+ aliases: ["lsp_install_decision"],
137
+ title: "LSP Install Decision",
138
+ description:
139
+ "Record whether the user allowed or declined installing a missing LSP server. Record 'declined' when the user declines, or has not explicitly asked for LSP installation, to silence future prompts.",
140
+ inputSchema: objectSchema(
141
+ {
142
+ server_id: {
143
+ type: "string",
144
+ description: "The LSP server id from the not-installed message (e.g. 'rust').",
145
+ },
146
+ decision: {
147
+ type: "string",
148
+ enum: ["declined", "allowed"],
149
+ description: "'declined' silences future prompts; 'allowed' pre-authorizes installation.",
150
+ },
151
+ },
152
+ ["server_id", "decision"],
153
+ ),
154
+ execute: executeLspInstallDecision,
155
+ },
156
+ ];
@@ -0,0 +1,133 @@
1
+ import { isDirectoryPath, resolveReadablePathInsideContext, withLspClient } from "../lsp/client-wrapper.js";
2
+ import { DEFAULT_MAX_DIAGNOSTICS } from "../lsp/constants.js";
3
+ import type { BunProjectChecksOptions } from "../lsp/bun-project-checks.js";
4
+ import { aggregateDiagnosticsForDirectory } from "../lsp/directory-diagnostics.js";
5
+ import { filterDiagnosticsBySeverity, formatDiagnostic } from "../lsp/formatters.js";
6
+ import { inferExtensionFromDirectory } from "../lsp/infer-extension.js";
7
+ import type { Diagnostic } from "../lsp/types.js";
8
+ import { missingDependencyResult } from "../missing-dependency-result.js";
9
+ import { runBunDirectoryDiagnostics } from "./bun-directory-diagnostics.js";
10
+ import { clientOptions, requireString, severityFilter } from "./parameters.js";
11
+ import { text } from "./result.js";
12
+ import type { LspDiagnosticsDetails, ToolExecutionResult } from "./types.js";
13
+
14
+ function asDiagnosticArray(result: { items?: Diagnostic[] } | Diagnostic[] | null | undefined): Diagnostic[] {
15
+ if (!result) return [];
16
+ if (Array.isArray(result)) return result;
17
+ return result.items ?? [];
18
+ }
19
+
20
+ export async function executeLspDiagnostics(
21
+ params: Record<string, unknown>,
22
+ signal?: AbortSignal,
23
+ bunOptions: BunProjectChecksOptions = {},
24
+ ): Promise<ToolExecutionResult> {
25
+ const filePath = requireString(params, "filePath");
26
+ const severity = severityFilter(params);
27
+
28
+ try {
29
+ const absPath = resolveReadablePathInsideContext(filePath);
30
+ if (isDirectoryPath(absPath)) {
31
+ const extension = inferExtensionFromDirectory(absPath);
32
+ if (!extension) {
33
+ const message = `No supported source files found in directory: ${absPath}`;
34
+ const details: LspDiagnosticsDetails = {
35
+ filePath,
36
+ severity,
37
+ mode: "directory",
38
+ diagnostics: [],
39
+ totalDiagnostics: 0,
40
+ truncated: false,
41
+ error: message,
42
+ errorKind: "no_files",
43
+ };
44
+ return text(message, details);
45
+ }
46
+
47
+ const bun = await runBunDirectoryDiagnostics(absPath, extension, severity, signal, bunOptions);
48
+ if (bun !== undefined) {
49
+ const details: LspDiagnosticsDetails = {
50
+ filePath,
51
+ severity,
52
+ mode: "directory",
53
+ diagnostics: [...bun.diagnostics],
54
+ totalDiagnostics: bun.diagnostics.length,
55
+ truncated: bun.diagnostics.length > DEFAULT_MAX_DIAGNOSTICS,
56
+ projectCommands: [...bun.projectCommands],
57
+ };
58
+ return text(bun.output, details);
59
+ }
60
+
61
+ const output = await aggregateDiagnosticsForDirectory(
62
+ absPath,
63
+ extension,
64
+ severity,
65
+ undefined,
66
+ signal === undefined ? {} : { signal },
67
+ );
68
+ const details: LspDiagnosticsDetails = {
69
+ filePath,
70
+ severity,
71
+ mode: "directory",
72
+ diagnostics: [],
73
+ totalDiagnostics: output.totalDiagnostics,
74
+ truncated: false,
75
+ fileFailures: [...output.fileFailures],
76
+ };
77
+ return text(output.output, details);
78
+ }
79
+
80
+ const result = await withLspClient(
81
+ filePath,
82
+ async (client, _workspaceRoot, resolvedFilePath) => client.diagnostics(resolvedFilePath, signal),
83
+ "diagnostics",
84
+ clientOptions(signal),
85
+ );
86
+ if (result.transientError) {
87
+ const message = result.transientError.message;
88
+ const details: LspDiagnosticsDetails = {
89
+ filePath,
90
+ severity,
91
+ mode: "file",
92
+ diagnostics: [],
93
+ totalDiagnostics: 0,
94
+ truncated: false,
95
+ error: message,
96
+ errorKind: result.transientError.kind,
97
+ };
98
+ return text(message, details, true);
99
+ }
100
+
101
+ const diagnostics = filterDiagnosticsBySeverity(asDiagnosticArray(result), severity);
102
+ const total = diagnostics.length;
103
+ const truncated = total > DEFAULT_MAX_DIAGNOSTICS;
104
+ const limited = truncated ? diagnostics.slice(0, DEFAULT_MAX_DIAGNOSTICS) : diagnostics;
105
+ const output =
106
+ total === 0
107
+ ? "No diagnostics found"
108
+ : [
109
+ ...(truncated ? [`Found ${total} diagnostics (showing first ${DEFAULT_MAX_DIAGNOSTICS}):`] : []),
110
+ ...limited.map(formatDiagnostic),
111
+ ].join("\n");
112
+ const details: LspDiagnosticsDetails = {
113
+ filePath,
114
+ severity,
115
+ mode: "file",
116
+ diagnostics: diagnostics.map((diagnostic) => ({ file: absPath, diagnostic })),
117
+ totalDiagnostics: total,
118
+ truncated,
119
+ };
120
+ return text(output, details);
121
+ } catch (error) {
122
+ const missingDependency = missingDependencyResult(error, {
123
+ filePath,
124
+ severity,
125
+ mode: "file",
126
+ diagnostics: [],
127
+ totalDiagnostics: 0,
128
+ truncated: false,
129
+ } satisfies Omit<LspDiagnosticsDetails, "error" | "errorKind">);
130
+ if (missingDependency) return missingDependency;
131
+ throw error;
132
+ }
133
+ }
@@ -0,0 +1,56 @@
1
+ import { mkdtempSync, readFileSync, rmSync, writeFileSync } from "node:fs";
2
+ import { tmpdir } from "node:os";
3
+ import { join } from "node:path";
4
+
5
+ import { afterEach, describe, expect, it } from "bun:test";
6
+
7
+ import { parseLspRequestContext, runWithRequestContext } from "../request-context.js";
8
+ import { executeLspFormat } from "./format.js";
9
+ import type { LspFormatDetails } from "./types.js";
10
+
11
+ const workspaces: string[] = [];
12
+
13
+ afterEach(() => {
14
+ for (const workspace of workspaces.splice(0)) rmSync(workspace, { recursive: true, force: true });
15
+ });
16
+
17
+ function workspaceWith(fileName: string, content: string): { readonly root: string; readonly filePath: string } {
18
+ const root = mkdtempSync(join(tmpdir(), "lsp-format-tool-"));
19
+ workspaces.push(root);
20
+ const filePath = join(root, fileName);
21
+ writeFileSync(filePath, content, "utf-8");
22
+ return { root, filePath };
23
+ }
24
+
25
+ function contextFor(root: string) {
26
+ return parseLspRequestContext({
27
+ cwd: root,
28
+ projectConfigPaths: [join(root, "lsp.json")],
29
+ userConfigPath: join(root, "user-lsp.json"),
30
+ installDecisionsPath: join(root, "install-decisions.json"),
31
+ capabilities: { installDecisionTool: false },
32
+ });
33
+ }
34
+
35
+ describe("executeLspFormat", () => {
36
+ it("#given an extension with no configured server #when format runs #then the missing dependency result is returned and the file is untouched", async () => {
37
+ // given
38
+ const original = "value\n";
39
+ const { root, filePath } = workspaceWith("module.wat", original);
40
+
41
+ // when
42
+ const result = await runWithRequestContext(contextFor(root), () => executeLspFormat({ filePath }));
43
+
44
+ // then
45
+ const details = result.details as LspFormatDetails;
46
+ expect(details.errorKind).toBe("missing_dependency");
47
+ expect(details.status).toBe("unavailable");
48
+ expect(result.content[0]?.text).toContain("No LSP server configured for extension: .wat");
49
+ expect(readFileSync(filePath)).toEqual(Buffer.from(original));
50
+ });
51
+
52
+ it("#given a missing filePath argument #when format runs #then the parameter contract is enforced", async () => {
53
+ // given / when / then
54
+ await expect(executeLspFormat({})).rejects.toThrow(/filePath/);
55
+ });
56
+ });
@@ -0,0 +1,56 @@
1
+ import { withLspClient } from "../lsp/client-wrapper.js";
2
+ import { type FormatDocumentResult, formatDocumentWithClient } from "../lsp/format-document.js";
3
+ import { missingDependencyResult } from "../missing-dependency-result.js";
4
+ import { clientOptions, requireString } from "./parameters.js";
5
+ import { text } from "./result.js";
6
+ import type { LspFormatDetails, ToolExecutionResult } from "./types.js";
7
+
8
+ export async function executeLspFormat(
9
+ params: Record<string, unknown>,
10
+ signal?: AbortSignal,
11
+ ): Promise<ToolExecutionResult> {
12
+ const filePath = requireString(params, "filePath");
13
+
14
+ try {
15
+ const result = await withLspClient(
16
+ filePath,
17
+ async (client, _workspaceRoot, resolvedFilePath) =>
18
+ formatDocumentWithClient(client, resolvedFilePath, signal === undefined ? {} : { signal }),
19
+ "format",
20
+ clientOptions(signal),
21
+ );
22
+ return text(describeResult(filePath, result), formatDetails(filePath, result));
23
+ } catch (error) {
24
+ const missingDependency = missingDependencyResult(error, {
25
+ filePath,
26
+ status: "unavailable",
27
+ reason: "server_unavailable",
28
+ linesAdded: 0,
29
+ linesRemoved: 0,
30
+ } satisfies Omit<LspFormatDetails, "error" | "errorKind">);
31
+ if (missingDependency) return missingDependency;
32
+ throw error;
33
+ }
34
+ }
35
+
36
+ function formatDetails(filePath: string, result: FormatDocumentResult): LspFormatDetails {
37
+ if (result.status === "unavailable") {
38
+ return { filePath, status: "unavailable", reason: result.reason, linesAdded: 0, linesRemoved: 0 };
39
+ }
40
+ return {
41
+ filePath,
42
+ status: result.status,
43
+ linesAdded: result.linesAdded,
44
+ linesRemoved: result.linesRemoved,
45
+ };
46
+ }
47
+
48
+ function describeResult(filePath: string, result: FormatDocumentResult): string {
49
+ if (result.status === "unavailable") {
50
+ return `Formatting unavailable for ${filePath}: the language server does not advertise documentFormattingProvider.`;
51
+ }
52
+ if (result.status === "unchanged") {
53
+ return `Already formatted: ${filePath}`;
54
+ }
55
+ return `Formatted ${filePath} (+${result.linesAdded}/-${result.linesRemoved} lines)`;
56
+ }
@@ -0,0 +1,11 @@
1
+ export { executeLspDiagnostics } from "./diagnostics.js";
2
+ export { LSP_MCP_TOOLS } from "./definitions.js";
3
+ export { executeLspFormat } from "./format.js";
4
+ export { executeLspInstallDecision } from "./install-decision.js";
5
+ export { executeLspFindReferences, executeLspGotoDefinition } from "./navigation.js";
6
+ export { isRecord } from "./parameters.js";
7
+ export { executeLspPrepareRename, executeLspRename } from "./rename.js";
8
+ export { executeLspStatus } from "./status.js";
9
+ export { executeLspSymbols } from "./symbols.js";
10
+ export type * from "./types.js";
11
+ export { coerceToolArguments, executeLspTool } from "./runtime.js";
@@ -0,0 +1,39 @@
1
+ import { getMergedServers } from "../lsp/config-loader.js";
2
+ import { type InstallDecision, isInstallDecision, recordInstallDecision } from "../lsp/server-install-state.js";
3
+ import { requireString } from "./parameters.js";
4
+ import { text } from "./result.js";
5
+ import type { ToolExecutionResult } from "./types.js";
6
+
7
+ export async function executeLspInstallDecision(params: Record<string, unknown>): Promise<ToolExecutionResult> {
8
+ const serverId = requireString(params, "server_id");
9
+ const decision = params["decision"];
10
+ if (!isInstallDecision(decision)) {
11
+ return text(
12
+ `Invalid decision '${String(decision)}'. Expected "declined" or "allowed".`,
13
+ { serverId, errorKind: "invalid_decision" },
14
+ true,
15
+ );
16
+ }
17
+
18
+ const serverIds = [...new Set(getMergedServers().map((server) => server.id))];
19
+ if (!serverIds.includes(serverId)) {
20
+ const preview = serverIds.slice(0, 20).join(", ");
21
+ return text(
22
+ `Unknown LSP server '${serverId}'. Known servers: ${preview}${serverIds.length > 20 ? "..." : ""}`,
23
+ { serverId, errorKind: "unknown_server" },
24
+ true,
25
+ );
26
+ }
27
+
28
+ recordInstallDecision(serverId, decision);
29
+ return text(`Recorded install decision for '${serverId}': ${decision}. ${decisionFollowUp(decision)}`, {
30
+ serverId,
31
+ decision,
32
+ });
33
+ }
34
+
35
+ function decisionFollowUp(decision: InstallDecision): string {
36
+ return decision === "declined"
37
+ ? "Future LSP lookups for this server stay quiet; proceed without LSP."
38
+ : "Future LSP lookups keep install instructions without asking the user.";
39
+ }