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,150 @@
1
+ import { mkdirSync, mkdtempSync, realpathSync, rmSync, writeFileSync } from "node:fs";
2
+ import { tmpdir } from "node:os";
3
+ import { join } from "node:path";
4
+ import { pathToFileURL } from "node:url";
5
+
6
+ import { afterEach, describe, expect, it } from "bun:test";
7
+
8
+ import type { Diagnostic } from "./types.js";
9
+ import { WorkspaceDocumentState } from "./workspace-document-state.js";
10
+ import type { WorkspaceMutation } from "./workspace-edit.js";
11
+
12
+ const workspaces: string[] = [];
13
+
14
+ afterEach(() => {
15
+ while (workspaces.length > 0) {
16
+ const workspace = workspaces.pop();
17
+ if (workspace) rmSync(workspace, { recursive: true, force: true });
18
+ }
19
+ });
20
+
21
+ function makeDocuments(): WorkspaceDocumentState {
22
+ return new WorkspaceDocumentState(
23
+ async () => {},
24
+ () => {},
25
+ { versionlessPublishQuiescenceMs: 0 },
26
+ );
27
+ }
28
+
29
+ function makeSourceFile(directorySegment: string): string {
30
+ const workspace = realpathSync(mkdtempSync(join(tmpdir(), "lsp-document-uri-")));
31
+ workspaces.push(workspace);
32
+ const directory = join(workspace, directorySegment);
33
+ mkdirSync(directory, { recursive: true });
34
+ const source = join(directory, "page.ts");
35
+ writeFileSync(source, "const value: number = 'text';\n", "utf-8");
36
+ return source;
37
+ }
38
+
39
+ const diagnostic: Diagnostic = {
40
+ range: { start: { line: 0, character: 6 }, end: { line: 0, character: 11 } },
41
+ severity: 1,
42
+ message: "Type 'string' is not assignable to type 'number'.",
43
+ };
44
+
45
+ describe("WorkspaceDocumentState published diagnostics under a re-encoded uri", () => {
46
+ it("#given a server that percent-encodes a path segment #when it publishes #then the diagnostics reach the open document", async () => {
47
+ const documents = makeDocuments();
48
+ const source = makeSourceFile("(marketing)");
49
+ await documents.openFile(source);
50
+ const snapshot = documents.captureDiagnosticSnapshot(source);
51
+ expect(snapshot).not.toBeNull();
52
+ const publishedUri = snapshot!.uri.replaceAll("(", "%28").replaceAll(")", "%29");
53
+ expect(publishedUri).not.toBe(snapshot!.uri);
54
+
55
+ documents.recordPublishedDiagnostics({ uri: publishedUri, diagnostics: [diagnostic], version: snapshot!.version });
56
+
57
+ expect(documents.getStoredDiagnostics(snapshot!.uri)).toEqual([diagnostic]);
58
+ expect(documents.resolvePushDiagnostics(snapshot!)).toEqual({ status: "ready", diagnostics: [diagnostic] });
59
+ });
60
+
61
+ it.skipIf(process.platform !== "win32")(
62
+ "#given a server that lowercases and percent-encodes the drive #when it publishes #then the diagnostics reach the open document",
63
+ async () => {
64
+ const documents = makeDocuments();
65
+ const source = makeSourceFile("routes");
66
+ await documents.openFile(source);
67
+ const snapshot = documents.captureDiagnosticSnapshot(source);
68
+ expect(snapshot).not.toBeNull();
69
+ const publishedUri = snapshot!.uri.replace(/^file:\/\/\/([A-Za-z]):/, (_match, drive: string) => `file:///${drive.toLowerCase()}%3A`);
70
+ expect(publishedUri).not.toBe(snapshot!.uri);
71
+
72
+ documents.recordPublishedDiagnostics({ uri: publishedUri, diagnostics: [diagnostic], version: snapshot!.version });
73
+
74
+ expect(documents.getStoredDiagnostics(snapshot!.uri)).toEqual([diagnostic]);
75
+ expect(documents.resolvePushDiagnostics(snapshot!)).toEqual({ status: "ready", diagnostics: [diagnostic] });
76
+ },
77
+ );
78
+
79
+ it("#given a document opened from a path the client already encodes #when the server echoes it verbatim #then the outgoing uri is unchanged", async () => {
80
+ const documents = makeDocuments();
81
+ const source = makeSourceFile("plain");
82
+ await documents.openFile(source);
83
+ const snapshot = documents.captureDiagnosticSnapshot(source);
84
+
85
+ expect(snapshot?.uri).toBe(pathToFileURL(source).href);
86
+ });
87
+ });
88
+
89
+ describe("WorkspaceDocumentState watched-file bounds", () => {
90
+ it("#given more closed-file mutations than one batch #when synchronized #then every notification stays bounded", async () => {
91
+ const notifications: unknown[] = [];
92
+ const documents = new WorkspaceDocumentState(
93
+ async (method, params) => {
94
+ if (method === "workspace/didChangeWatchedFiles") notifications.push(params);
95
+ },
96
+ () => {},
97
+ { versionlessPublishQuiescenceMs: 0 },
98
+ );
99
+ const changedPaths = Array.from({ length: 129 }, (_, index) => `/workspace/file-${index}.ts`);
100
+ const operations: WorkspaceMutation[] = changedPaths.map((path) => ({
101
+ kind: "create",
102
+ path,
103
+ replaced: false,
104
+ }));
105
+
106
+ await documents.synchronize({ operations, changedPaths });
107
+
108
+ expect(notifications).toHaveLength(2);
109
+ expect(notificationChanges(notifications[0])).toHaveLength(128);
110
+ expect(notificationChanges(notifications[1])).toHaveLength(1);
111
+ });
112
+
113
+ it("#given changed closed files #when synchronized #then sends bounded changed watched-file notifications", async () => {
114
+ const notifications: unknown[] = [];
115
+ const documents = new WorkspaceDocumentState(
116
+ async (method, params) => {
117
+ if (method === "workspace/didChangeWatchedFiles") notifications.push(params);
118
+ },
119
+ () => {},
120
+ { versionlessPublishQuiescenceMs: 0 },
121
+ );
122
+ const changedPaths = Array.from({ length: 129 }, (_, index) => `/workspace/file-${index}.ts`);
123
+ const operations: WorkspaceMutation[] = changedPaths.map((path) => ({
124
+ kind: "text",
125
+ path,
126
+ beforeText: "before",
127
+ afterText: "after",
128
+ }));
129
+
130
+ await documents.synchronize({ operations, changedPaths });
131
+
132
+ expect(notifications).toHaveLength(2);
133
+ expect(notificationChanges(notifications[0])).toHaveLength(128);
134
+ expect(notificationChanges(notifications[1])).toHaveLength(1);
135
+ expect(notificationTypes(notifications[0])).toEqual(Array.from({ length: 128 }, () => 2));
136
+ expect(notificationTypes(notifications[1])).toEqual([2]);
137
+ });
138
+ });
139
+
140
+ function notificationChanges(value: unknown): readonly unknown[] {
141
+ if (typeof value !== "object" || value === null || !("changes" in value) || !Array.isArray(value.changes)) return [];
142
+ return value.changes;
143
+ }
144
+
145
+ function notificationTypes(value: unknown): readonly unknown[] {
146
+ return notificationChanges(value).map((change) => {
147
+ if (typeof change !== "object" || change === null || !("type" in change)) return undefined;
148
+ return change.type;
149
+ });
150
+ }
@@ -0,0 +1,392 @@
1
+ import { readFileSync, realpathSync } from "node:fs";
2
+ import { relative, resolve } from "node:path";
3
+ import { pathToFileURL } from "node:url";
4
+
5
+ import { effectiveExtension } from "./effective-extension.js";
6
+ import { getLanguageId } from "./language-mappings.js";
7
+ import type { Diagnostic } from "./types.js";
8
+ import type { TimerProvider } from "./timer-provider.js";
9
+ import type { PlannedWorkspaceOperation, WorkspaceMutation, WorkspaceMutationDelta } from "./workspace-edit-types.js";
10
+
11
+ const WATCHED_FILE_BATCH_SIZE = 128;
12
+ const DEFAULT_VERSIONLESS_PUBLISH_QUIESCENCE_MS = 250;
13
+
14
+ type SendNotification = (method: string, params: unknown) => Promise<void>;
15
+
16
+ interface OpenDocumentState {
17
+ readonly path: string;
18
+ readonly uri: string;
19
+ readonly languageId: string;
20
+ text: string;
21
+ version: number;
22
+ generation: number;
23
+ publishGeneration: number;
24
+ lastPublish?: PublishedDiagnostics;
25
+ pullCache?: PullDiagnosticsCache;
26
+ waiters: Set<() => void>;
27
+ }
28
+
29
+ interface WatchedFileEvent {
30
+ readonly uri: string;
31
+ readonly type: 1 | 2 | 3;
32
+ }
33
+
34
+ interface PublishedDiagnostics {
35
+ readonly diagnostics: readonly Diagnostic[];
36
+ readonly publishGeneration: number;
37
+ readonly documentGenerationAtArrival: number;
38
+ readonly arrivedAt: number;
39
+ readonly version?: number;
40
+ }
41
+
42
+ interface PullDiagnosticsCache {
43
+ readonly documentVersion: number;
44
+ readonly diagnostics: readonly Diagnostic[];
45
+ readonly resultId?: string;
46
+ }
47
+
48
+ export interface DocumentVersionFailure {
49
+ readonly changeIndex: number;
50
+ readonly message: string;
51
+ }
52
+
53
+ export interface DiagnosticSnapshot {
54
+ readonly path: string;
55
+ readonly uri: string;
56
+ readonly version: number;
57
+ readonly documentGeneration: number;
58
+ readonly publishGeneration: number;
59
+ }
60
+
61
+ export interface PullDiagnosticsReport {
62
+ readonly diagnostics: readonly Diagnostic[];
63
+ readonly kind: "full";
64
+ readonly resultId?: string;
65
+ }
66
+
67
+ export interface PullDiagnosticsCacheHit {
68
+ readonly documentVersion: number;
69
+ readonly diagnostics: readonly Diagnostic[];
70
+ readonly resultId?: string;
71
+ }
72
+
73
+ export type PushDiagnosticsResolution =
74
+ | { readonly status: "ready"; readonly diagnostics: readonly Diagnostic[] }
75
+ | { readonly status: "wait"; readonly waitMs: number }
76
+ | { readonly status: "missing" };
77
+
78
+ export interface WorkspaceDocumentStateOptions {
79
+ readonly now?: () => number;
80
+ readonly timerProvider?: TimerProvider;
81
+ readonly versionlessPublishQuiescenceMs?: number;
82
+ }
83
+
84
+ function canonicalPath(filePath: string): string {
85
+ const absolute = resolve(filePath);
86
+ try {
87
+ return realpathSync(absolute);
88
+ } catch {
89
+ return absolute;
90
+ }
91
+ }
92
+
93
+ function normalizeDocumentUri(uri: string): string {
94
+ let decoded = uri;
95
+ try {
96
+ decoded = decodeURIComponent(uri);
97
+ } catch {
98
+ decoded = uri;
99
+ }
100
+ if (process.platform !== "win32") return decoded;
101
+ return decoded.replace(/^(file:\/\/\/)([a-z]):/, (_match, prefix: string, drive: string) => `${prefix}${drive.toUpperCase()}:`);
102
+ }
103
+
104
+ function isSameOrDescendant(candidate: string, parent: string): boolean {
105
+ const suffix = relative(parent, candidate);
106
+ return suffix === "" || (!suffix.startsWith("..") && suffix !== "..");
107
+ }
108
+
109
+ function movedPath(candidate: string, oldPath: string, newPath: string): string {
110
+ const suffix = relative(oldPath, candidate);
111
+ return suffix === "" ? newPath : resolve(newPath, suffix);
112
+ }
113
+
114
+ export class WorkspaceDocumentState {
115
+ private readonly openDocuments = new Map<string, OpenDocumentState>();
116
+ private readonly openByUri = new Map<string, OpenDocumentState>();
117
+ private readonly openPromises = new Map<string, Promise<void>>();
118
+ private readonly now: () => number;
119
+ private readonly timerProvider: TimerProvider;
120
+ private readonly versionlessPublishQuiescenceMs: number;
121
+
122
+ constructor(
123
+ private readonly sendNotification: SendNotification,
124
+ private readonly clearDiagnostics: (uri: string) => void,
125
+ options: WorkspaceDocumentStateOptions = {},
126
+ ) {
127
+ this.timerProvider = options.timerProvider ?? {
128
+ now: options.now ?? (() => Date.now()),
129
+ setTimeout: (callback, delayMs) => setTimeout(callback, delayMs),
130
+ clearTimeout: (handle) => clearTimeout(handle),
131
+ };
132
+ this.now = () => this.timerProvider.now();
133
+ this.versionlessPublishQuiescenceMs =
134
+ options.versionlessPublishQuiescenceMs ?? DEFAULT_VERSIONLESS_PUBLISH_QUIESCENCE_MS;
135
+ }
136
+
137
+ async openFile(filePath: string): Promise<void> {
138
+ const path = canonicalPath(filePath);
139
+ const existingOpen = this.openPromises.get(path);
140
+ if (existingOpen) {
141
+ await existingOpen;
142
+ return this.openFile(path);
143
+ }
144
+
145
+ const text = readFileSync(path, "utf-8");
146
+ const existing = this.openDocuments.get(path);
147
+ if (!existing) return this.openDocumentSingleFlight(path, text);
148
+ if (existing.text === text) return;
149
+ await this.changeDocument(existing, text);
150
+ }
151
+
152
+ getVersion(filePath: string): number | undefined {
153
+ return this.openDocuments.get(canonicalPath(filePath))?.version;
154
+ }
155
+
156
+ getStoredDiagnostics(uri: string): readonly Diagnostic[] {
157
+ const state = this.openByUri.get(normalizeDocumentUri(uri));
158
+ if (!state) return [];
159
+ return state.lastPublish?.diagnostics ?? state.pullCache?.diagnostics ?? [];
160
+ }
161
+
162
+ captureDiagnosticSnapshot(filePath: string): DiagnosticSnapshot | null {
163
+ const state = this.openDocuments.get(canonicalPath(filePath));
164
+ if (!state) return null;
165
+ return {
166
+ path: state.path,
167
+ uri: state.uri,
168
+ version: state.version,
169
+ documentGeneration: state.generation,
170
+ publishGeneration: state.publishGeneration,
171
+ };
172
+ }
173
+
174
+ isCurrentSnapshot(snapshot: DiagnosticSnapshot): boolean {
175
+ const state = this.openDocuments.get(snapshot.path);
176
+ return (
177
+ state !== undefined &&
178
+ state.uri === snapshot.uri &&
179
+ state.version === snapshot.version &&
180
+ state.generation === snapshot.documentGeneration
181
+ );
182
+ }
183
+
184
+ getPullCache(snapshot: DiagnosticSnapshot): PullDiagnosticsCacheHit | null {
185
+ const state = this.openByUri.get(normalizeDocumentUri(snapshot.uri));
186
+ if (!state?.pullCache || state.pullCache.documentVersion !== snapshot.version) return null;
187
+ return state.pullCache;
188
+ }
189
+
190
+ recordPullDiagnostics(snapshot: DiagnosticSnapshot, report: PullDiagnosticsReport): void {
191
+ const state = this.openByUri.get(normalizeDocumentUri(snapshot.uri));
192
+ if (!state) return;
193
+ state.pullCache = {
194
+ documentVersion: snapshot.version,
195
+ diagnostics: [...report.diagnostics],
196
+ ...(report.resultId === undefined ? {} : { resultId: report.resultId }),
197
+ };
198
+ }
199
+
200
+ recordPublishedDiagnostics(params: {
201
+ readonly uri: string;
202
+ readonly diagnostics: readonly Diagnostic[];
203
+ readonly version?: number;
204
+ }): void {
205
+ const state = this.openByUri.get(normalizeDocumentUri(params.uri));
206
+ if (!state) return;
207
+ state.publishGeneration += 1;
208
+ state.lastPublish = {
209
+ diagnostics: [...params.diagnostics],
210
+ publishGeneration: state.publishGeneration,
211
+ documentGenerationAtArrival: state.generation,
212
+ arrivedAt: this.now(),
213
+ ...(params.version === undefined ? {} : { version: params.version }),
214
+ };
215
+ this.notifyWaiters(state);
216
+ }
217
+
218
+ resolvePushDiagnostics(snapshot: DiagnosticSnapshot): PushDiagnosticsResolution {
219
+ const state = this.openByUri.get(normalizeDocumentUri(snapshot.uri));
220
+ if (!state?.lastPublish) return { status: "missing" };
221
+ const publish = state.lastPublish;
222
+ if (publish.version !== undefined) {
223
+ return publish.version === snapshot.version
224
+ ? { status: "ready", diagnostics: publish.diagnostics }
225
+ : { status: "missing" };
226
+ }
227
+ if (publish.documentGenerationAtArrival < snapshot.documentGeneration) return { status: "missing" };
228
+ const readyAt = publish.arrivedAt + this.versionlessPublishQuiescenceMs;
229
+ const waitMs = Math.max(0, readyAt - this.now());
230
+ return waitMs === 0
231
+ ? { status: "ready", diagnostics: publish.diagnostics }
232
+ : { status: "wait", waitMs };
233
+ }
234
+
235
+ waitForDiagnosticsActivity(snapshot: DiagnosticSnapshot, timeoutMs: number): Promise<void> {
236
+ const state = this.openByUri.get(normalizeDocumentUri(snapshot.uri));
237
+ if (!state || timeoutMs <= 0) return Promise.resolve();
238
+ // A publish that landed between the caller's snapshot and this registration already IS the
239
+ // activity being waited for, and its notifyWaiters ran before this waiter existed. Without
240
+ // this check that wake-up is lost and the wait can only end at the freshness deadline, which
241
+ // turns the deadline from a fallback into the poll interval the result depends on (#8323).
242
+ if (state.publishGeneration !== snapshot.publishGeneration) return Promise.resolve();
243
+ return new Promise((resolveActivity) => {
244
+ let settled = false;
245
+ const finish = () => {
246
+ if (settled) return;
247
+ settled = true;
248
+ this.timerProvider.clearTimeout(timer);
249
+ state.waiters.delete(finish);
250
+ resolveActivity();
251
+ };
252
+ const timer = this.timerProvider.setTimeout(finish, timeoutMs);
253
+ if (typeof timer.unref === "function") timer.unref();
254
+ state.waiters.add(finish);
255
+ });
256
+ }
257
+
258
+ validateVersions(operations: readonly PlannedWorkspaceOperation[]): DocumentVersionFailure | null {
259
+ const versions = new Map([...this.openDocuments].map(([path, state]) => [path, state.version]));
260
+ for (const operation of operations) {
261
+ if (operation.kind === "text") {
262
+ const current = versions.get(operation.path);
263
+ if (operation.documentVersion !== null && current !== operation.documentVersion) {
264
+ const observed = current === undefined ? "closed document" : `open document version ${current}`;
265
+ return {
266
+ changeIndex: operation.changeIndex,
267
+ message: `document version ${operation.documentVersion} does not match ${observed} for ${operation.path}`,
268
+ };
269
+ }
270
+ if (current !== undefined) versions.set(operation.path, current + 1);
271
+ continue;
272
+ }
273
+ if (operation.kind === "rename") {
274
+ const moved = [...versions].filter(([path]) => isSameOrDescendant(path, operation.oldPath));
275
+ for (const [path] of moved) versions.delete(path);
276
+ for (const [path] of moved) versions.set(movedPath(path, operation.oldPath, operation.newPath), 1);
277
+ continue;
278
+ }
279
+ if (operation.kind === "delete") {
280
+ for (const path of [...versions.keys()]) {
281
+ if (isSameOrDescendant(path, operation.path)) versions.delete(path);
282
+ }
283
+ continue;
284
+ }
285
+ if (operation.kind === "create" && operation.replaced && versions.has(operation.path)) {
286
+ versions.set(operation.path, 1);
287
+ }
288
+ }
289
+ return null;
290
+ }
291
+
292
+ async synchronize(delta: WorkspaceMutationDelta): Promise<void> {
293
+ const watched: WatchedFileEvent[] = [];
294
+ for (const mutation of delta.operations) await this.synchronizeMutation(mutation, watched);
295
+ for (let index = 0; index < watched.length; index += WATCHED_FILE_BATCH_SIZE) {
296
+ await this.sendNotification("workspace/didChangeWatchedFiles", {
297
+ changes: watched.slice(index, index + WATCHED_FILE_BATCH_SIZE),
298
+ });
299
+ }
300
+ }
301
+
302
+ private async synchronizeMutation(mutation: WorkspaceMutation, watched: WatchedFileEvent[]): Promise<void> {
303
+ if (mutation.kind === "text") {
304
+ const state = this.openDocuments.get(mutation.path);
305
+ if (state) await this.changeDocument(state, mutation.afterText);
306
+ else watched.push({ uri: pathToFileURL(mutation.path).href, type: 2 });
307
+ return;
308
+ }
309
+ if (mutation.kind === "create") {
310
+ const state = this.openDocuments.get(mutation.path);
311
+ if (state) {
312
+ await this.closeDocument(state);
313
+ await this.openDocumentSingleFlight(mutation.path, readFileSync(mutation.path, "utf-8"));
314
+ } else {
315
+ watched.push({ uri: pathToFileURL(mutation.path).href, type: mutation.replaced ? 2 : 1 });
316
+ }
317
+ return;
318
+ }
319
+ if (mutation.kind === "rename") {
320
+ const moved = [...this.openDocuments.values()].filter((state) =>
321
+ isSameOrDescendant(state.path, mutation.oldPath),
322
+ );
323
+ for (const state of moved) await this.closeDocument(state);
324
+ for (const state of moved) {
325
+ const path = movedPath(state.path, mutation.oldPath, mutation.newPath);
326
+ await this.openDocumentSingleFlight(path, readFileSync(path, "utf-8"));
327
+ }
328
+ if (moved.length === 0) {
329
+ watched.push({ uri: pathToFileURL(mutation.oldPath).href, type: 3 });
330
+ watched.push({ uri: pathToFileURL(mutation.newPath).href, type: 1 });
331
+ }
332
+ return;
333
+ }
334
+ const removed = [...this.openDocuments.values()].filter((state) =>
335
+ isSameOrDescendant(state.path, mutation.path),
336
+ );
337
+ for (const state of removed) await this.closeDocument(state);
338
+ if (removed.length === 0) watched.push({ uri: pathToFileURL(mutation.path).href, type: 3 });
339
+ }
340
+
341
+ private async openDocumentSingleFlight(path: string, text: string): Promise<void> {
342
+ const existing = this.openPromises.get(path);
343
+ if (existing) return existing;
344
+ const open = (async () => {
345
+ const state: OpenDocumentState = {
346
+ path,
347
+ uri: pathToFileURL(path).href,
348
+ languageId: getLanguageId(effectiveExtension(path)),
349
+ text,
350
+ version: 1,
351
+ generation: 1,
352
+ publishGeneration: 0,
353
+ waiters: new Set(),
354
+ };
355
+ this.openDocuments.set(path, state);
356
+ this.openByUri.set(normalizeDocumentUri(state.uri), state);
357
+ this.notifyWaiters(state);
358
+ await this.sendNotification("textDocument/didOpen", {
359
+ textDocument: { uri: state.uri, languageId: state.languageId, version: state.version, text },
360
+ });
361
+ })().finally(() => {
362
+ this.openPromises.delete(path);
363
+ });
364
+ this.openPromises.set(path, open);
365
+ return open;
366
+ }
367
+
368
+ private async changeDocument(state: OpenDocumentState, text: string): Promise<void> {
369
+ state.text = text;
370
+ state.version += 1;
371
+ state.generation += 1;
372
+ this.clearDiagnostics(state.uri);
373
+ this.notifyWaiters(state);
374
+ await this.sendNotification("textDocument/didChange", {
375
+ textDocument: { uri: state.uri, version: state.version },
376
+ contentChanges: [{ text }],
377
+ });
378
+ await this.sendNotification("textDocument/didSave", { textDocument: { uri: state.uri }, text });
379
+ }
380
+
381
+ private async closeDocument(state: OpenDocumentState): Promise<void> {
382
+ this.openDocuments.delete(state.path);
383
+ this.openByUri.delete(normalizeDocumentUri(state.uri));
384
+ this.clearDiagnostics(state.uri);
385
+ this.notifyWaiters(state);
386
+ await this.sendNotification("textDocument/didClose", { textDocument: { uri: state.uri } });
387
+ }
388
+
389
+ private notifyWaiters(state: OpenDocumentState): void {
390
+ for (const waiter of [...state.waiters]) waiter();
391
+ }
392
+ }
@@ -0,0 +1,132 @@
1
+ import { mkdtempSync, readFileSync, realpathSync, rmSync, symlinkSync, writeFileSync } from "node:fs";
2
+ import { tmpdir } from "node:os";
3
+ import { join } from "node:path";
4
+ import { pathToFileURL } from "node:url";
5
+
6
+ import { afterEach, describe, expect, it } from "bun:test";
7
+
8
+ import { applyWorkspaceEdit, planWorkspaceEdit } from "./workspace-edit.js";
9
+
10
+ const tempDirectories: string[] = [];
11
+
12
+ afterEach(() => {
13
+ for (const directory of tempDirectories.splice(0)) rmSync(directory, { recursive: true, force: true });
14
+ });
15
+
16
+ describe("workspace edit adversarial inputs", () => {
17
+ it("#given malformed and decorated URIs #when planned #then every variant is rejected before mutation", () => {
18
+ const workspace = makeTempDirectory("lsp-workspace-");
19
+ const source = join(workspace, "source.ts");
20
+ writeFileSync(source, "const before = 1;\n", "utf-8");
21
+ const decorated = `${pathToFileURL(source).href}?query=forbidden`;
22
+
23
+ for (const uri of ["untitled:source.ts", decorated, "file:///%ZZ"] as const) {
24
+ const result = planWorkspaceEdit({ changes: { [uri]: [insertion()] } }, workspace);
25
+ expect(result.success).toBe(false);
26
+ }
27
+ expect(readFileSync(source, "utf-8")).toBe("const before = 1;\n");
28
+ });
29
+
30
+ it("#given invalid ranges and resource options #when planned #then each failure retains its operation index", () => {
31
+ const workspace = makeTempDirectory("lsp-workspace-");
32
+ const source = join(workspace, "source.ts");
33
+ const created = join(workspace, "created.ts");
34
+ writeFileSync(source, "const before = 1;\n", "utf-8");
35
+ const invalidRange = planWorkspaceEdit(
36
+ {
37
+ documentChanges: [
38
+ {
39
+ textDocument: { uri: pathToFileURL(source).href, version: null },
40
+ edits: [
41
+ {
42
+ range: { start: { line: 0, character: -1 }, end: { line: 0, character: 2 } },
43
+ newText: "bad",
44
+ },
45
+ ],
46
+ },
47
+ ],
48
+ },
49
+ workspace,
50
+ );
51
+ const invalidOption = planWorkspaceEdit(
52
+ {
53
+ documentChanges: [
54
+ {
55
+ textDocument: { uri: pathToFileURL(source).href, version: null },
56
+ edits: [],
57
+ },
58
+ { kind: "create", uri: pathToFileURL(created).href, options: { overwrite: "yes" } },
59
+ ],
60
+ },
61
+ workspace,
62
+ );
63
+
64
+ expect(invalidRange.success).toBe(false);
65
+ if (!invalidRange.success) expect(invalidRange.result.errors[0]).toContain("change 0");
66
+ expect(invalidOption.success).toBe(false);
67
+ if (!invalidOption.success) expect(invalidOption.result.errors[0]).toContain("change 1");
68
+ expect(readFileSync(source, "utf-8")).toBe("const before = 1;\n");
69
+ });
70
+
71
+ it("#given an outside target and a dirty unrelated file #when prevalidation fails #then neither is touched", () => {
72
+ const workspace = makeTempDirectory("lsp-workspace-");
73
+ const outside = makeTempDirectory("lsp-outside-");
74
+ const dirty = join(workspace, "dirty.ts");
75
+ const outsideFile = join(outside, "outside.ts");
76
+ writeFileSync(dirty, "user-owned dirty bytes\n", "utf-8");
77
+ writeFileSync(outsideFile, "outside bytes\n", "utf-8");
78
+
79
+ const result = applyWorkspaceEdit(
80
+ { changes: { [pathToFileURL(outsideFile).href]: [insertion()] } },
81
+ { workspaceRoot: workspace },
82
+ );
83
+
84
+ expect(result.success).toBe(false);
85
+ expect(result.errors.join("\n")).toContain("outside workspace");
86
+ expect(readFileSync(dirty, "utf-8")).toBe("user-owned dirty bytes\n");
87
+ expect(readFileSync(outsideFile, "utf-8")).toBe("outside bytes\n");
88
+ });
89
+
90
+ it("#given an in-workspace symlink to an outside file #when applying an edit #then rejects without modifying target", () => {
91
+ const workspace = makeTempDirectory("lsp-workspace-");
92
+ const outside = makeTempDirectory("lsp-outside-");
93
+ const outsideFile = join(outside, "outside.ts");
94
+ const canonicalWorkspace = realpathSync(workspace);
95
+ const linkedDirectory = join(canonicalWorkspace, "linked");
96
+ writeFileSync(outsideFile, "outside bytes\n", "utf-8");
97
+ symlinkSync(outside, linkedDirectory);
98
+
99
+ const result = applyWorkspaceEdit(
100
+ { changes: { [pathToFileURL(join(linkedDirectory, "outside.ts")).href]: [insertion()] } },
101
+ { workspaceRoot: canonicalWorkspace },
102
+ );
103
+
104
+ expect(result.success).toBe(false);
105
+ expect(result.errors.join("\n")).toContain("outside workspace");
106
+ expect(readFileSync(outsideFile, "utf-8")).toBe("outside bytes\n");
107
+ });
108
+
109
+ it("#given annotations or mixed edit representations #when planned #then unsupported claims are rejected", () => {
110
+ const workspace = makeTempDirectory("lsp-workspace-");
111
+ const unsupported = [
112
+ { changeAnnotations: { change: { label: "unsupported" } } },
113
+ { changes: {}, documentChanges: [] },
114
+ { documentChanges: [{ kind: "create", uri: "file:///missing", annotationId: "change" }] },
115
+ ];
116
+
117
+ for (const edit of unsupported) expect(planWorkspaceEdit(edit, workspace).success).toBe(false);
118
+ });
119
+ });
120
+
121
+ function insertion() {
122
+ return {
123
+ range: { start: { line: 0, character: 0 }, end: { line: 0, character: 0 } },
124
+ newText: "x",
125
+ };
126
+ }
127
+
128
+ function makeTempDirectory(prefix: string): string {
129
+ const directory = mkdtempSync(join(tmpdir(), prefix));
130
+ tempDirectories.push(directory);
131
+ return directory;
132
+ }