lazycodex-ai 5.0.0-beta.4 → 5.0.0-beta.42

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 (551) hide show
  1. package/README.ja.md +25 -21
  2. package/README.ko.md +25 -21
  3. package/README.md +38 -23
  4. package/README.ru.md +24 -20
  5. package/README.zh-cn.md +25 -21
  6. package/dist/cli/config-manager/parse-opencode-config-file.d.ts +2 -1
  7. package/dist/cli/doctor/checks/system-plugin.d.ts +4 -3
  8. package/dist/cli/fallback-lane-policy.d.ts +1 -0
  9. package/dist/cli/index.js +67006 -64814
  10. package/dist/cli/install-codex/install-codex-test-fixtures.d.ts +1 -1
  11. package/dist/cli/run/on-complete-hook.d.ts +2 -0
  12. package/dist/cli/runtime-commands.d.ts +1 -1
  13. package/dist/cli/worktree-sweep/classify.d.ts +16 -0
  14. package/dist/cli/worktree-sweep/format.d.ts +8 -0
  15. package/dist/cli/worktree-sweep/git.d.ts +19 -0
  16. package/dist/cli/worktree-sweep/index.d.ts +7 -0
  17. package/dist/cli/worktree-sweep/options.d.ts +2 -0
  18. package/dist/cli/worktree-sweep/parse-worktree-list.d.ts +8 -0
  19. package/dist/cli/worktree-sweep/sweep.d.ts +2 -0
  20. package/dist/cli/worktree-sweep/types.d.ts +65 -0
  21. package/dist/cli/worktree-sweep/worktree-sweep.d.ts +2 -0
  22. package/dist/cli-node/index.js +67283 -65068
  23. package/package.json +9 -9
  24. package/packages/git-bash-mcp/dist/cli.js +6 -1
  25. package/packages/lsp-daemon/dist/cli.js +804 -329
  26. package/packages/lsp-daemon/dist/client.d.ts +10 -0
  27. package/packages/lsp-daemon/dist/client.js +764 -286
  28. package/packages/lsp-daemon/dist/daemon-client.d.ts +1 -0
  29. package/packages/lsp-daemon/dist/daemon-client.js +3 -0
  30. package/packages/lsp-daemon/dist/ensure-daemon.js +1 -0
  31. package/packages/lsp-daemon/dist/index.js +768 -295
  32. package/packages/lsp-daemon/dist/proxy.js +3 -0
  33. package/packages/lsp-daemon/dist/version-reap.js +1 -1
  34. package/packages/lsp-daemon/package.json +1 -1
  35. package/packages/lsp-tools-mcp/dist/cli.js +723 -250
  36. package/packages/lsp-tools-mcp/dist/lsp/manager.js +259 -125
  37. package/packages/lsp-tools-mcp/dist/mcp.js +725 -252
  38. package/packages/lsp-tools-mcp/dist/request-context.js +12 -13
  39. package/packages/lsp-tools-mcp/dist/tools.js +729 -260
  40. package/packages/lsp-tools-mcp/package.json +1 -1
  41. package/packages/omo-codex/plugin/.codex-plugin/plugin.json +4 -6
  42. package/packages/omo-codex/plugin/.mcp.json +0 -6
  43. package/packages/omo-codex/plugin/AGENTS.md +47 -0
  44. package/packages/omo-codex/plugin/README.md +2 -2
  45. package/packages/omo-codex/plugin/components/bootstrap/dist/cli.js +45 -49
  46. package/packages/omo-codex/plugin/components/bootstrap/hooks/hooks.json +1 -1
  47. package/packages/omo-codex/plugin/components/bootstrap/package.json +1 -1
  48. package/packages/omo-codex/plugin/components/bootstrap/src/hook.ts +1 -0
  49. package/packages/omo-codex/plugin/components/comment-checker/AGENTS.md +9 -0
  50. package/packages/omo-codex/plugin/components/comment-checker/biome.json +2 -2
  51. package/packages/omo-codex/plugin/components/comment-checker/dist/cli.js +2 -1
  52. package/packages/omo-codex/plugin/components/comment-checker/hooks/hooks.json +1 -1
  53. package/packages/omo-codex/plugin/components/comment-checker/package.json +5 -5
  54. package/packages/omo-codex/plugin/components/comment-checker/src/apply-patch.ts +2 -8
  55. package/packages/omo-codex/plugin/components/comment-checker/src/core.ts +1 -2
  56. package/packages/omo-codex/plugin/components/comment-checker/src/request-extractor.ts +1 -1
  57. package/packages/omo-codex/plugin/components/comment-checker/src/runner.ts +1 -0
  58. package/packages/omo-codex/plugin/components/git-bash/AGENTS.md +1 -1
  59. package/packages/omo-codex/plugin/components/git-bash/hooks/hooks.json +2 -2
  60. package/packages/omo-codex/plugin/components/git-bash/package.json +3 -4
  61. package/packages/omo-codex/plugin/components/lazycodex-executor-verify/biome.json +2 -2
  62. package/packages/omo-codex/plugin/components/lazycodex-executor-verify/dist/cli.js +1 -5
  63. package/packages/omo-codex/plugin/components/lazycodex-executor-verify/dist/codex-hook.js +1 -5
  64. package/packages/omo-codex/plugin/components/lazycodex-executor-verify/hooks/hooks.json +1 -1
  65. package/packages/omo-codex/plugin/components/lazycodex-executor-verify/package.json +5 -5
  66. package/packages/omo-codex/plugin/components/lazycodex-executor-verify/src/codex-hook.ts +1 -5
  67. package/packages/omo-codex/plugin/components/lazycodex-executor-verify/test/codex-hook.test.ts +4 -21
  68. package/packages/omo-codex/plugin/components/lcx/skills/lcx-doctor/SKILL.md +1 -1
  69. package/packages/omo-codex/plugin/components/lsp/AGENTS.md +30 -15
  70. package/packages/omo-codex/plugin/components/lsp/biome.json +2 -2
  71. package/packages/omo-codex/plugin/components/lsp/dist/.omo-runtime-manifest.json +4 -4
  72. package/packages/omo-codex/plugin/components/lsp/dist/cli.js +752 -300
  73. package/packages/omo-codex/plugin/components/lsp/dist/daemon-cli-path.js +1 -1
  74. package/packages/omo-codex/plugin/components/lsp/hooks/hooks.json +2 -2
  75. package/packages/omo-codex/plugin/components/lsp/package.json +5 -5
  76. package/packages/omo-codex/plugin/components/lsp/src/cli.ts +1 -1
  77. package/packages/omo-codex/plugin/components/lsp/src/codex-hook.ts +1 -1
  78. package/packages/omo-codex/plugin/components/lsp/src/daemon-cli-path.ts +1 -5
  79. package/packages/omo-codex/plugin/components/lsp/test/codex-hook-unavailable.test.ts +6 -7
  80. package/packages/omo-codex/plugin/components/lsp/test/codex-hook.test.ts +1 -2
  81. package/packages/omo-codex/plugin/components/lsp/test/package-smoke.test.ts +11 -1
  82. package/packages/omo-codex/plugin/components/rules/AGENTS.md +12 -0
  83. package/packages/omo-codex/plugin/components/rules/biome.json +2 -2
  84. package/packages/omo-codex/plugin/components/rules/dist/cli.js +60 -45
  85. package/packages/omo-codex/plugin/components/rules/hooks/hooks.json +4 -4
  86. package/packages/omo-codex/plugin/components/rules/package.json +7 -7
  87. package/packages/omo-codex/plugin/components/rules/src/config.ts +1 -2
  88. package/packages/omo-codex/plugin/components/rules/src/persistent-cache.ts +1 -2
  89. package/packages/omo-codex/plugin/components/rules/src/post-compact-budget.ts +9 -5
  90. package/packages/omo-codex/plugin/components/rules/src/rules-engine-factory.ts +1 -4
  91. package/packages/omo-codex/plugin/components/rules/src/static-injection.ts +4 -9
  92. package/packages/omo-codex/plugin/components/rules/test/bundled-rules-priority.test.ts +11 -16
  93. package/packages/omo-codex/plugin/components/rules/test/bundled-rules.test.ts +17 -25
  94. package/packages/omo-codex/plugin/components/rules/test/codex-hook-post-compact-budget.test.ts +9 -7
  95. package/packages/omo-codex/plugin/components/rules/test/codex-hook-post-compact-context.test.ts +0 -6
  96. package/packages/omo-codex/plugin/components/rules/test/codex-hook-post-compact-dedup.test.ts +6 -4
  97. package/packages/omo-codex/plugin/components/rules/test/codex-hook-post-compact-directive.test.ts +12 -9
  98. package/packages/omo-codex/plugin/components/rules/test/codex-hook.test.ts +28 -37
  99. package/packages/omo-codex/plugin/components/rules/test/dynamic-target-fingerprints.test.ts +1 -2
  100. package/packages/omo-codex/plugin/components/rules/test/engine.test.ts +7 -4
  101. package/packages/omo-codex/plugin/components/rules/test/finder.test.ts +2 -3
  102. package/packages/omo-codex/plugin/components/rules/test/formatter.test.ts +39 -72
  103. package/packages/omo-codex/plugin/components/rules/test/hephaestus-model-variant.test.ts +1 -2
  104. package/packages/omo-codex/plugin/components/rules/test/hook-output.test.ts +2 -3
  105. package/packages/omo-codex/plugin/components/rules/test/matcher.test.ts +2 -3
  106. package/packages/omo-codex/plugin/components/rules/test/package-smoke.test.ts +1 -1
  107. package/packages/omo-codex/plugin/components/rules/test/parser.test.ts +1 -2
  108. package/packages/omo-codex/plugin/components/rules/test/post-compact-budget.test.ts +5 -6
  109. package/packages/omo-codex/plugin/components/rules/test/rules-engine-consumption.test.ts +3 -6
  110. package/packages/omo-codex/plugin/components/rules/test/scanner.test.ts +1 -2
  111. package/packages/omo-codex/plugin/components/rules/test/sources.test.ts +2 -5
  112. package/packages/omo-codex/plugin/components/rules/test/windows-git-bash-bundled-rule.test.ts +2 -17
  113. package/packages/omo-codex/plugin/components/teammode/hooks/hooks.json +1 -1
  114. package/packages/omo-codex/plugin/components/teammode/package.json +5 -5
  115. package/packages/omo-codex/plugin/components/teammode/test/thread-title-hook.test.ts +4 -10
  116. package/packages/omo-codex/plugin/components/telemetry/AGENTS.md +8 -0
  117. package/packages/omo-codex/plugin/components/telemetry/biome.json +2 -2
  118. package/packages/omo-codex/plugin/components/telemetry/dist/cli.js +2463 -437
  119. package/packages/omo-codex/plugin/components/telemetry/dist/posthog.js +2467 -441
  120. package/packages/omo-codex/plugin/components/telemetry/hooks/hooks.json +1 -1
  121. package/packages/omo-codex/plugin/components/telemetry/package.json +5 -5
  122. package/packages/omo-codex/plugin/components/telemetry/src/codex-hook.ts +1 -4
  123. package/packages/omo-codex/plugin/components/telemetry/src/posthog.ts +4 -14
  124. package/packages/omo-codex/plugin/components/telemetry/src/product-identity.ts +1 -1
  125. package/packages/omo-codex/plugin/components/telemetry/test/diagnostics.test.ts +2 -5
  126. package/packages/omo-codex/plugin/components/ultrawork/AGENTS.md +10 -4
  127. package/packages/omo-codex/plugin/components/ultrawork/biome.json +2 -2
  128. package/packages/omo-codex/plugin/components/ultrawork/dist/cli.js +489 -4
  129. package/packages/omo-codex/plugin/components/ultrawork/hooks/hooks.json +1 -1
  130. package/packages/omo-codex/plugin/components/ultrawork/package.json +5 -6
  131. package/packages/omo-codex/plugin/components/ultrawork/scripts/sync-directive.mjs +30 -14
  132. package/packages/omo-codex/plugin/components/ultrawork/skills/ulw-plan/SKILL.md +6 -7
  133. package/packages/omo-codex/plugin/components/ultrawork/skills/ulw-plan/references/full-workflow.md +31 -7
  134. package/packages/omo-codex/plugin/components/ultrawork/skills/ulw-plan/references/intent-clear.md +2 -1
  135. package/packages/omo-codex/plugin/components/ultrawork/skills/ulw-plan/references/intent-unclear.md +5 -5
  136. package/packages/omo-codex/plugin/components/ultrawork/src/directive-content.ts +4 -0
  137. package/packages/omo-codex/plugin/components/ultrawork/src/directive.ts +5 -2
  138. package/packages/omo-codex/plugin/components/ultrawork/test/codex-hook-trigger-policy.test.ts +9 -1
  139. package/packages/omo-codex/plugin/components/ultrawork/test/codex-hook.test.ts +0 -136
  140. package/packages/omo-codex/plugin/components/ultrawork/test/directive-source.test.ts +14 -8
  141. package/packages/omo-codex/plugin/components/ultrawork/test/package-smoke.test.ts +12 -1
  142. package/packages/omo-codex/plugin/components/ultrawork/test/skill-pointer.test.ts +0 -2
  143. package/packages/omo-codex/plugin/components/{start-work-continuation → ulw-execute-continuation}/AGENTS.md +2 -2
  144. package/packages/omo-codex/plugin/components/{start-work-continuation → ulw-execute-continuation}/NOTICE +1 -1
  145. package/packages/omo-codex/plugin/components/{start-work-continuation → ulw-execute-continuation}/README.md +5 -5
  146. package/packages/omo-codex/plugin/components/{start-work-continuation → ulw-execute-continuation}/biome.json +2 -2
  147. package/packages/omo-codex/plugin/components/{start-work-continuation → ulw-execute-continuation}/directive.md +6 -6
  148. package/packages/omo-codex/plugin/components/{start-work-continuation → ulw-execute-continuation}/dist/cli.js +12 -12
  149. package/packages/omo-codex/plugin/components/ulw-execute-continuation/hooks/hooks.json +28 -0
  150. package/packages/omo-codex/plugin/components/{start-work-continuation → ulw-execute-continuation}/package.json +12 -12
  151. package/packages/omo-codex/plugin/components/{start-work-continuation → ulw-execute-continuation}/src/boulder-reader.ts +1 -1
  152. package/packages/omo-codex/plugin/components/{start-work-continuation → ulw-execute-continuation}/src/cli.ts +1 -1
  153. package/packages/omo-codex/plugin/components/{start-work-continuation → ulw-execute-continuation}/src/codex-hook.ts +3 -3
  154. package/packages/omo-codex/plugin/components/{start-work-continuation → ulw-execute-continuation}/src/directive.ts +1 -1
  155. package/packages/omo-codex/plugin/components/{start-work-continuation → ulw-execute-continuation}/src/index.ts +1 -1
  156. package/packages/omo-codex/plugin/components/{start-work-continuation → ulw-execute-continuation}/test/boulder-reader.test.ts +3 -3
  157. package/packages/omo-codex/plugin/components/{start-work-continuation → ulw-execute-continuation}/test/cli.test.ts +1 -4
  158. package/packages/omo-codex/plugin/components/{start-work-continuation → ulw-execute-continuation}/test/codex-hook.test.ts +8 -22
  159. package/packages/omo-codex/plugin/components/ulw-loop/AGENTS.md +19 -0
  160. package/packages/omo-codex/plugin/components/ulw-loop/CHANGELOG.md +1 -1
  161. package/packages/omo-codex/plugin/components/ulw-loop/README.md +12 -1
  162. package/packages/omo-codex/plugin/components/ulw-loop/biome.json +2 -2
  163. package/packages/omo-codex/plugin/components/ulw-loop/directive.md +15 -3
  164. package/packages/omo-codex/plugin/components/ulw-loop/dist/checkpoint-codex-validation.d.ts +12 -0
  165. package/packages/omo-codex/plugin/components/ulw-loop/dist/checkpoint-codex-validation.js +45 -0
  166. package/packages/omo-codex/plugin/components/ulw-loop/dist/checkpoint-continuation.js +9 -0
  167. package/packages/omo-codex/plugin/components/ulw-loop/dist/checkpoint-reconciliation.d.ts +15 -0
  168. package/packages/omo-codex/plugin/components/ulw-loop/dist/checkpoint-reconciliation.js +15 -1
  169. package/packages/omo-codex/plugin/components/ulw-loop/dist/checkpoint-template.d.ts +8 -0
  170. package/packages/omo-codex/plugin/components/ulw-loop/dist/checkpoint-template.js +120 -0
  171. package/packages/omo-codex/plugin/components/ulw-loop/dist/checkpoint.js +40 -39
  172. package/packages/omo-codex/plugin/components/ulw-loop/dist/cli-commands.js +7 -2
  173. package/packages/omo-codex/plugin/components/ulw-loop/dist/cli-output.d.ts +2 -1
  174. package/packages/omo-codex/plugin/components/ulw-loop/dist/cli-output.js +12 -1
  175. package/packages/omo-codex/plugin/components/ulw-loop/dist/cli-subcommands.js +2 -0
  176. package/packages/omo-codex/plugin/components/ulw-loop/dist/cli.js +958 -342
  177. package/packages/omo-codex/plugin/components/ulw-loop/dist/codex-goal-instruction.d.ts +2 -0
  178. package/packages/omo-codex/plugin/components/ulw-loop/dist/codex-goal-instruction.js +27 -6
  179. package/packages/omo-codex/plugin/components/ulw-loop/dist/codex-goal-snapshot.d.ts +13 -0
  180. package/packages/omo-codex/plugin/components/ulw-loop/dist/codex-goal-snapshot.js +15 -1
  181. package/packages/omo-codex/plugin/components/ulw-loop/dist/domain-types.d.ts +17 -9
  182. package/packages/omo-codex/plugin/components/ulw-loop/dist/paths.js +1 -1
  183. package/packages/omo-codex/plugin/components/ulw-loop/dist/plan-io.js +17 -2
  184. package/packages/omo-codex/plugin/components/ulw-loop/dist/plan-missing-recovery.d.ts +13 -0
  185. package/packages/omo-codex/plugin/components/ulw-loop/dist/plan-missing-recovery.js +19 -0
  186. package/packages/omo-codex/plugin/components/ulw-loop/dist/quality-gate-aggregate.d.ts +7 -0
  187. package/packages/omo-codex/plugin/components/ulw-loop/dist/quality-gate-aggregate.js +9 -0
  188. package/packages/omo-codex/plugin/components/ulw-loop/dist/quality-gate-artifacts.d.ts +12 -0
  189. package/packages/omo-codex/plugin/components/ulw-loop/dist/quality-gate-artifacts.js +104 -0
  190. package/packages/omo-codex/plugin/components/ulw-loop/dist/quality-gate-fields.d.ts +13 -1
  191. package/packages/omo-codex/plugin/components/ulw-loop/dist/quality-gate-fields.js +65 -9
  192. package/packages/omo-codex/plugin/components/ulw-loop/dist/quality-gate-verdicts.js +5 -1
  193. package/packages/omo-codex/plugin/components/ulw-loop/dist/quality-gate.d.ts +4 -2
  194. package/packages/omo-codex/plugin/components/ulw-loop/dist/quality-gate.js +69 -111
  195. package/packages/omo-codex/plugin/components/ulw-loop/dist/review-blockers.js +4 -2
  196. package/packages/omo-codex/plugin/components/ulw-loop/dist/spawn-guard.js +185 -14
  197. package/packages/omo-codex/plugin/components/ulw-loop/dist/status-next-actions.d.ts +6 -0
  198. package/packages/omo-codex/plugin/components/ulw-loop/dist/status-next-actions.js +33 -0
  199. package/packages/omo-codex/plugin/components/ulw-loop/dist/stop-resume-hook.js +3 -3
  200. package/packages/omo-codex/plugin/components/ulw-loop/dist/surface.d.ts +18 -0
  201. package/packages/omo-codex/plugin/components/ulw-loop/dist/surface.js +65 -0
  202. package/packages/omo-codex/plugin/components/ulw-loop/hooks/hooks.json +4 -4
  203. package/packages/omo-codex/plugin/components/ulw-loop/package.json +5 -5
  204. package/packages/omo-codex/plugin/components/ulw-loop/skills/ulw-loop/SKILL.md +4 -3
  205. package/packages/omo-codex/plugin/components/ulw-loop/skills/ulw-loop/references/define-goal.md +108 -0
  206. package/packages/omo-codex/plugin/components/ulw-loop/skills/ulw-loop/references/full-workflow.md +22 -1
  207. package/packages/omo-codex/plugin/components/ulw-loop/src/checkpoint-codex-validation.ts +81 -0
  208. package/packages/omo-codex/plugin/components/ulw-loop/src/checkpoint-continuation.ts +7 -0
  209. package/packages/omo-codex/plugin/components/ulw-loop/src/checkpoint-reconciliation.ts +31 -1
  210. package/packages/omo-codex/plugin/components/ulw-loop/src/checkpoint-template.ts +134 -0
  211. package/packages/omo-codex/plugin/components/ulw-loop/src/checkpoint.ts +38 -71
  212. package/packages/omo-codex/plugin/components/ulw-loop/src/cli-commands.ts +7 -2
  213. package/packages/omo-codex/plugin/components/ulw-loop/src/cli-output.ts +14 -1
  214. package/packages/omo-codex/plugin/components/ulw-loop/src/cli-subcommands.ts +2 -0
  215. package/packages/omo-codex/plugin/components/ulw-loop/src/cli.ts +3 -5
  216. package/packages/omo-codex/plugin/components/ulw-loop/src/codex-goal-instruction.ts +34 -5
  217. package/packages/omo-codex/plugin/components/ulw-loop/src/codex-goal-snapshot.ts +26 -1
  218. package/packages/omo-codex/plugin/components/ulw-loop/src/codex-hook.ts +3 -1
  219. package/packages/omo-codex/plugin/components/ulw-loop/src/domain-types.ts +19 -9
  220. package/packages/omo-codex/plugin/components/ulw-loop/src/paths.ts +1 -1
  221. package/packages/omo-codex/plugin/components/ulw-loop/src/plan-io.ts +18 -3
  222. package/packages/omo-codex/plugin/components/ulw-loop/src/plan-missing-recovery.ts +27 -0
  223. package/packages/omo-codex/plugin/components/ulw-loop/src/quality-gate-aggregate.ts +11 -0
  224. package/packages/omo-codex/plugin/components/ulw-loop/src/quality-gate-artifacts.ts +123 -0
  225. package/packages/omo-codex/plugin/components/ulw-loop/src/quality-gate-fields.ts +68 -15
  226. package/packages/omo-codex/plugin/components/ulw-loop/src/quality-gate-verdicts.ts +6 -1
  227. package/packages/omo-codex/plugin/components/ulw-loop/src/quality-gate.ts +82 -131
  228. package/packages/omo-codex/plugin/components/ulw-loop/src/review-blockers.ts +4 -2
  229. package/packages/omo-codex/plugin/components/ulw-loop/src/spawn-guard.ts +187 -12
  230. package/packages/omo-codex/plugin/components/ulw-loop/src/status-next-actions.ts +36 -0
  231. package/packages/omo-codex/plugin/components/ulw-loop/src/stop-resume-hook.ts +3 -3
  232. package/packages/omo-codex/plugin/components/ulw-loop/src/surface.ts +95 -0
  233. package/packages/omo-codex/plugin/components/ulw-loop/test/checkpoint-continuation.test.ts +0 -1
  234. package/packages/omo-codex/plugin/components/ulw-loop/test/checkpoint-final.test.ts +133 -1
  235. package/packages/omo-codex/plugin/components/ulw-loop/test/checkpoint-template.test.ts +137 -0
  236. package/packages/omo-codex/plugin/components/ulw-loop/test/cli-create-goals.test.ts +25 -0
  237. package/packages/omo-codex/plugin/components/ulw-loop/test/cli-entrypoint.test.ts +26 -2
  238. package/packages/omo-codex/plugin/components/ulw-loop/test/cli-status-next-actions.test.ts +183 -0
  239. package/packages/omo-codex/plugin/components/ulw-loop/test/codex-goal-instruction.test.ts +37 -2
  240. package/packages/omo-codex/plugin/components/ulw-loop/test/codex-goal-snapshot.test.ts +18 -0
  241. package/packages/omo-codex/plugin/components/ulw-loop/test/codex-hook.test.ts +0 -3
  242. package/packages/omo-codex/plugin/components/ulw-loop/test/fixtures/quality-gate-builder.ts +7 -3
  243. package/packages/omo-codex/plugin/components/ulw-loop/test/guided-recovery.test.ts +105 -0
  244. package/packages/omo-codex/plugin/components/ulw-loop/test/package-smoke.test.ts +5 -37
  245. package/packages/omo-codex/plugin/components/ulw-loop/test/paths.test.ts +9 -0
  246. package/packages/omo-codex/plugin/components/ulw-loop/test/quality-gate-aggregate-basics.test.ts +258 -0
  247. package/packages/omo-codex/plugin/components/ulw-loop/test/quality-gate-cap-and-dedupe.test.ts +22 -0
  248. package/packages/omo-codex/plugin/components/ulw-loop/test/quality-gate-poisoning-cascades.test.ts +97 -0
  249. package/packages/omo-codex/plugin/components/ulw-loop/test/quality-gate-roles.test.ts +46 -2
  250. package/packages/omo-codex/plugin/components/ulw-loop/test/quality-gate-senpi-surface.test.ts +131 -0
  251. package/packages/omo-codex/plugin/components/ulw-loop/test/quality-gate-single-report.test.ts +241 -0
  252. package/packages/omo-codex/plugin/components/ulw-loop/test/quality-gate.test.ts +48 -3
  253. package/packages/omo-codex/plugin/components/ulw-loop/test/spawn-guard.test.ts +318 -1
  254. package/packages/omo-codex/plugin/components/ulw-loop/test/steering.test.ts +8 -5
  255. package/packages/omo-codex/plugin/components/ulw-loop/test/stop-resume-hook.test.ts +1 -1
  256. package/packages/omo-codex/plugin/components/ulw-loop/test/surface.test.ts +74 -0
  257. package/packages/omo-codex/plugin/components/ulw-loop/test/ultrawork-directive.test.ts +13 -8
  258. package/packages/omo-codex/plugin/components/ulw-loop/vitest.config.ts +1 -0
  259. package/packages/omo-codex/plugin/hooks/post-compact-resetting-git-bash-mcp-reminder.json +1 -1
  260. package/packages/omo-codex/plugin/hooks/post-compact-resetting-lsp-diagnostics-cache.json +1 -1
  261. package/packages/omo-codex/plugin/hooks/post-compact-resetting-project-rule-cache.json +1 -1
  262. package/packages/omo-codex/plugin/hooks/post-tool-use-checking-comments.json +1 -1
  263. package/packages/omo-codex/plugin/hooks/post-tool-use-checking-lsp-diagnostics.json +1 -1
  264. package/packages/omo-codex/plugin/hooks/post-tool-use-checking-thread-title-hygiene.json +1 -1
  265. package/packages/omo-codex/plugin/hooks/post-tool-use-matching-project-rules.json +1 -1
  266. package/packages/omo-codex/plugin/hooks/pre-tool-use-enforcing-unlimited-goal-budget.json +1 -1
  267. package/packages/omo-codex/plugin/hooks/pre-tool-use-guarding-ulw-loop-spawns.json +1 -1
  268. package/packages/omo-codex/plugin/hooks/pre-tool-use-recommending-git-bash-mcp.json +1 -1
  269. package/packages/omo-codex/plugin/hooks/session-start-checking-auto-update.json +1 -1
  270. package/packages/omo-codex/plugin/hooks/session-start-checking-bootstrap-provisioning.json +1 -1
  271. package/packages/omo-codex/plugin/hooks/session-start-loading-project-rules.json +1 -1
  272. package/packages/omo-codex/plugin/hooks/session-start-recording-session-telemetry.json +1 -1
  273. package/packages/omo-codex/plugin/hooks/stop-checking-ulw-execute-continuation.json +17 -0
  274. package/packages/omo-codex/plugin/hooks/stop-checking-ulw-loop-resume.json +1 -1
  275. package/packages/omo-codex/plugin/hooks/subagent-stop-checking-ulw-execute-continuation.json +17 -0
  276. package/packages/omo-codex/plugin/hooks/subagent-stop-verifying-lazycodex-executor-evidence.json +1 -1
  277. package/packages/omo-codex/plugin/hooks/user-prompt-submit-checking-ultrawork-trigger.json +1 -1
  278. package/packages/omo-codex/plugin/hooks/user-prompt-submit-checking-ulw-loop-steering.json +1 -1
  279. package/packages/omo-codex/plugin/hooks/user-prompt-submit-loading-project-rules.json +1 -1
  280. package/packages/omo-codex/plugin/model-catalog.json +3 -3
  281. package/packages/omo-codex/plugin/package-lock.json +676 -524
  282. package/packages/omo-codex/plugin/package.json +2 -3
  283. package/packages/omo-codex/plugin/scripts/AGENTS.md +39 -0
  284. package/packages/omo-codex/plugin/scripts/auto-update-plan.mjs +1 -2
  285. package/packages/omo-codex/plugin/scripts/auto-update.mjs +0 -9
  286. package/packages/omo-codex/plugin/scripts/canonical-ultrawork-directive.mjs +17 -0
  287. package/packages/omo-codex/plugin/scripts/hook-status-message.mjs +0 -1
  288. package/packages/omo-codex/plugin/scripts/migrate-codex-config/catalog.mjs +3 -3
  289. package/packages/omo-codex/plugin/scripts/sync-skills.mjs +42 -31
  290. package/packages/omo-codex/plugin/shared/package.json +3 -4
  291. package/packages/omo-codex/plugin/shared/src/config-loader.ts +2 -102
  292. package/packages/omo-codex/plugin/shared/src/config-migration.ts +0 -1
  293. package/packages/omo-codex/plugin/shared/test/config-loader.test.ts +41 -130
  294. package/packages/omo-codex/plugin/skills/ast-grep/AGENTS.md +51 -0
  295. package/packages/omo-codex/plugin/skills/ast-grep/SKILL.md +1 -1
  296. package/packages/omo-codex/plugin/skills/coding-agent-sessions/AGENTS.md +62 -0
  297. package/packages/omo-codex/plugin/skills/coding-agent-sessions/SKILL.md +3 -2
  298. package/packages/omo-codex/plugin/skills/coding-agent-sessions/references/all-platforms.md +1 -1
  299. package/packages/omo-codex/plugin/skills/coding-agent-sessions/references/senpi.md +4 -4
  300. package/packages/omo-codex/plugin/skills/coding-agent-sessions/scripts/agent_sessions/pi_family.py +1 -1
  301. package/packages/omo-codex/plugin/skills/data-scientist/SKILL.md +99 -239
  302. package/packages/omo-codex/plugin/skills/data-scientist/references/execution-surfaces.md +91 -0
  303. package/packages/omo-codex/plugin/skills/data-scientist/references/placement.md +74 -0
  304. package/packages/omo-codex/plugin/skills/data-scientist/references/polars-lane.md +95 -0
  305. package/packages/omo-codex/plugin/skills/data-scientist/references/uv-setup.md +1 -1
  306. package/packages/omo-codex/plugin/skills/data-scientist/references/visualization.md +64 -0
  307. package/packages/omo-codex/plugin/skills/data-scientist/scripts/ensure-js-deps.sh +28 -0
  308. package/packages/omo-codex/plugin/skills/data-scientist/scripts/ensure-py-deps.sh +37 -0
  309. package/packages/omo-codex/plugin/skills/debugging/SKILL.md +3 -1
  310. package/packages/omo-codex/plugin/skills/debugging/references/methodology/00-setup.md +12 -0
  311. package/packages/omo-codex/plugin/skills/debugging/references/methodology/02-investigate.md +21 -0
  312. package/packages/omo-codex/plugin/skills/debugging/references/runtimes/go.md +15 -1
  313. package/packages/omo-codex/plugin/skills/debugging/references/runtimes/native-binary.md +38 -0
  314. package/packages/omo-codex/plugin/skills/debugging/references/runtimes/node.md +25 -0
  315. package/packages/omo-codex/plugin/skills/debugging/references/runtimes/python.md +13 -0
  316. package/packages/omo-codex/plugin/skills/debugging/references/runtimes/rust.md +41 -0
  317. package/packages/omo-codex/plugin/skills/debugging/references/scripts/dap.mjs +267 -0
  318. package/packages/omo-codex/plugin/skills/debugging/references/scripts/fixture-adapter.mjs +59 -0
  319. package/packages/omo-codex/plugin/skills/debugging/references/tools/dap.md +103 -0
  320. package/packages/omo-codex/plugin/skills/debugging/references/tools/frida.md +193 -0
  321. package/packages/omo-codex/plugin/skills/frontend/SKILL.md +12 -8
  322. package/packages/omo-codex/plugin/skills/frontend/references/design/_INDEX.md +1 -0
  323. package/packages/omo-codex/plugin/skills/frontend/references/design/print-paged-media.md +76 -0
  324. package/packages/omo-codex/plugin/skills/frontend/references/design/stylegallery.md +80 -0
  325. package/packages/omo-codex/plugin/skills/frontend/references/designpowers/README.md +1 -1
  326. package/packages/omo-codex/plugin/skills/frontend/references/designpowers/lane-a-direction.md +1 -1
  327. package/packages/omo-codex/plugin/skills/frontend/references/designpowers/lane-b-execution.md +11 -11
  328. package/packages/omo-codex/plugin/skills/frontend/references/designpowers/lane-d-memory.md +3 -3
  329. package/packages/omo-codex/plugin/skills/frontend/references/designpowers/orchestration.md +1 -1
  330. package/packages/omo-codex/plugin/skills/frontend/references/designpowers/routing.md +5 -5
  331. package/packages/omo-codex/plugin/skills/git-master/SKILL.md +1 -1
  332. package/packages/omo-codex/plugin/skills/init-deep/SKILL.md +14 -14
  333. package/packages/omo-codex/plugin/skills/lcx-doctor/SKILL.md +1 -1
  334. package/packages/omo-codex/plugin/skills/lsp-setup/SKILL.md +1 -1
  335. package/packages/omo-codex/plugin/skills/programming/SKILL.md +1 -1
  336. package/packages/omo-codex/plugin/skills/refactor/SKILL.md +1 -1
  337. package/packages/omo-codex/plugin/skills/remove-ai-slops/SKILL.md +1 -1
  338. package/packages/omo-codex/plugin/skills/review-work/SKILL.md +101 -419
  339. package/packages/omo-codex/plugin/skills/ultimate-browsing/ATTRIBUTION.md +38 -11
  340. package/packages/omo-codex/plugin/skills/ultimate-browsing/SKILL.md +26 -9
  341. package/packages/omo-codex/plugin/skills/ultimate-browsing/engine/AGENTS.md +110 -0
  342. package/packages/omo-codex/plugin/skills/ultimate-browsing/engine/templates/package.json +1 -1
  343. package/packages/omo-codex/plugin/skills/ultimate-browsing/references/chrome-stealth.md +23 -18
  344. package/packages/omo-codex/plugin/skills/ultimate-browsing/references/insane-search/README.md +9 -2
  345. package/packages/omo-codex/plugin/skills/ultrawork/SKILL.md +15 -3
  346. package/packages/omo-codex/plugin/skills/{start-work → ulw-execute}/SKILL.md +19 -26
  347. package/packages/omo-codex/plugin/skills/ulw-execute/agents/openai.yaml +2 -0
  348. package/packages/omo-codex/plugin/skills/ulw-loop/SKILL.md +4 -3
  349. package/packages/omo-codex/plugin/skills/ulw-loop/references/define-goal.md +108 -0
  350. package/packages/omo-codex/plugin/skills/ulw-loop/references/full-workflow.md +22 -1
  351. package/packages/omo-codex/plugin/skills/ulw-plan/SKILL.md +6 -7
  352. package/packages/omo-codex/plugin/skills/ulw-plan/references/full-workflow.md +31 -7
  353. package/packages/omo-codex/plugin/skills/ulw-plan/references/intent-clear.md +2 -1
  354. package/packages/omo-codex/plugin/skills/ulw-plan/references/intent-unclear.md +5 -5
  355. package/packages/omo-codex/plugin/skills/ulw-research/SKILL.md +8 -3
  356. package/packages/omo-codex/plugin/skills/visual-qa/AGENTS.md +58 -0
  357. package/packages/omo-codex/plugin/skills/visual-qa/SKILL.md +4 -3
  358. package/packages/omo-codex/plugin/test/AGENTS.md +47 -0
  359. package/packages/omo-codex/plugin/test/aggregate-agents.test.mjs +19 -173
  360. package/packages/omo-codex/plugin/test/aggregate-hooks.test.mjs +9 -48
  361. package/packages/omo-codex/plugin/test/aggregate-manifest.test.mjs +2 -3
  362. package/packages/omo-codex/plugin/test/aggregate-mcp.test.mjs +2 -7
  363. package/packages/omo-codex/plugin/test/aggregate-model-catalog.test.mjs +1 -1
  364. package/packages/omo-codex/plugin/test/aggregate-plugin-fixture.mjs +175 -13
  365. package/packages/omo-codex/plugin/test/aggregate.test.mjs +78 -2
  366. package/packages/omo-codex/plugin/test/auto-update-release-notes.test.mjs +19 -33
  367. package/packages/omo-codex/plugin/test/auto-update.test.mjs +2 -27
  368. package/packages/omo-codex/plugin/test/bootstrap-setup.test.mjs +0 -31
  369. package/packages/omo-codex/plugin/test/canonical-ultrawork-directive.test.mjs +53 -0
  370. package/packages/omo-codex/plugin/test/component-bin-names.test.mjs +2 -2
  371. package/packages/omo-codex/plugin/test/component-bundled-cli.test.mjs +1 -51
  372. package/packages/omo-codex/plugin/test/component-hook-contract-cases.mjs +2 -2
  373. package/packages/omo-codex/plugin/test/hook-status-message.test.mjs +4 -5
  374. package/packages/omo-codex/plugin/test/lcx-contribute-bug-fix-template.test.mjs +21 -27
  375. package/packages/omo-codex/plugin/test/mcp-research-servers.test.mjs +1 -3
  376. package/packages/omo-codex/plugin/test/migrate-codex-config.test.mjs +8 -8
  377. package/packages/omo-codex/plugin/test/scaffold-plan.test.mjs +0 -36
  378. package/packages/omo-codex/plugin/test/sync-skills-codex-compatibility.test.mjs +101 -0
  379. package/packages/omo-codex/plugin/test/sync-skills-test-support.mjs +24 -14
  380. package/packages/omo-codex/plugin/test/sync-skills.test.mjs +14 -119
  381. package/packages/omo-codex/plugin/test/teammode-archive-ambiguity.test.mjs +0 -40
  382. package/packages/omo-codex/plugin/test/teammode-communication.test.mjs +6 -62
  383. package/packages/omo-codex/plugin/test/teammode-thread-links.test.mjs +3 -36
  384. package/packages/omo-codex/plugin/test/teammode-transport.test.mjs +0 -44
  385. package/packages/omo-codex/plugin/test/teammode-worktree.test.mjs +2 -6
  386. package/packages/omo-codex/plugin/test/ultrawork-skill-pointer.test.mjs +5 -5
  387. package/packages/omo-codex/plugin/test/ulw-plan-review-state-contract.test.mjs +0 -3
  388. package/packages/omo-codex/scripts/install-dist/install-local.mjs +2818 -913
  389. package/packages/{omo-codex/plugin/components/ultrawork/skills/ultrawork/SKILL.md → prompts-core/prompts/ultrawork/codex.md} +15 -10
  390. package/packages/shared-skills/package.json +7 -1
  391. package/packages/shared-skills/skills/ast-grep/AGENTS.md +51 -0
  392. package/packages/shared-skills/skills/ast-grep/SKILL.md +1 -1
  393. package/packages/shared-skills/skills/coding-agent-sessions/AGENTS.md +62 -0
  394. package/packages/shared-skills/skills/coding-agent-sessions/SKILL.md +3 -2
  395. package/packages/shared-skills/skills/coding-agent-sessions/references/all-platforms.md +1 -1
  396. package/packages/shared-skills/skills/coding-agent-sessions/references/senpi.md +4 -4
  397. package/packages/shared-skills/skills/coding-agent-sessions/scripts/agent_sessions/pi_family.py +1 -1
  398. package/packages/shared-skills/skills/data-scientist/SKILL.md +99 -239
  399. package/packages/shared-skills/skills/data-scientist/references/execution-surfaces.md +91 -0
  400. package/packages/shared-skills/skills/data-scientist/references/placement.md +74 -0
  401. package/packages/shared-skills/skills/data-scientist/references/polars-lane.md +95 -0
  402. package/packages/shared-skills/skills/data-scientist/references/uv-setup.md +1 -1
  403. package/packages/shared-skills/skills/data-scientist/references/visualization.md +64 -0
  404. package/packages/shared-skills/skills/data-scientist/scripts/ensure-js-deps.sh +28 -0
  405. package/packages/shared-skills/skills/data-scientist/scripts/ensure-py-deps.sh +37 -0
  406. package/packages/shared-skills/skills/debugging/SKILL.md +3 -1
  407. package/packages/shared-skills/skills/debugging/references/methodology/00-setup.md +12 -0
  408. package/packages/shared-skills/skills/debugging/references/methodology/02-investigate.md +21 -0
  409. package/packages/shared-skills/skills/debugging/references/runtimes/go.md +15 -1
  410. package/packages/shared-skills/skills/debugging/references/runtimes/native-binary.md +38 -0
  411. package/packages/shared-skills/skills/debugging/references/runtimes/node.md +25 -0
  412. package/packages/shared-skills/skills/debugging/references/runtimes/python.md +13 -0
  413. package/packages/shared-skills/skills/debugging/references/runtimes/rust.md +41 -0
  414. package/packages/shared-skills/skills/debugging/references/scripts/dap.mjs +267 -0
  415. package/packages/shared-skills/skills/debugging/references/scripts/dap.test.ts +86 -0
  416. package/packages/shared-skills/skills/debugging/references/scripts/fixture-adapter.mjs +59 -0
  417. package/packages/shared-skills/skills/debugging/references/tools/dap.md +103 -0
  418. package/packages/shared-skills/skills/debugging/references/tools/frida.md +193 -0
  419. package/packages/shared-skills/skills/frontend/SKILL.md +12 -8
  420. package/packages/shared-skills/skills/frontend/references/design/_INDEX.md +1 -0
  421. package/packages/shared-skills/skills/frontend/references/design/print-paged-media.md +76 -0
  422. package/packages/shared-skills/skills/frontend/references/design/stylegallery.md +80 -0
  423. package/packages/shared-skills/skills/frontend/references/designpowers/README.md +1 -1
  424. package/packages/shared-skills/skills/frontend/references/designpowers/lane-a-direction.md +1 -1
  425. package/packages/shared-skills/skills/frontend/references/designpowers/lane-b-execution.md +11 -11
  426. package/packages/shared-skills/skills/frontend/references/designpowers/lane-d-memory.md +3 -3
  427. package/packages/shared-skills/skills/frontend/references/designpowers/orchestration.md +1 -1
  428. package/packages/shared-skills/skills/frontend/references/designpowers/routing.md +5 -5
  429. package/packages/shared-skills/skills/git-master/SKILL.md +1 -1
  430. package/packages/shared-skills/skills/init-deep/SKILL.md +14 -14
  431. package/packages/shared-skills/skills/lsp-setup/SKILL.md +1 -1
  432. package/packages/shared-skills/skills/programming/SKILL.md +1 -1
  433. package/packages/shared-skills/skills/refactor/SKILL.md +1 -1
  434. package/packages/shared-skills/skills/remove-ai-slops/SKILL.md +1 -1
  435. package/packages/shared-skills/skills/review-work/SKILL.md +100 -418
  436. package/packages/shared-skills/skills/ultimate-browsing/ATTRIBUTION.md +38 -11
  437. package/packages/shared-skills/skills/ultimate-browsing/SKILL.md +26 -9
  438. package/packages/shared-skills/skills/ultimate-browsing/engine/AGENTS.md +110 -0
  439. package/packages/shared-skills/skills/ultimate-browsing/engine/templates/package.json +1 -1
  440. package/packages/shared-skills/skills/ultimate-browsing/references/chrome-stealth.md +23 -18
  441. package/packages/shared-skills/skills/ultimate-browsing/references/insane-search/README.md +9 -2
  442. package/packages/shared-skills/skills/{start-work → ulw-execute}/SKILL.md +17 -16
  443. package/packages/shared-skills/skills/ulw-plan/SKILL.md +7 -8
  444. package/packages/shared-skills/skills/ulw-plan/references/full-workflow.md +31 -7
  445. package/packages/shared-skills/skills/ulw-plan/references/intent-clear.md +2 -1
  446. package/packages/shared-skills/skills/ulw-plan/references/intent-unclear.md +5 -5
  447. package/packages/shared-skills/skills/ulw-research/SKILL.md +8 -3
  448. package/packages/shared-skills/skills/visual-qa/AGENTS.md +58 -0
  449. package/packages/shared-skills/skills/visual-qa/SKILL.md +4 -3
  450. package/script/qa/web-terminal-visual-qa.mjs +2 -0
  451. package/script/qa/xterm-live-terminal.mjs +18 -2
  452. package/packages/lsp-tools-mcp/dist/lsp/cleanup-errors.d.ts +0 -1
  453. package/packages/lsp-tools-mcp/dist/lsp/constants.d.ts +0 -1
  454. package/packages/lsp-tools-mcp/dist/lsp/language-mappings.d.ts +0 -1
  455. package/packages/lsp-tools-mcp/dist/lsp/process-signal-cleanup.d.ts +0 -1
  456. package/packages/lsp-tools-mcp/dist/missing-dependency-result.d.ts +0 -1
  457. package/packages/omo-codex/plugin/components/codegraph/AGENTS.md +0 -58
  458. package/packages/omo-codex/plugin/components/codegraph/NODE-RUNTIME-LICENSES.md +0 -2951
  459. package/packages/omo-codex/plugin/components/codegraph/NOTICE +0 -16
  460. package/packages/omo-codex/plugin/components/codegraph/dist/cli.js +0 -12136
  461. package/packages/omo-codex/plugin/components/codegraph/dist/serve.js +0 -9734
  462. package/packages/omo-codex/plugin/components/codegraph/package.json +0 -33
  463. package/packages/omo-codex/plugin/components/codegraph/src/cache-gc.ts +0 -29
  464. package/packages/omo-codex/plugin/components/codegraph/src/cli.ts +0 -79
  465. package/packages/omo-codex/plugin/components/codegraph/src/hook-input.ts +0 -33
  466. package/packages/omo-codex/plugin/components/codegraph/src/hook-sweep.ts +0 -25
  467. package/packages/omo-codex/plugin/components/codegraph/src/hook-types.ts +0 -131
  468. package/packages/omo-codex/plugin/components/codegraph/src/hook.ts +0 -258
  469. package/packages/omo-codex/plugin/components/codegraph/src/mcp-bridge.ts +0 -309
  470. package/packages/omo-codex/plugin/components/codegraph/src/mcp-unavailable.ts +0 -80
  471. package/packages/omo-codex/plugin/components/codegraph/src/post-tool-use-hook.ts +0 -34
  472. package/packages/omo-codex/plugin/components/codegraph/src/serve-invocation.ts +0 -29
  473. package/packages/omo-codex/plugin/components/codegraph/src/serve.ts +0 -263
  474. package/packages/omo-codex/plugin/components/codegraph/src/session-start-command.ts +0 -106
  475. package/packages/omo-codex/plugin/components/codegraph/src/session-start-cooldown.ts +0 -145
  476. package/packages/omo-codex/plugin/components/codegraph/src/session-start-hook-runtime.ts +0 -21
  477. package/packages/omo-codex/plugin/components/codegraph/src/session-start-lock.ts +0 -139
  478. package/packages/omo-codex/plugin/components/codegraph/src/session-start-outcome.ts +0 -15
  479. package/packages/omo-codex/plugin/components/codegraph/src/session-start-paths.ts +0 -32
  480. package/packages/omo-codex/plugin/components/codegraph/src/session-start-project.ts +0 -109
  481. package/packages/omo-codex/plugin/components/codegraph/src/session-start-worker-result.ts +0 -148
  482. package/packages/omo-codex/plugin/components/codegraph/src/session-start-worker.ts +0 -175
  483. package/packages/omo-codex/plugin/components/codegraph/src/sweep-cli.ts +0 -81
  484. package/packages/omo-codex/plugin/components/codegraph/test/cache-gc.test.ts +0 -34
  485. package/packages/omo-codex/plugin/components/codegraph/test/hook-exclusion.test.ts +0 -112
  486. package/packages/omo-codex/plugin/components/codegraph/test/hook-registration.test.ts +0 -26
  487. package/packages/omo-codex/plugin/components/codegraph/test/hook-session-start-guard.test.ts +0 -160
  488. package/packages/omo-codex/plugin/components/codegraph/test/hook-store-upgrade.test.ts +0 -50
  489. package/packages/omo-codex/plugin/components/codegraph/test/hook-sweep.test.ts +0 -29
  490. package/packages/omo-codex/plugin/components/codegraph/test/hook.test.ts +0 -320
  491. package/packages/omo-codex/plugin/components/codegraph/test/mcp-bridge-fixtures.ts +0 -172
  492. package/packages/omo-codex/plugin/components/codegraph/test/package-runtime.test.ts +0 -91
  493. package/packages/omo-codex/plugin/components/codegraph/test/provisioned-node-guard.test.ts +0 -100
  494. package/packages/omo-codex/plugin/components/codegraph/test/serve-built-wrapper.test.ts +0 -76
  495. package/packages/omo-codex/plugin/components/codegraph/test/serve-mcp-bridge-lifecycle.test.ts +0 -133
  496. package/packages/omo-codex/plugin/components/codegraph/test/serve-mcp-bridge.test.ts +0 -245
  497. package/packages/omo-codex/plugin/components/codegraph/test/serve-mcp-facade.test.ts +0 -69
  498. package/packages/omo-codex/plugin/components/codegraph/test/serve-node-support.test.ts +0 -43
  499. package/packages/omo-codex/plugin/components/codegraph/test/serve-provision.test.ts +0 -147
  500. package/packages/omo-codex/plugin/components/codegraph/test/serve-unavailable.test.ts +0 -175
  501. package/packages/omo-codex/plugin/components/codegraph/test/serve.test.ts +0 -385
  502. package/packages/omo-codex/plugin/components/codegraph/test/session-start-node-support.test.ts +0 -206
  503. package/packages/omo-codex/plugin/components/codegraph/test/session-start-project.test.ts +0 -58
  504. package/packages/omo-codex/plugin/components/codegraph/test/session-start-state.test.ts +0 -104
  505. package/packages/omo-codex/plugin/components/codegraph/test/session-start-trust-boundary.test.ts +0 -65
  506. package/packages/omo-codex/plugin/components/codegraph/test/session-start-worker-availability.test.ts +0 -106
  507. package/packages/omo-codex/plugin/components/codegraph/test/session-start-worker-cooldown.test.ts +0 -116
  508. package/packages/omo-codex/plugin/components/codegraph/test/session-start-worker-flow.test.ts +0 -258
  509. package/packages/omo-codex/plugin/components/codegraph/test/sweep-cli.test.ts +0 -56
  510. package/packages/omo-codex/plugin/components/codegraph/tsconfig.build.json +0 -13
  511. package/packages/omo-codex/plugin/components/codegraph/tsconfig.json +0 -25
  512. package/packages/omo-codex/plugin/components/start-work-continuation/LICENSE +0 -21
  513. package/packages/omo-codex/plugin/components/start-work-continuation/hooks/hooks.json +0 -28
  514. package/packages/omo-codex/plugin/components/ultrawork/directive.md +0 -471
  515. package/packages/omo-codex/plugin/hooks/post-tool-use-checking-codegraph-init-guidance.json +0 -18
  516. package/packages/omo-codex/plugin/hooks/session-start-checking-codegraph-bootstrap.json +0 -17
  517. package/packages/omo-codex/plugin/hooks/stop-checking-start-work-continuation.json +0 -17
  518. package/packages/omo-codex/plugin/hooks/subagent-stop-checking-start-work-continuation.json +0 -17
  519. package/packages/omo-codex/plugin/scripts/migrate-omo-sot/editor.mjs +0 -125
  520. package/packages/omo-codex/plugin/scripts/migrate-omo-sot/jsonc.mjs +0 -43
  521. package/packages/omo-codex/plugin/scripts/migrate-omo-sot/scaffold.mjs +0 -29
  522. package/packages/omo-codex/plugin/scripts/migrate-omo-sot.mjs +0 -121
  523. package/packages/omo-codex/plugin/skills/data-scientist/references/common-scenarios.md +0 -176
  524. package/packages/omo-codex/plugin/skills/data-scientist/references/execution-templates.md +0 -197
  525. package/packages/omo-codex/plugin/skills/data-scientist/references/integration-patterns.md +0 -153
  526. package/packages/omo-codex/plugin/skills/data-scientist/references/performance-benchmarks.md +0 -37
  527. package/packages/omo-codex/plugin/skills/start-work/agents/openai.yaml +0 -2
  528. package/packages/omo-codex/plugin/test/aggregate-skills.test.mjs +0 -92
  529. package/packages/omo-codex/plugin/test/component-codegraph-mcp-smoke.test.mjs +0 -76
  530. package/packages/omo-codex/plugin/test/migrate-omo-sot.test.mjs +0 -179
  531. package/packages/omo-codex/plugin/test/sync-skills-orchestration.test.mjs +0 -314
  532. package/packages/omo-codex/plugin/test/ulw-plan-scope-contract.test.mjs +0 -24
  533. package/packages/shared-skills/skills/data-scientist/references/common-scenarios.md +0 -176
  534. package/packages/shared-skills/skills/data-scientist/references/execution-templates.md +0 -197
  535. package/packages/shared-skills/skills/data-scientist/references/integration-patterns.md +0 -153
  536. package/packages/shared-skills/skills/data-scientist/references/performance-benchmarks.md +0 -37
  537. /package/packages/omo-codex/plugin/components/{start-work-continuation → ulw-execute-continuation}/.gitattributes +0 -0
  538. /package/packages/omo-codex/plugin/components/{start-work-continuation → ulw-execute-continuation}/CHANGELOG.md +0 -0
  539. /package/packages/omo-codex/plugin/components/{codegraph → ulw-execute-continuation}/LICENSE +0 -0
  540. /package/packages/omo-codex/plugin/components/{start-work-continuation → ulw-execute-continuation}/src/plan-checklist.ts +0 -0
  541. /package/packages/omo-codex/plugin/components/{start-work-continuation → ulw-execute-continuation}/src/types.ts +0 -0
  542. /package/packages/omo-codex/plugin/components/{start-work-continuation → ulw-execute-continuation}/test/fixtures/boulder-completed.json +0 -0
  543. /package/packages/omo-codex/plugin/components/{start-work-continuation → ulw-execute-continuation}/test/fixtures/boulder-mixed-platforms.json +0 -0
  544. /package/packages/omo-codex/plugin/components/{start-work-continuation → ulw-execute-continuation}/test/fixtures/boulder-single-codex-work.json +0 -0
  545. /package/packages/omo-codex/plugin/components/{start-work-continuation → ulw-execute-continuation}/test/fixtures/plan-all-done.md +0 -0
  546. /package/packages/omo-codex/plugin/components/{start-work-continuation → ulw-execute-continuation}/test/fixtures/plan-scaffold.md +0 -0
  547. /package/packages/omo-codex/plugin/components/{start-work-continuation → ulw-execute-continuation}/test/fixtures/plan-with-nested-checkboxes.md +0 -0
  548. /package/packages/omo-codex/plugin/components/{start-work-continuation → ulw-execute-continuation}/test/fixtures/plan-with-unchecked.md +0 -0
  549. /package/packages/omo-codex/plugin/components/{start-work-continuation → ulw-execute-continuation}/tsconfig.build.json +0 -0
  550. /package/packages/omo-codex/plugin/components/{start-work-continuation → ulw-execute-continuation}/tsconfig.json +0 -0
  551. /package/packages/omo-codex/plugin/components/{start-work-continuation → ulw-execute-continuation}/vitest.config.ts +0 -0
@@ -4,8 +4,8 @@
4
4
  import { argv, stderr } from "node:process";
5
5
 
6
6
  // src/proxy.ts
7
- import { existsSync as existsSync12, realpathSync as realpathSync4 } from "node:fs";
8
- import { basename as basename3, delimiter as delimiter4, dirname as dirname9, isAbsolute as isAbsolute5 } from "node:path";
7
+ import { existsSync as existsSync13, realpathSync as realpathSync6 } from "node:fs";
8
+ import { basename as basename4, delimiter as delimiter4, dirname as dirname11, isAbsolute as isAbsolute6 } from "node:path";
9
9
 
10
10
  // ../mcp-stdio-core/src/record.ts
11
11
  function isPlainRecord(value) {
@@ -184,6 +184,7 @@ async function runJsonRpcStdioServer(config) {
184
184
  const idleTimer = createIdleTimer(idleTimeoutMs, log, () => {
185
185
  isClosed = true;
186
186
  config.onIdleTimeout?.();
187
+ config.input.destroy();
187
188
  });
188
189
  const watchdog = createParentWatchdog(config.parentWatchdog, (parentPid, pollIntervalMs) => {
189
190
  isClosed = true;
@@ -280,7 +281,11 @@ function createParentWatchdog(config, onDeadParent) {
280
281
  const probeAlive = config.probeAlive ?? isProcessAlive;
281
282
  let fired = false;
282
283
  const timer = setInterval(() => {
283
- if (fired || probeAlive(parentPid))
284
+ if (fired)
285
+ return;
286
+ const alive = probeAlive(parentPid);
287
+ config.onPoll?.(alive);
288
+ if (alive)
284
289
  return;
285
290
  fired = true;
286
291
  onDeadParent(parentPid, pollIntervalMs);
@@ -315,8 +320,8 @@ function createIdleTimer(idleTimeoutMs, log, onTimeout) {
315
320
  };
316
321
  }
317
322
  // ../lsp-core/src/lsp/client-wrapper.ts
318
- import { existsSync as existsSync9, statSync as statSync3 } from "node:fs";
319
- import { dirname as dirname6, join as join4, resolve as resolve7 } from "node:path";
323
+ import { existsSync as existsSync10, realpathSync as realpathSync5, statSync as statSync3 } from "node:fs";
324
+ import { basename as basename3, dirname as dirname8, join as join5, resolve as resolve8 } from "node:path";
320
325
 
321
326
  // ../lsp-core/src/request-context.ts
322
327
  import { AsyncLocalStorage } from "node:async_hooks";
@@ -325,18 +330,17 @@ import { homedir } from "node:os";
325
330
  import { basename, delimiter, dirname, isAbsolute, join, relative, resolve } from "node:path";
326
331
 
327
332
  class LspRequestContextParseError extends Error {
328
- code;
329
- name = "LspRequestContextParseError";
330
333
  constructor(code, message) {
331
334
  super(message);
332
335
  this.code = code;
336
+ this.name = "LspRequestContextParseError";
333
337
  }
334
338
  }
335
339
 
336
340
  class LspRequestContextUnavailableError extends Error {
337
- name = "LspRequestContextUnavailableError";
338
341
  constructor() {
339
342
  super("LSP request context is required. Standalone MCP startup must install one with runWithRequestContext(createStandaloneMcpRequestContext()).");
343
+ this.name = "LspRequestContextUnavailableError";
340
344
  }
341
345
  }
342
346
  var storage = new AsyncLocalStorage;
@@ -356,7 +360,7 @@ function contextCwd() {
356
360
  }
357
361
  function createStandaloneMcpRequestContext(input = {}) {
358
362
  const env = input.env ?? process.env;
359
- const cwd = canonicalCwd(input.cwd ?? process.cwd());
363
+ const cwd = canonicalCwd(input.cwd ?? env["LSP_TOOLS_MCP_CWD"] ?? process.cwd());
360
364
  const home = input.homeDir ?? homedir();
361
365
  const projectConfigPaths = translateProjectConfigEnv(env["LSP_TOOLS_MCP_PROJECT_CONFIG"], cwd);
362
366
  const userConfigPath = translateHomeConfigEnv(env["LSP_TOOLS_MCP_USER_CONFIG"], home, ".codex/lsp-client.json");
@@ -499,22 +503,15 @@ function effectiveExtension(filePath) {
499
503
 
500
504
  // ../lsp-core/src/lsp/errors.ts
501
505
  class LspConnectionClosedError extends Error {
502
- serverId;
503
- root;
504
- name = "LspConnectionClosedError";
505
506
  constructor(serverId, root, message) {
506
507
  super(message ?? `LSP connection closed for ${serverId} at ${root}`);
507
508
  this.serverId = serverId;
508
509
  this.root = root;
510
+ this.name = "LspConnectionClosedError";
509
511
  }
510
512
  }
511
513
 
512
514
  class LspProcessExitedError extends Error {
513
- serverId;
514
- root;
515
- exitCode;
516
- stderrTail;
517
- name = "LspProcessExitedError";
518
515
  constructor(serverId, root, exitCode, stderrTail) {
519
516
  const stderrSuffix = stderrTail ? `
520
517
  stderr tail: ${stderrTail}` : "";
@@ -523,46 +520,59 @@ stderr tail: ${stderrTail}` : "";
523
520
  this.root = root;
524
521
  this.exitCode = exitCode;
525
522
  this.stderrTail = stderrTail;
523
+ this.name = "LspProcessExitedError";
526
524
  }
527
525
  }
528
526
 
529
527
  class LspRequestTimeoutError extends Error {
530
- method;
531
- stderrTail;
532
- name = "LspRequestTimeoutError";
533
528
  constructor(method, stderrTail) {
534
529
  const stderrSuffix = stderrTail ? `
535
530
  recent stderr: ${stderrTail}` : "";
536
531
  super(`LSP request timeout (method: ${method})${stderrSuffix}`);
537
532
  this.method = method;
538
533
  this.stderrTail = stderrTail;
534
+ this.name = "LspRequestTimeoutError";
539
535
  }
540
536
  }
541
537
 
542
538
  class LspInvalidPathError extends Error {
543
- name = "LspInvalidPathError";
539
+ constructor() {
540
+ super(...arguments);
541
+ this.name = "LspInvalidPathError";
542
+ }
544
543
  }
545
544
 
546
545
  class LspServerLookupError extends Error {
547
- lookup;
548
- name = "LspServerLookupError";
549
546
  constructor(message, lookup) {
550
547
  super(message);
551
548
  this.lookup = lookup;
549
+ this.name = "LspServerLookupError";
552
550
  }
553
551
  }
554
552
 
555
553
  class LspServerInitializingError extends Error {
556
- originalError;
557
- name = "LspServerInitializingError";
558
554
  constructor(originalError) {
559
555
  super(`LSP server is still initializing. Please retry in a few seconds. Original error: ${originalError.message}`);
560
556
  this.originalError = originalError;
557
+ this.name = "LspServerInitializingError";
561
558
  }
562
559
  }
563
560
 
564
561
  class LspProcessSpawnError extends Error {
565
- name = "LspProcessSpawnError";
562
+ constructor() {
563
+ super(...arguments);
564
+ this.name = "LspProcessSpawnError";
565
+ }
566
+ }
567
+
568
+ class LspClientRespawnBudgetExceededError extends Error {
569
+ constructor(serverId, root, retryLimit) {
570
+ super(`LSP server ${serverId} at ${root} failed to stay alive; respawn budget exhausted ` + `(${retryLimit} consecutive dead generations). Retrying after the cooldown may succeed.`);
571
+ this.serverId = serverId;
572
+ this.root = root;
573
+ this.retryLimit = retryLimit;
574
+ this.name = "LspClientRespawnBudgetExceededError";
575
+ }
566
576
  }
567
577
  function isLspDeadConnectionError(err) {
568
578
  return err instanceof LspConnectionClosedError || err instanceof LspProcessExitedError;
@@ -585,6 +595,13 @@ import { pathToFileURL as pathToFileURL3 } from "node:url";
585
595
  // ../lsp-core/src/lsp/connection.ts
586
596
  import { pathToFileURL } from "node:url";
587
597
 
598
+ // ../lsp-core/src/lsp/timer-provider.ts
599
+ var realTimerProvider = {
600
+ now: () => Date.now(),
601
+ setTimeout: (callback, delayMs) => setTimeout(callback, delayMs),
602
+ clearTimeout: (handle) => clearTimeout(handle)
603
+ };
604
+
588
605
  // ../lsp-core/src/lsp/constants.ts
589
606
  var DEFAULT_MAX_REFERENCES = 200;
590
607
  var DEFAULT_MAX_SYMBOLS = 200;
@@ -593,9 +610,12 @@ var DEFAULT_MAX_DIRECTORY_FILES = 50;
593
610
  var REQUEST_TIMEOUT_MS = 15000;
594
611
  var INIT_TIMEOUT_MS = 60000;
595
612
  var IDLE_TIMEOUT_MS = 5 * 60000;
613
+ var MAX_RESIDENT_CLIENTS = 6;
596
614
  var REAPER_INTERVAL_MS = 60000;
597
615
  var STOP_HARD_KILL_TIMEOUT_MS = 5000;
598
616
  var STOP_SIGKILL_GRACE_MS = 1000;
617
+ var CLIENT_RESPAWN_RETRY_LIMIT = 2;
618
+ var CLIENT_RESPAWN_COOLDOWN_MS = 60000;
599
619
 
600
620
  // ../lsp-core/src/lsp/json-rpc-connection.ts
601
621
  var HEADER_SEPARATOR2 = `\r
@@ -607,20 +627,31 @@ var METHOD_NOT_FOUND = -32601;
607
627
  var INTERNAL_ERROR = -32603;
608
628
 
609
629
  class JsonRpcConnection {
610
- reader;
611
- writer;
612
- pendingRequests = new Map;
613
- notificationHandlers = new Map;
614
- requestHandlers = new Map;
615
- closeHandlers = [];
616
- errorHandlers = [];
617
- inputBuffer = Buffer.alloc(0);
618
- nextRequestId = 1;
619
- listening = false;
620
- disposed = false;
621
630
  constructor(reader, writer) {
622
631
  this.reader = reader;
623
632
  this.writer = writer;
633
+ this.pendingRequests = new Map;
634
+ this.notificationHandlers = new Map;
635
+ this.requestHandlers = new Map;
636
+ this.closeHandlers = [];
637
+ this.errorHandlers = [];
638
+ this.inputBuffer = Buffer.alloc(0);
639
+ this.nextRequestId = 1;
640
+ this.listening = false;
641
+ this.disposed = false;
642
+ this.handleData = (chunk) => {
643
+ const chunkBuffer = Buffer.isBuffer(chunk) ? chunk : Buffer.from(chunk, "utf8");
644
+ this.inputBuffer = Buffer.concat([this.inputBuffer, chunkBuffer]);
645
+ this.drainInputBuffer();
646
+ };
647
+ this.handleClose = () => {
648
+ for (const handler of this.closeHandlers) {
649
+ handler();
650
+ }
651
+ };
652
+ this.handleStreamError = (error) => {
653
+ this.emitError(error);
654
+ };
624
655
  }
625
656
  listen() {
626
657
  if (this.listening)
@@ -655,6 +686,7 @@ class JsonRpcConnection {
655
686
  let cancelAfterWrite = false;
656
687
  let settled = false;
657
688
  const writeCancel = () => this.writeMessage({ jsonrpc: "2.0", method: "$/cancelRequest", params: { id } });
689
+ let rejectAfterCancelWrite;
658
690
  const responsePromise = new Promise((resolve2, reject) => {
659
691
  const cleanup = () => {
660
692
  options.signal?.removeEventListener("abort", onAbort);
@@ -666,15 +698,19 @@ class JsonRpcConnection {
666
698
  this.pendingRequests.delete(key);
667
699
  cleanup();
668
700
  const rejectCancelled = () => reject(abortError(options.signal));
701
+ rejectAfterCancelWrite = async () => {
702
+ try {
703
+ await writeCancel();
704
+ } catch (error) {
705
+ this.emitError(toError(error));
706
+ }
707
+ rejectCancelled();
708
+ };
669
709
  if (!requestWritten) {
670
710
  cancelAfterWrite = true;
671
- rejectCancelled();
672
711
  return;
673
712
  }
674
- writeCancel().then(rejectCancelled, (error) => {
675
- this.emitError(toError(error));
676
- rejectCancelled();
677
- });
713
+ rejectAfterCancelWrite();
678
714
  };
679
715
  const onAbort = () => settleCancel();
680
716
  this.pendingRequests.set(key, {
@@ -702,7 +738,7 @@ class JsonRpcConnection {
702
738
  await this.writeMessage(message);
703
739
  requestWritten = true;
704
740
  if (cancelAfterWrite)
705
- await writeCancel();
741
+ await rejectAfterCancelWrite?.();
706
742
  } catch (error) {
707
743
  if (settled)
708
744
  return responsePromise;
@@ -741,19 +777,6 @@ class JsonRpcConnection {
741
777
  this.notificationHandlers.clear();
742
778
  this.requestHandlers.clear();
743
779
  }
744
- handleData = (chunk) => {
745
- const chunkBuffer = Buffer.isBuffer(chunk) ? chunk : Buffer.from(chunk, "utf8");
746
- this.inputBuffer = Buffer.concat([this.inputBuffer, chunkBuffer]);
747
- this.drainInputBuffer();
748
- };
749
- handleClose = () => {
750
- for (const handler of this.closeHandlers) {
751
- handler();
752
- }
753
- };
754
- handleStreamError = (error) => {
755
- this.emitError(error);
756
- };
757
780
  drainInputBuffer() {
758
781
  while (true) {
759
782
  const headerEnd = this.inputBuffer.indexOf(HEADER_SEPARATOR2);
@@ -1101,33 +1124,29 @@ function isPosition(value) {
1101
1124
 
1102
1125
  // ../lsp-core/src/lsp/transport.ts
1103
1126
  class LspClientNotStartedError extends Error {
1104
- serverId;
1105
- root;
1106
- name = "LspClientNotStartedError";
1107
1127
  constructor(serverId, root) {
1108
1128
  super("LSP client not started");
1109
1129
  this.serverId = serverId;
1110
1130
  this.root = root;
1131
+ this.name = "LspClientNotStartedError";
1111
1132
  }
1112
1133
  }
1113
1134
 
1114
1135
  class LspClientTransport {
1115
- root;
1116
- server;
1117
- proc = null;
1118
- connection = null;
1119
- stderrBuffer = [];
1120
- processExited = false;
1121
- diagnosticsStore = new Map;
1122
- requestTimeoutMs;
1123
- initializeTimeoutMs;
1124
- workspaceApplyEditHandler = null;
1125
- diagnosticPullSupported = false;
1126
1136
  constructor(root, server2, timeouts = {}) {
1127
1137
  this.root = root;
1128
1138
  this.server = server2;
1139
+ this.proc = null;
1140
+ this.connection = null;
1141
+ this.stderrBuffer = [];
1142
+ this.processExited = false;
1143
+ this.diagnosticsStore = new Map;
1144
+ this.workspaceApplyEditHandler = null;
1145
+ this.diagnosticPullSupported = false;
1146
+ this.documentFormattingSupported = false;
1129
1147
  this.requestTimeoutMs = timeouts.requestTimeoutMs ?? REQUEST_TIMEOUT_MS;
1130
1148
  this.initializeTimeoutMs = timeouts.initializeTimeoutMs ?? INIT_TIMEOUT_MS;
1149
+ this.timerProvider = timeouts.timerProvider ?? realTimerProvider;
1131
1150
  }
1132
1151
  pid() {
1133
1152
  return this.proc?.pid;
@@ -1147,6 +1166,12 @@ class LspClientTransport {
1147
1166
  isDiagnosticPullSupported() {
1148
1167
  return this.diagnosticPullSupported;
1149
1168
  }
1169
+ setDocumentFormattingSupported(supported) {
1170
+ this.documentFormattingSupported = supported;
1171
+ }
1172
+ isDocumentFormattingSupported() {
1173
+ return this.documentFormattingSupported;
1174
+ }
1150
1175
  handlePublishDiagnostics(params) {
1151
1176
  this.diagnosticsStore.set(params.uri, [...params.diagnostics]);
1152
1177
  }
@@ -1222,7 +1247,7 @@ class LspClientTransport {
1222
1247
  const options = args[1];
1223
1248
  const timeoutMs = options?.timeoutMs ?? this.requestTimeoutMs;
1224
1249
  const timeoutController = new AbortController;
1225
- const timeoutHandle = setTimeout(() => {
1250
+ const timeoutHandle = this.timerProvider.setTimeout(() => {
1226
1251
  const stderrTail = this.stderrBuffer.slice(-5).join(`
1227
1252
  `);
1228
1253
  timeoutController.abort(new LspRequestTimeoutError(method, stderrTail || undefined));
@@ -1241,7 +1266,7 @@ class LspClientTransport {
1241
1266
  }
1242
1267
  throw error;
1243
1268
  } finally {
1244
- clearTimeout(timeoutHandle);
1269
+ this.timerProvider.clearTimeout(timeoutHandle);
1245
1270
  combinedSignal.dispose();
1246
1271
  }
1247
1272
  }
@@ -1360,6 +1385,14 @@ function supportsDiagnosticPull(capabilities) {
1360
1385
  return false;
1361
1386
  return Object.hasOwn(capabilities, "diagnosticProvider");
1362
1387
  }
1388
+ function supportsDocumentFormatting(capabilities) {
1389
+ if (capabilities === undefined)
1390
+ return false;
1391
+ const provider = capabilities.documentFormattingProvider;
1392
+ if (provider === undefined || provider === null || provider === false)
1393
+ return false;
1394
+ return provider === true || typeof provider === "object";
1395
+ }
1363
1396
 
1364
1397
  class LspClientConnection extends LspClientTransport {
1365
1398
  async initialize() {
@@ -1376,6 +1409,7 @@ class LspClientConnection extends LspClientTransport {
1376
1409
  references: {},
1377
1410
  documentSymbol: { hierarchicalDocumentSymbolSupport: true },
1378
1411
  publishDiagnostics: {},
1412
+ formatting: { dynamicRegistration: false },
1379
1413
  rename: {
1380
1414
  prepareSupport: true,
1381
1415
  prepareSupportDefaultBehavior: 1
@@ -1417,6 +1451,7 @@ class LspClientConnection extends LspClientTransport {
1417
1451
  initializationOptions: this.server.initialization
1418
1452
  }, { timeoutMs: this.initializeTimeoutMs });
1419
1453
  this.setDiagnosticPullSupported(supportsDiagnosticPull(result?.capabilities));
1454
+ this.setDocumentFormattingSupported(supportsDocumentFormatting(result?.capabilities));
1420
1455
  await this.sendNotification("initialized", {});
1421
1456
  await this.sendNotification("workspace/didChangeConfiguration", {
1422
1457
  settings: { json: { validate: { enable: true } } }
@@ -1612,6 +1647,17 @@ function canonicalPath(filePath) {
1612
1647
  return absolute;
1613
1648
  }
1614
1649
  }
1650
+ function normalizeDocumentUri(uri) {
1651
+ let decoded = uri;
1652
+ try {
1653
+ decoded = decodeURIComponent(uri);
1654
+ } catch {
1655
+ decoded = uri;
1656
+ }
1657
+ if (process.platform !== "win32")
1658
+ return decoded;
1659
+ return decoded.replace(/^(file:\/\/\/)([a-z]):/, (_match, prefix, drive) => `${prefix}${drive.toUpperCase()}:`);
1660
+ }
1615
1661
  function isSameOrDescendant(candidate, parent) {
1616
1662
  const suffix = relative2(parent, candidate);
1617
1663
  return suffix === "" || !suffix.startsWith("..") && suffix !== "..";
@@ -1622,17 +1668,18 @@ function movedPath(candidate, oldPath, newPath) {
1622
1668
  }
1623
1669
 
1624
1670
  class WorkspaceDocumentState {
1625
- sendNotification;
1626
- clearDiagnostics;
1627
- openDocuments = new Map;
1628
- openByUri = new Map;
1629
- openPromises = new Map;
1630
- now;
1631
- versionlessPublishQuiescenceMs;
1632
1671
  constructor(sendNotification, clearDiagnostics, options = {}) {
1633
1672
  this.sendNotification = sendNotification;
1634
1673
  this.clearDiagnostics = clearDiagnostics;
1635
- this.now = options.now ?? (() => Date.now());
1674
+ this.openDocuments = new Map;
1675
+ this.openByUri = new Map;
1676
+ this.openPromises = new Map;
1677
+ this.timerProvider = options.timerProvider ?? {
1678
+ now: options.now ?? (() => Date.now()),
1679
+ setTimeout: (callback, delayMs) => setTimeout(callback, delayMs),
1680
+ clearTimeout: (handle) => clearTimeout(handle)
1681
+ };
1682
+ this.now = () => this.timerProvider.now();
1636
1683
  this.versionlessPublishQuiescenceMs = options.versionlessPublishQuiescenceMs ?? DEFAULT_VERSIONLESS_PUBLISH_QUIESCENCE_MS;
1637
1684
  }
1638
1685
  async openFile(filePath) {
@@ -1654,7 +1701,7 @@ class WorkspaceDocumentState {
1654
1701
  return this.openDocuments.get(canonicalPath(filePath))?.version;
1655
1702
  }
1656
1703
  getStoredDiagnostics(uri) {
1657
- const state = this.openByUri.get(uri);
1704
+ const state = this.openByUri.get(normalizeDocumentUri(uri));
1658
1705
  if (!state)
1659
1706
  return [];
1660
1707
  return state.lastPublish?.diagnostics ?? state.pullCache?.diagnostics ?? [];
@@ -1676,13 +1723,13 @@ class WorkspaceDocumentState {
1676
1723
  return state !== undefined && state.uri === snapshot.uri && state.version === snapshot.version && state.generation === snapshot.documentGeneration;
1677
1724
  }
1678
1725
  getPullCache(snapshot) {
1679
- const state = this.openByUri.get(snapshot.uri);
1726
+ const state = this.openByUri.get(normalizeDocumentUri(snapshot.uri));
1680
1727
  if (!state?.pullCache || state.pullCache.documentVersion !== snapshot.version)
1681
1728
  return null;
1682
1729
  return state.pullCache;
1683
1730
  }
1684
1731
  recordPullDiagnostics(snapshot, report) {
1685
- const state = this.openByUri.get(snapshot.uri);
1732
+ const state = this.openByUri.get(normalizeDocumentUri(snapshot.uri));
1686
1733
  if (!state)
1687
1734
  return;
1688
1735
  state.pullCache = {
@@ -1692,7 +1739,7 @@ class WorkspaceDocumentState {
1692
1739
  };
1693
1740
  }
1694
1741
  recordPublishedDiagnostics(params) {
1695
- const state = this.openByUri.get(params.uri);
1742
+ const state = this.openByUri.get(normalizeDocumentUri(params.uri));
1696
1743
  if (!state)
1697
1744
  return;
1698
1745
  state.publishGeneration += 1;
@@ -1706,7 +1753,7 @@ class WorkspaceDocumentState {
1706
1753
  this.notifyWaiters(state);
1707
1754
  }
1708
1755
  resolvePushDiagnostics(snapshot) {
1709
- const state = this.openByUri.get(snapshot.uri);
1756
+ const state = this.openByUri.get(normalizeDocumentUri(snapshot.uri));
1710
1757
  if (!state?.lastPublish)
1711
1758
  return { status: "missing" };
1712
1759
  const publish = state.lastPublish;
@@ -1720,7 +1767,7 @@ class WorkspaceDocumentState {
1720
1767
  return waitMs === 0 ? { status: "ready", diagnostics: publish.diagnostics } : { status: "wait", waitMs };
1721
1768
  }
1722
1769
  waitForDiagnosticsActivity(snapshot, timeoutMs) {
1723
- const state = this.openByUri.get(snapshot.uri);
1770
+ const state = this.openByUri.get(normalizeDocumentUri(snapshot.uri));
1724
1771
  if (!state || timeoutMs <= 0)
1725
1772
  return Promise.resolve();
1726
1773
  return new Promise((resolveActivity) => {
@@ -1729,11 +1776,11 @@ class WorkspaceDocumentState {
1729
1776
  if (settled)
1730
1777
  return;
1731
1778
  settled = true;
1732
- clearTimeout(timer);
1779
+ this.timerProvider.clearTimeout(timer);
1733
1780
  state.waiters.delete(finish);
1734
1781
  resolveActivity();
1735
1782
  };
1736
- const timer = setTimeout(finish, timeoutMs);
1783
+ const timer = this.timerProvider.setTimeout(finish, timeoutMs);
1737
1784
  if (typeof timer.unref === "function")
1738
1785
  timer.unref();
1739
1786
  state.waiters.add(finish);
@@ -1841,7 +1888,7 @@ class WorkspaceDocumentState {
1841
1888
  waiters: new Set
1842
1889
  };
1843
1890
  this.openDocuments.set(path, state);
1844
- this.openByUri.set(state.uri, state);
1891
+ this.openByUri.set(normalizeDocumentUri(state.uri), state);
1845
1892
  this.notifyWaiters(state);
1846
1893
  await this.sendNotification("textDocument/didOpen", {
1847
1894
  textDocument: { uri: state.uri, languageId: state.languageId, version: state.version, text }
@@ -1866,7 +1913,7 @@ class WorkspaceDocumentState {
1866
1913
  }
1867
1914
  async closeDocument(state) {
1868
1915
  this.openDocuments.delete(state.path);
1869
- this.openByUri.delete(state.uri);
1916
+ this.openByUri.delete(normalizeDocumentUri(state.uri));
1870
1917
  this.clearDiagnostics(state.uri);
1871
1918
  this.notifyWaiters(state);
1872
1919
  await this.sendNotification("textDocument/didClose", { textDocument: { uri: state.uri } });
@@ -1895,13 +1942,11 @@ import { dirname as dirname2, isAbsolute as isAbsolute2, relative as relative3,
1895
1942
  import { fileURLToPath } from "node:url";
1896
1943
 
1897
1944
  class WorkspaceEditPathError extends Error {
1898
- path;
1899
- detail;
1900
- name = "WorkspaceEditPathError";
1901
1945
  constructor(path, detail) {
1902
1946
  super(`${detail}: ${path}`);
1903
1947
  this.path = path;
1904
1948
  this.detail = detail;
1949
+ this.name = "WorkspaceEditPathError";
1905
1950
  }
1906
1951
  }
1907
1952
  function isPathInsideWorkspace(filePath, workspaceRoot) {
@@ -2193,13 +2238,11 @@ function canonicalFingerprint(operations) {
2193
2238
 
2194
2239
  // ../lsp-core/src/lsp/workspace-edit-types.ts
2195
2240
  class WorkspaceEditValidationError extends Error {
2196
- changeIndex;
2197
- detail;
2198
- name = "WorkspaceEditValidationError";
2199
2241
  constructor(changeIndex, detail) {
2200
2242
  super(`change ${changeIndex}: ${detail}`);
2201
2243
  this.changeIndex = changeIndex;
2202
2244
  this.detail = detail;
2245
+ this.name = "WorkspaceEditValidationError";
2203
2246
  }
2204
2247
  }
2205
2248
 
@@ -2697,10 +2740,9 @@ function simulateDelete(operation, virtual) {
2697
2740
  import { existsSync as existsSync5, lstatSync as lstatSync3, readdirSync as readdirSync2 } from "node:fs";
2698
2741
  import { dirname as dirname4, resolve as resolve5 } from "node:path";
2699
2742
  class WorkspaceSnapshotBuilder {
2700
- workspaceRoot;
2701
- snapshots = new Map;
2702
2743
  constructor(workspaceRoot) {
2703
2744
  this.workspaceRoot = workspaceRoot;
2745
+ this.snapshots = new Map;
2704
2746
  }
2705
2747
  build(operations) {
2706
2748
  this.add(this.workspaceRoot, false);
@@ -2744,8 +2786,10 @@ function snapshotOperations(operations, workspaceRoot) {
2744
2786
 
2745
2787
  // ../lsp-core/src/lsp/workspace-edit-plan.ts
2746
2788
  class PlanPathIndex {
2747
- firstChangeByPath = new Map;
2748
- reportedPathByCanonical = new Map;
2789
+ constructor() {
2790
+ this.firstChangeByPath = new Map;
2791
+ this.reportedPathByCanonical = new Map;
2792
+ }
2749
2793
  build(operations) {
2750
2794
  for (const operation of operations) {
2751
2795
  switch (operation.kind) {
@@ -2834,14 +2878,11 @@ function isRecord4(value) {
2834
2878
  }
2835
2879
 
2836
2880
  class WorkspaceMutationController {
2837
- workspaceRoot;
2838
- documents;
2839
- activeLease = null;
2840
- nextLeaseId = 1;
2841
- io;
2842
2881
  constructor(workspaceRoot, documents) {
2843
2882
  this.workspaceRoot = workspaceRoot;
2844
2883
  this.documents = documents;
2884
+ this.activeLease = null;
2885
+ this.nextLeaseId = 1;
2845
2886
  }
2846
2887
  setIo(io) {
2847
2888
  this.io = io;
@@ -2954,14 +2995,12 @@ var DIAGNOSTICS_FRESHNESS_TIMEOUT_MS = 3000;
2954
2995
  var VERSIONLESS_PUBLISH_QUIESCENCE_MS = 250;
2955
2996
 
2956
2997
  class LspClient extends LspClientConnection {
2957
- diagnosticPullErrors = [];
2958
- documents;
2959
- workspaceMutations;
2960
- diagnosticsFreshnessTimeoutMs;
2961
2998
  constructor(root, server2, options = {}) {
2962
2999
  super(root, server2, options);
3000
+ this.diagnosticPullErrors = [];
2963
3001
  this.diagnosticsFreshnessTimeoutMs = options.diagnosticsFreshnessTimeoutMs ?? DIAGNOSTICS_FRESHNESS_TIMEOUT_MS;
2964
3002
  this.documents = new WorkspaceDocumentState((method, params) => this.sendNotification(method, params), (uri) => this.diagnosticsStore.delete(uri), {
3003
+ timerProvider: this.timerProvider,
2965
3004
  versionlessPublishQuiescenceMs: options.versionlessPublishQuiescenceMs ?? VERSIONLESS_PUBLISH_QUIESCENCE_MS
2966
3005
  });
2967
3006
  this.workspaceMutations = new WorkspaceMutationController(root, this.documents);
@@ -3014,6 +3053,18 @@ class LspClient extends LspClientConnection {
3014
3053
  textDocument: { uri: pathToFileURL3(absPath).href }
3015
3054
  }, options);
3016
3055
  }
3056
+ async formatDocument(filePath, options, signal) {
3057
+ if (!this.isDocumentFormattingSupported())
3058
+ return null;
3059
+ const absPath = this.resolveWorkspacePath(filePath);
3060
+ await this.openFile(absPath);
3061
+ const requestOptions = signal === undefined ? {} : { signal };
3062
+ const edits = await this.sendRequest("textDocument/formatting", {
3063
+ textDocument: { uri: pathToFileURL3(absPath).href },
3064
+ options
3065
+ }, requestOptions);
3066
+ return edits ?? [];
3067
+ }
3017
3068
  async workspaceSymbols(query, signal) {
3018
3069
  const options = signal === undefined ? {} : { signal };
3019
3070
  return this.sendRequest("workspace/symbol", { query }, options);
@@ -3053,7 +3104,7 @@ class LspClient extends LspClientConnection {
3053
3104
  const absPath = this.resolveWorkspacePath(filePath);
3054
3105
  const uri = pathToFileURL3(absPath).href;
3055
3106
  await this.openFile(absPath);
3056
- const deadlineAt = Date.now() + this.diagnosticsFreshnessTimeoutMs;
3107
+ const deadlineAt = this.timerProvider.now() + this.diagnosticsFreshnessTimeoutMs;
3057
3108
  for (;; ) {
3058
3109
  signal?.throwIfAborted();
3059
3110
  const snapshot = this.documents.captureDiagnosticSnapshot(absPath);
@@ -3066,7 +3117,7 @@ class LspClient extends LspClientConnection {
3066
3117
  if (!pushFallbackOnly) {
3067
3118
  const cached = this.documents.getPullCache(snapshot);
3068
3119
  try {
3069
- const remainingMs2 = deadlineAt - Date.now();
3120
+ const remainingMs2 = deadlineAt - this.timerProvider.now();
3070
3121
  if (remainingMs2 <= 0)
3071
3122
  return this.freshnessTimeout(absPath);
3072
3123
  const result = await this.sendRequest("textDocument/diagnostic", {
@@ -3101,7 +3152,7 @@ class LspClient extends LspClientConnection {
3101
3152
  }
3102
3153
  if (!pushFallbackOnly)
3103
3154
  continue;
3104
- const remainingMs = deadlineAt - Date.now();
3155
+ const remainingMs = deadlineAt - this.timerProvider.now();
3105
3156
  if (remainingMs <= 0) {
3106
3157
  if (!this.isDiagnosticPullSupported() && snapshot.publishGeneration === 0) {
3107
3158
  const cached = this.documents.getPullCache(snapshot);
@@ -3259,18 +3310,16 @@ function awaitWithSignal(promise, signal) {
3259
3310
  }
3260
3311
 
3261
3312
  class LspManager {
3262
- clients = new Map;
3263
- reaperHandle = null;
3264
- signalDisposer = null;
3265
- disposed = false;
3266
- idleTimeoutMs;
3267
- initTimeoutMs;
3268
- reaperIntervalMs;
3269
- clientFactory;
3270
- now;
3271
3313
  constructor(options = {}) {
3314
+ this.clients = new Map;
3315
+ this.pendingStops = new Map;
3316
+ this.respawnBudgets = new Map;
3317
+ this.reaperHandle = null;
3318
+ this.signalDisposer = null;
3319
+ this.disposed = false;
3272
3320
  this.idleTimeoutMs = options.idleTimeoutMs ?? IDLE_TIMEOUT_MS;
3273
3321
  this.initTimeoutMs = options.initTimeoutMs ?? INIT_TIMEOUT_MS;
3322
+ this.maxResidentClients = options.maxResidentClients ?? MAX_RESIDENT_CLIENTS;
3274
3323
  this.reaperIntervalMs = options.reaperIntervalMs ?? REAPER_INTERVAL_MS;
3275
3324
  this.clientFactory = options.clientFactory ?? ((root, server2) => new LspClient(root, server2));
3276
3325
  this.now = options.now ?? (() => Date.now());
@@ -3290,24 +3339,79 @@ class LspManager {
3290
3339
  getKey(root, serverId) {
3291
3340
  return `${root}::${serverId}`;
3292
3341
  }
3342
+ tombstoneStop(key, client) {
3343
+ const stop = stopClientBestEffort(client);
3344
+ this.pendingStops.set(key, stop);
3345
+ stop.finally(() => {
3346
+ if (this.pendingStops.get(key) === stop) {
3347
+ this.pendingStops.delete(key);
3348
+ }
3349
+ });
3350
+ return stop;
3351
+ }
3352
+ recordDeadGeneration(key) {
3353
+ let budget = this.respawnBudgets.get(key);
3354
+ if (budget === undefined) {
3355
+ budget = { deadGenerations: 0, exhaustedAt: null };
3356
+ this.respawnBudgets.set(key, budget);
3357
+ }
3358
+ budget.deadGenerations += 1;
3359
+ }
3360
+ markHealthyGeneration(key) {
3361
+ this.respawnBudgets.delete(key);
3362
+ }
3363
+ ensureRespawnAllowed(key, root, serverId) {
3364
+ const budget = this.respawnBudgets.get(key);
3365
+ if (budget === undefined || budget.deadGenerations < CLIENT_RESPAWN_RETRY_LIMIT)
3366
+ return;
3367
+ if (budget.exhaustedAt === null) {
3368
+ budget.exhaustedAt = this.now();
3369
+ throw new LspClientRespawnBudgetExceededError(serverId, root, CLIENT_RESPAWN_RETRY_LIMIT);
3370
+ }
3371
+ if (this.now() - budget.exhaustedAt < CLIENT_RESPAWN_COOLDOWN_MS) {
3372
+ throw new LspClientRespawnBudgetExceededError(serverId, root, CLIENT_RESPAWN_RETRY_LIMIT);
3373
+ }
3374
+ budget.deadGenerations = 0;
3375
+ budget.exhaustedAt = null;
3376
+ }
3293
3377
  reapStale() {
3294
3378
  const t = this.now();
3295
3379
  for (const [key, managed] of this.clients) {
3296
3380
  if (managed.isInitializing && managed.initializingSince !== null && t - managed.initializingSince > this.initTimeoutMs) {
3297
- stopClientBestEffort(managed.client);
3298
3381
  this.clients.delete(key);
3382
+ this.tombstoneStop(key, managed.client);
3299
3383
  continue;
3300
3384
  }
3301
3385
  if (!managed.isInitializing && managed.refCount === 0 && managed.pendingWaiters === 0 && t - managed.lastUsedAt > this.idleTimeoutMs) {
3302
- stopClientBestEffort(managed.client);
3303
3386
  this.clients.delete(key);
3387
+ this.tombstoneStop(key, managed.client);
3388
+ }
3389
+ }
3390
+ }
3391
+ evictForAdmission() {
3392
+ while (this.clients.size >= this.maxResidentClients) {
3393
+ const victim = this.leastRecentlyUsedIdleClient();
3394
+ if (!victim)
3395
+ return;
3396
+ this.clients.delete(victim.key);
3397
+ this.tombstoneStop(victim.key, victim.managed.client);
3398
+ }
3399
+ }
3400
+ leastRecentlyUsedIdleClient() {
3401
+ let candidate = null;
3402
+ for (const [key, managed] of this.clients) {
3403
+ if (managed.refCount > 0 || managed.pendingWaiters > 0 || managed.isInitializing)
3404
+ continue;
3405
+ if (candidate === null || managed.lastUsedAt < candidate.managed.lastUsedAt) {
3406
+ candidate = { key, managed };
3304
3407
  }
3305
3408
  }
3409
+ return candidate;
3306
3410
  }
3307
3411
  async tryDeleteIfOrphaned(key, managed) {
3308
3412
  if (managed.refCount === 0 && managed.pendingWaiters === 0 && !managed.isInitializing && this.clients.get(key) === managed) {
3309
3413
  this.clients.delete(key);
3310
- await stopClientBestEffort(managed.client);
3414
+ await this.tombstoneStop(key, managed.client);
3311
3415
  }
3312
3416
  }
3313
3417
  async getClient(root, server2, signal) {
@@ -3316,12 +3420,22 @@ class LspManager {
3316
3420
  }
3317
3421
  signal?.throwIfAborted();
3318
3422
  const key = this.getKey(root, server2.id);
3423
+ for (;; ) {
3424
+ const pendingStop = this.pendingStops.get(key);
3425
+ if (pendingStop === undefined)
3426
+ break;
3427
+ await awaitWithSignal(pendingStop, signal);
3428
+ signal?.throwIfAborted();
3429
+ }
3430
+ if (this.disposed) {
3431
+ throw new Error("LspManager has been disposed");
3432
+ }
3319
3433
  let managed = this.clients.get(key);
3320
3434
  if (managed) {
3321
3435
  const t = this.now();
3322
3436
  if (managed.isInitializing && managed.initializingSince !== null && t - managed.initializingSince > this.initTimeoutMs) {
3323
- await stopClientBestEffort(managed.client);
3324
3437
  this.clients.delete(key);
3438
+ await this.tombstoneStop(key, managed.client);
3325
3439
  managed = undefined;
3326
3440
  }
3327
3441
  }
@@ -3342,14 +3456,20 @@ class LspManager {
3342
3456
  signal.throwIfAborted();
3343
3457
  }
3344
3458
  if (!managed.client.isAlive()) {
3345
- await stopClientBestEffort(managed.client);
3346
- this.clients.delete(key);
3459
+ this.recordDeadGeneration(key);
3460
+ if (this.clients.get(key) === managed) {
3461
+ this.clients.delete(key);
3462
+ }
3463
+ await this.tombstoneStop(key, managed.client);
3347
3464
  return this.getClient(root, server2, signal);
3348
3465
  }
3466
+ this.markHealthyGeneration(key);
3349
3467
  managed.refCount++;
3350
3468
  managed.lastUsedAt = this.now();
3351
3469
  return managed.client;
3352
3470
  }
3471
+ this.evictForAdmission();
3472
+ this.ensureRespawnAllowed(key, root, server2.id);
3353
3473
  const client = this.clientFactory(root, server2);
3354
3474
  const initStartedAt = this.now();
3355
3475
  const initPromise = (async () => {
@@ -3373,7 +3493,7 @@ class LspManager {
3373
3493
  if (this.clients.get(key) === newManaged) {
3374
3494
  this.clients.delete(key);
3375
3495
  }
3376
- await stopClientBestEffort(client);
3496
+ await this.tombstoneStop(key, client);
3377
3497
  throw err;
3378
3498
  }
3379
3499
  newManaged.pendingWaiters--;
@@ -3384,6 +3504,15 @@ class LspManager {
3384
3504
  await this.tryDeleteIfOrphaned(key, newManaged);
3385
3505
  signal.throwIfAborted();
3386
3506
  }
3507
+ if (!client.isAlive()) {
3508
+ this.recordDeadGeneration(key);
3509
+ if (this.clients.get(key) === newManaged) {
3510
+ this.clients.delete(key);
3511
+ }
3512
+ await this.tombstoneStop(key, client);
3513
+ return this.getClient(root, server2, signal);
3514
+ }
3515
+ this.markHealthyGeneration(key);
3387
3516
  newManaged.refCount++;
3388
3517
  newManaged.lastUsedAt = this.now();
3389
3518
  return client;
@@ -3404,14 +3533,20 @@ class LspManager {
3404
3533
  if (client && managed.client !== client)
3405
3534
  return;
3406
3535
  this.clients.delete(key);
3407
- stopClientBestEffort(managed.client);
3536
+ this.tombstoneStop(key, managed.client);
3408
3537
  }
3409
3538
  warmupClient(root, server2) {
3410
3539
  if (this.disposed)
3411
3540
  return;
3412
3541
  const key = this.getKey(root, server2.id);
3413
- if (this.clients.has(key))
3542
+ if (this.clients.has(key) || this.pendingStops.has(key))
3414
3543
  return;
3544
+ this.evictForAdmission();
3545
+ try {
3546
+ this.ensureRespawnAllowed(key, root, server2.id);
3547
+ } catch {
3548
+ return;
3549
+ }
3415
3550
  const client = this.clientFactory(root, server2);
3416
3551
  const initStartedAt = this.now();
3417
3552
  const initPromise = (async () => {
@@ -3437,7 +3572,7 @@ class LspManager {
3437
3572
  if (this.clients.get(key) === managed) {
3438
3573
  this.clients.delete(key);
3439
3574
  }
3440
- stopClientBestEffort(client);
3575
+ this.tombstoneStop(key, client);
3441
3576
  });
3442
3577
  }
3443
3578
  isServerInitializing(root, serverId) {
@@ -3481,8 +3616,11 @@ class LspManager {
3481
3616
  for (const managed of this.clients.values()) {
3482
3617
  stopPromises.push(stopClientBestEffort(managed.client));
3483
3618
  }
3619
+ const tombstonedStops = [...this.pendingStops.values()];
3484
3620
  this.clients.clear();
3485
- await Promise.allSettled(stopPromises);
3621
+ this.respawnBudgets.clear();
3622
+ await Promise.allSettled([...stopPromises, ...tombstonedStops]);
3623
+ this.pendingStops.clear();
3486
3624
  }
3487
3625
  }
3488
3626
  var _defaultInstance = null;
@@ -3500,57 +3638,52 @@ async function disposeDefaultLspManager() {
3500
3638
  }
3501
3639
  }
3502
3640
 
3503
- // ../lsp-core/src/lsp/server-install-state.ts
3504
- import { existsSync as existsSync6, mkdirSync, readFileSync as readFileSync3, renameSync as renameSync2, writeFileSync as writeFileSync2 } from "node:fs";
3505
- import { dirname as dirname5 } from "node:path";
3506
- function getInstallDecisionsPath() {
3507
- return lspRequestContext().installDecisionsPath;
3508
- }
3509
- function loadInstallDecisions() {
3510
- const path = getInstallDecisionsPath();
3511
- if (!existsSync6(path))
3512
- return {};
3513
- try {
3514
- const parsed = JSON.parse(readFileSync3(path, "utf8"));
3515
- return isInstallDecisions(parsed) ? parsed : {};
3516
- } catch {
3517
- return {};
3641
+ // ../lsp-core/src/lsp/outside-context-workspace.ts
3642
+ import { existsSync as existsSync6, realpathSync as realpathSync4 } from "node:fs";
3643
+ import { dirname as dirname5, join as join3 } from "node:path";
3644
+
3645
+ // ../lsp-core/src/lsp/workspace-markers.ts
3646
+ var GIT_WORKSPACE_MARKER = ".git";
3647
+ var PROJECT_WORKSPACE_MARKERS = [
3648
+ "package.json",
3649
+ "pyproject.toml",
3650
+ "Cargo.toml",
3651
+ "go.mod",
3652
+ "pom.xml",
3653
+ "build.gradle"
3654
+ ];
3655
+ var WORKSPACE_MARKERS = [GIT_WORKSPACE_MARKER, ...PROJECT_WORKSPACE_MARKERS];
3656
+
3657
+ // ../lsp-core/src/lsp/outside-context-workspace.ts
3658
+ function findWorkspaceRootOutsideContext(directory) {
3659
+ const marked = nearestMarkedAncestor(directory);
3660
+ if (marked !== undefined)
3661
+ return marked;
3662
+ return realpathSync4(nearestExistingAncestor(directory));
3663
+ }
3664
+ function nearestMarkedAncestor(directory) {
3665
+ let current = directory;
3666
+ for (;; ) {
3667
+ if (existsSync6(current) && WORKSPACE_MARKERS.some((marker) => existsSync6(join3(current, marker)))) {
3668
+ return realpathSync4(current);
3669
+ }
3670
+ const parent = dirname5(current);
3671
+ if (parent === current)
3672
+ return;
3673
+ current = parent;
3518
3674
  }
3519
3675
  }
3520
- function loadInstallDecision(serverId) {
3521
- return loadInstallDecisions()[serverId];
3522
- }
3523
- function recordInstallDecision(serverId, decision, decidedAt = new Date().toISOString()) {
3524
- const decisions = loadInstallDecisions();
3525
- decisions[serverId] = { decision, decidedAt };
3526
- writeInstallDecisions(decisions);
3527
- }
3528
- function isInstallDecision(value) {
3529
- return value === "declined" || value === "allowed";
3530
- }
3531
- function writeInstallDecisions(decisions) {
3532
- const path = getInstallDecisionsPath();
3533
- mkdirSync(dirname5(path), { recursive: true });
3534
- const tmpPath = `${path}.tmp`;
3535
- writeFileSync2(tmpPath, `${JSON.stringify(decisions, null, 2)}
3536
- `, "utf8");
3537
- renameSync2(tmpPath, path);
3538
- }
3539
- function isInstallDecisions(value) {
3540
- return isRecord5(value) && Object.values(value).every(isInstallDecisionRecord);
3541
- }
3542
- function isInstallDecisionRecord(value) {
3543
- if (!isRecord5(value))
3544
- return false;
3545
- return isInstallDecision(value["decision"]) && typeof value["decidedAt"] === "string";
3546
- }
3547
- function isRecord5(value) {
3548
- return typeof value === "object" && value !== null && !Array.isArray(value);
3676
+ function nearestExistingAncestor(directory) {
3677
+ let current = directory;
3678
+ while (!existsSync6(current)) {
3679
+ const parent = dirname5(current);
3680
+ if (parent === current)
3681
+ return current;
3682
+ current = parent;
3683
+ }
3684
+ return current;
3549
3685
  }
3550
3686
 
3551
- // ../lsp-core/src/lsp/config-loader.ts
3552
- import { existsSync as existsSync7, readFileSync as readFileSync4 } from "node:fs";
3553
-
3554
3687
  // ../lsp-core/src/lsp/server-definitions.ts
3555
3688
  var LSP_INSTALL_HINTS = {
3556
3689
  typescript: "npm install -g typescript-language-server typescript",
@@ -3596,6 +3729,26 @@ var LSP_INSTALL_HINTS = {
3596
3729
  julials: `julia -e 'using Pkg; Pkg.add("LanguageServer")'`,
3597
3730
  razor: "Razor runs through the Roslyn language server (cohosting). " + "Install: dotnet tool install -g roslyn-language-server --prerelease (requires v5.8.0+). See https://github.com/dotnet/razor"
3598
3731
  };
3732
+ var LSP_LOCAL_INSTALL_HINTS = {
3733
+ typescript: "bun add -d typescript-language-server typescript",
3734
+ vue: "bun add -d @vue/language-server",
3735
+ eslint: "bun add -d vscode-langservers-extracted",
3736
+ oxlint: "bun add -d oxlint",
3737
+ biome: "bun add -d @biomejs/biome",
3738
+ svelte: "bun add -d svelte-language-server",
3739
+ astro: "bun add -d @astrojs/language-server",
3740
+ bash: "bun add -d bash-language-server",
3741
+ "bash-ls": "bun add -d bash-language-server",
3742
+ "yaml-ls": "bun add -d yaml-language-server",
3743
+ php: "bun add -d intelephense",
3744
+ prisma: "bun add -d prisma",
3745
+ dockerfile: "bun add -d dockerfile-language-server-nodejs",
3746
+ pyright: "uv add --dev pyright",
3747
+ basedpyright: "uv add --dev basedpyright",
3748
+ ruff: "uv add --dev ruff",
3749
+ ty: "uv add --dev ty",
3750
+ "ruby-lsp": "bundle add ruby-lsp --group development"
3751
+ };
3599
3752
  var BUILTIN_SERVERS = {
3600
3753
  typescript: {
3601
3754
  command: ["typescript-language-server", "--stdio"],
@@ -3698,7 +3851,56 @@ var BUILTIN_SERVERS = {
3698
3851
  }
3699
3852
  };
3700
3853
 
3854
+ // ../lsp-core/src/lsp/server-install-state.ts
3855
+ import { existsSync as existsSync7, mkdirSync, readFileSync as readFileSync3, renameSync as renameSync2, writeFileSync as writeFileSync2 } from "node:fs";
3856
+ import { dirname as dirname6 } from "node:path";
3857
+ function getInstallDecisionsPath() {
3858
+ return lspRequestContext().installDecisionsPath;
3859
+ }
3860
+ function loadInstallDecisions() {
3861
+ const path = getInstallDecisionsPath();
3862
+ if (!existsSync7(path))
3863
+ return {};
3864
+ try {
3865
+ const parsed = JSON.parse(readFileSync3(path, "utf8"));
3866
+ return isInstallDecisions(parsed) ? parsed : {};
3867
+ } catch {
3868
+ return {};
3869
+ }
3870
+ }
3871
+ function loadInstallDecision(serverId) {
3872
+ return loadInstallDecisions()[serverId];
3873
+ }
3874
+ function recordInstallDecision(serverId, decision, decidedAt = new Date().toISOString()) {
3875
+ const decisions = loadInstallDecisions();
3876
+ decisions[serverId] = { decision, decidedAt };
3877
+ writeInstallDecisions(decisions);
3878
+ }
3879
+ function isInstallDecision(value) {
3880
+ return value === "declined" || value === "allowed";
3881
+ }
3882
+ function writeInstallDecisions(decisions) {
3883
+ const path = getInstallDecisionsPath();
3884
+ mkdirSync(dirname6(path), { recursive: true });
3885
+ const tmpPath = `${path}.tmp`;
3886
+ writeFileSync2(tmpPath, `${JSON.stringify(decisions, null, 2)}
3887
+ `, "utf8");
3888
+ renameSync2(tmpPath, path);
3889
+ }
3890
+ function isInstallDecisions(value) {
3891
+ return isRecord5(value) && Object.values(value).every(isInstallDecisionRecord);
3892
+ }
3893
+ function isInstallDecisionRecord(value) {
3894
+ if (!isRecord5(value))
3895
+ return false;
3896
+ return isInstallDecision(value["decision"]) && typeof value["decidedAt"] === "string";
3897
+ }
3898
+ function isRecord5(value) {
3899
+ return typeof value === "object" && value !== null && !Array.isArray(value);
3900
+ }
3901
+
3701
3902
  // ../lsp-core/src/lsp/config-loader.ts
3903
+ import { existsSync as existsSync8, readFileSync as readFileSync4 } from "node:fs";
3702
3904
  function getProjectConfigPaths() {
3703
3905
  return lspRequestContext().projectConfigPaths;
3704
3906
  }
@@ -3706,7 +3908,7 @@ function getUserConfigPath() {
3706
3908
  return lspRequestContext().userConfigPath;
3707
3909
  }
3708
3910
  function loadJsonFile(path) {
3709
- if (!existsSync7(path))
3911
+ if (!existsSync8(path))
3710
3912
  return null;
3711
3913
  try {
3712
3914
  const parsed = JSON.parse(readFileSync4(path, "utf-8"));
@@ -3894,54 +4096,155 @@ function getDisabledServerIds() {
3894
4096
  }
3895
4097
 
3896
4098
  // ../lsp-core/src/lsp/server-installation.ts
3897
- import { existsSync as existsSync8 } from "node:fs";
3898
- import { delimiter as delimiter3, join as join3 } from "node:path";
3899
- function isServerInstalled(command, _workingDirectory) {
3900
- if (command.length === 0)
3901
- return false;
3902
- const [cmd] = command;
3903
- if (!cmd)
3904
- return false;
3905
- if (cmd.includes("/") || cmd.includes("\\")) {
3906
- if (existsSync8(cmd))
3907
- return true;
4099
+ import { existsSync as existsSync9 } from "node:fs";
4100
+ import { delimiter as delimiter3, dirname as dirname7, isAbsolute as isAbsolute3, join as join4, resolve as resolve7 } from "node:path";
4101
+ var LOCAL_BIN_RULES = [
4102
+ {
4103
+ markers: ["package.json", "bun.lock", "bun.lockb", "package-lock.json", "yarn.lock", "pnpm-lock.yaml"],
4104
+ binDirs: [join4("node_modules", ".bin")]
4105
+ },
4106
+ {
4107
+ markers: [
4108
+ "pyproject.toml",
4109
+ "ty.toml",
4110
+ "requirements.txt",
4111
+ "setup.py",
4112
+ "setup.cfg",
4113
+ "Pipfile",
4114
+ "pyrightconfig.json",
4115
+ "ruff.toml",
4116
+ ".ruff.toml"
4117
+ ],
4118
+ binDirs: [
4119
+ join4(".venv", "bin"),
4120
+ join4(".venv", "Scripts"),
4121
+ join4("venv", "bin"),
4122
+ join4("venv", "Scripts"),
4123
+ join4(".env", "bin"),
4124
+ join4(".env", "Scripts")
4125
+ ]
4126
+ },
4127
+ {
4128
+ markers: ["Gemfile", "Gemfile.lock"],
4129
+ binDirs: [join4("vendor", "bundle", "bin"), "bin"]
4130
+ },
4131
+ {
4132
+ markers: ["go.mod", "go.sum", "go.work"],
4133
+ binDirs: ["bin"]
3908
4134
  }
3909
- const isWindows = process.platform === "win32";
3910
- let exts = [""];
3911
- if (isWindows) {
3912
- const pathExt = process.env["PATHEXT"] ?? "";
3913
- if (pathExt) {
3914
- const systemExts = pathExt.split(";").filter(Boolean);
3915
- exts = [...new Set([...exts, ...systemExts, ".exe", ".cmd", ".bat", ".ps1"])];
3916
- } else {
3917
- exts = ["", ".exe", ".cmd", ".bat", ".ps1"];
4135
+ ];
4136
+ var resolutionCache = new Map;
4137
+ var probeCount = 0;
4138
+ function probe(path) {
4139
+ probeCount += 1;
4140
+ return existsSync9(path);
4141
+ }
4142
+ function executableSuffixes(platform, pathExt) {
4143
+ if (platform !== "win32")
4144
+ return [""];
4145
+ const configured = pathExt ?? process.env["PATHEXT"] ?? "";
4146
+ const systemExts = configured.split(";").filter((entry) => entry.length > 0).map((entry) => entry.toLowerCase());
4147
+ return [...new Set(["", ...systemExts, ".exe", ".cmd", ".bat", ".ps1"])];
4148
+ }
4149
+ function probeWithSuffixes(directory, command, suffixes) {
4150
+ for (const suffix of suffixes) {
4151
+ const candidate = join4(directory, command + suffix);
4152
+ if (probe(candidate))
4153
+ return candidate;
4154
+ }
4155
+ return null;
4156
+ }
4157
+ function resolveLocal(command, workingDirectory, suffixes, stopAt) {
4158
+ const boundary = stopAt === undefined ? undefined : resolve7(stopAt);
4159
+ let current = resolve7(workingDirectory);
4160
+ while (true) {
4161
+ for (const rule of LOCAL_BIN_RULES) {
4162
+ if (!rule.markers.some((marker) => probe(join4(current, marker))))
4163
+ continue;
4164
+ for (const binDir of rule.binDirs) {
4165
+ const found = probeWithSuffixes(join4(current, binDir), command, suffixes);
4166
+ if (found !== null)
4167
+ return found;
4168
+ }
3918
4169
  }
4170
+ if (probe(join4(current, ".git")))
4171
+ return null;
4172
+ if (boundary !== undefined && current === boundary)
4173
+ return null;
4174
+ const parent = dirname7(current);
4175
+ if (parent === current)
4176
+ return null;
4177
+ current = parent;
3919
4178
  }
3920
- let pathEnv = process.env["PATH"] ?? "";
3921
- if (isWindows && !pathEnv) {
4179
+ }
4180
+ function resolveFromPath(command, suffixes, platform, pathEnvOverride) {
4181
+ let pathEnv = pathEnvOverride ?? process.env["PATH"] ?? "";
4182
+ if (platform === "win32" && !pathEnv) {
3922
4183
  pathEnv = process.env["Path"] ?? "";
3923
4184
  }
3924
- const paths = pathEnv.split(delimiter3);
3925
- for (const p of paths) {
3926
- for (const suffix of exts) {
3927
- if (existsSync8(join3(p, cmd + suffix))) {
3928
- return true;
3929
- }
3930
- }
4185
+ for (const entry of pathEnv.split(delimiter3)) {
4186
+ if (entry.length === 0)
4187
+ continue;
4188
+ const found = probeWithSuffixes(entry, command, suffixes);
4189
+ if (found !== null)
4190
+ return found;
3931
4191
  }
3932
- if (cmd === "node")
3933
- return true;
3934
- return false;
4192
+ return null;
4193
+ }
4194
+ function resolveServerBinary(command, workingDirectory, options = {}) {
4195
+ if (command.length === 0)
4196
+ return null;
4197
+ const [cmd] = command;
4198
+ if (cmd === undefined || cmd.length === 0)
4199
+ return null;
4200
+ const platform = options.platform ?? process.platform;
4201
+ const suffixes = executableSuffixes(platform, options.pathExt);
4202
+ if (cmd.includes("/") || cmd.includes("\\")) {
4203
+ const explicit = isAbsolute3(cmd) ? cmd : resolve7(workingDirectory ?? process.cwd(), cmd);
4204
+ return probe(explicit) ? explicit : null;
4205
+ }
4206
+ const cacheKey = JSON.stringify([
4207
+ workingDirectory ?? "",
4208
+ cmd,
4209
+ platform,
4210
+ options.stopAt ?? "",
4211
+ options.pathExt ?? "",
4212
+ options.pathEnv ?? process.env["PATH"] ?? ""
4213
+ ]);
4214
+ const cached = resolutionCache.get(cacheKey);
4215
+ if (cached !== undefined)
4216
+ return cached;
4217
+ let resolved = null;
4218
+ if (workingDirectory !== undefined && workingDirectory.length > 0) {
4219
+ resolved = resolveLocal(cmd, workingDirectory, suffixes, options.stopAt);
4220
+ }
4221
+ resolved ??= resolveFromPath(cmd, suffixes, platform, options.pathEnv);
4222
+ if (resolved === null && cmd === "node")
4223
+ resolved = cmd;
4224
+ resolutionCache.set(cacheKey, resolved);
4225
+ return resolved;
4226
+ }
4227
+ function isServerInstalled(command, workingDirectory, options = {}) {
4228
+ if (command.length === 0)
4229
+ return false;
4230
+ return resolveServerBinary(command, workingDirectory, options) !== null;
3935
4231
  }
3936
4232
 
3937
4233
  // ../lsp-core/src/lsp/server-resolution.ts
4234
+ function withResolvedCommand(command, binaryPath) {
4235
+ return [binaryPath, ...command.slice(1)];
4236
+ }
3938
4237
  function findServerForExtension(ext) {
3939
4238
  const servers = getMergedServers();
4239
+ const workingDirectory = contextCwd();
3940
4240
  for (const server2 of servers) {
3941
- if (server2.extensions.includes(ext) && isServerInstalled(server2.command)) {
4241
+ if (!server2.extensions.includes(ext))
4242
+ continue;
4243
+ const binaryPath = resolveServerBinary(server2.command, workingDirectory);
4244
+ if (binaryPath !== null) {
3942
4245
  const resolvedServer = {
3943
4246
  id: server2.id,
3944
- command: server2.command,
4247
+ command: withResolvedCommand(server2.command, binaryPath),
3945
4248
  extensions: server2.extensions,
3946
4249
  priority: server2.priority
3947
4250
  };
@@ -3988,6 +4291,7 @@ function findServerForExtension(ext) {
3988
4291
  function getAllServers() {
3989
4292
  const servers = getMergedServers();
3990
4293
  const disabled = getDisabledServerIds();
4294
+ const workingDirectory = contextCwd();
3991
4295
  const result = [];
3992
4296
  const seen = new Set;
3993
4297
  for (const server2 of servers) {
@@ -3995,7 +4299,7 @@ function getAllServers() {
3995
4299
  continue;
3996
4300
  result.push({
3997
4301
  id: server2.id,
3998
- installed: isServerInstalled(server2.command),
4302
+ installed: isServerInstalled(server2.command, workingDirectory),
3999
4303
  extensions: server2.extensions,
4000
4304
  disabled: false,
4001
4305
  source: server2.source,
@@ -4009,7 +4313,7 @@ function getAllServers() {
4009
4313
  const builtin = BUILTIN_SERVERS[id];
4010
4314
  result.push({
4011
4315
  id,
4012
- installed: builtin ? isServerInstalled(builtin.command) : false,
4316
+ installed: builtin ? isServerInstalled(builtin.command, workingDirectory) : false,
4013
4317
  extensions: builtin?.extensions ?? [],
4014
4318
  disabled: true,
4015
4319
  source: "disabled",
@@ -4020,7 +4324,6 @@ function getAllServers() {
4020
4324
  }
4021
4325
 
4022
4326
  // ../lsp-core/src/lsp/client-wrapper.ts
4023
- var WORKSPACE_MARKERS = [".git", "package.json", "pyproject.toml", "Cargo.toml", "go.mod", "pom.xml", "build.gradle"];
4024
4327
  function isDirectoryPath(filePath) {
4025
4328
  try {
4026
4329
  return statSync3(filePath).isDirectory();
@@ -4029,32 +4332,90 @@ function isDirectoryPath(filePath) {
4029
4332
  }
4030
4333
  }
4031
4334
  function findWorkspaceRoot(filePath) {
4032
- const abs = resolvePathInsideContext(filePath);
4335
+ const cwd = contextCwd();
4336
+ const abs = resolveReadablePathInsideContext(filePath);
4033
4337
  let dir = abs;
4034
4338
  if (!isDirectoryPath(dir)) {
4035
- dir = dirname6(dir);
4036
- }
4037
- let prevDir = "";
4038
- while (dir !== prevDir) {
4039
- for (const marker of WORKSPACE_MARKERS) {
4040
- if (existsSync9(join4(dir, marker))) {
4041
- return dir;
4339
+ dir = dirname8(dir);
4340
+ }
4341
+ if (!isPathInside(cwd, abs))
4342
+ return findWorkspaceRootOutsideContext(dir);
4343
+ const fallbackRoot = nearestExistingDirectoryInsideContext(dir, cwd) ?? cwd;
4344
+ let nearestPackageRoot;
4345
+ while (isPathInside(cwd, dir)) {
4346
+ const canonicalDir = existingDirectoryInsideContext(dir, cwd);
4347
+ if (canonicalDir !== undefined) {
4348
+ if (existsSync10(join5(dir, GIT_WORKSPACE_MARKER))) {
4349
+ return canonicalDir;
4350
+ }
4351
+ if (nearestPackageRoot === undefined && hasProjectWorkspaceMarker(dir)) {
4352
+ nearestPackageRoot = canonicalDir;
4042
4353
  }
4043
4354
  }
4044
- prevDir = dir;
4045
- dir = dirname6(dir);
4355
+ if (dir === cwd)
4356
+ break;
4357
+ dir = dirname8(dir);
4046
4358
  }
4047
- return dirname6(abs);
4359
+ return nearestPackageRoot ?? fallbackRoot;
4360
+ }
4361
+ function hasProjectWorkspaceMarker(directory) {
4362
+ return PROJECT_WORKSPACE_MARKERS.some((marker) => existsSync10(join5(directory, marker)));
4363
+ }
4364
+ function resolveReadablePathInsideContext(filePath) {
4365
+ const cwd = contextCwd();
4366
+ const abs = resolve8(cwd, filePath);
4367
+ if (isPathInside(cwd, abs))
4368
+ return abs;
4369
+ const rebased = rebaseThroughCanonicalAncestor(abs, cwd);
4370
+ if (rebased !== undefined)
4371
+ return rebased;
4372
+ return canonicalizeExistingOrNearestAncestor(abs);
4048
4373
  }
4049
4374
  function resolvePathInsideContext(filePath) {
4050
4375
  const cwd = contextCwd();
4051
- const abs = resolve7(cwd, filePath);
4376
+ const abs = resolveReadablePathInsideContext(filePath);
4052
4377
  const canonical = canonicalizeExistingOrNearestAncestor(abs);
4053
4378
  if (!isPathInside(cwd, canonical)) {
4054
4379
  throw new LspInvalidPathError(`LSP file path must be inside request cwd: ${filePath}`);
4055
4380
  }
4056
4381
  return canonical;
4057
4382
  }
4383
+ function rebaseThroughCanonicalAncestor(path, cwd) {
4384
+ let current = path;
4385
+ const suffix = [];
4386
+ while (true) {
4387
+ if (existsSync10(current)) {
4388
+ const canonical = realpathSync5(current);
4389
+ if (isPathInside(cwd, canonical))
4390
+ return suffix.length === 0 ? canonical : join5(canonical, ...suffix);
4391
+ }
4392
+ const parent = dirname8(current);
4393
+ if (parent === current)
4394
+ return;
4395
+ suffix.unshift(basename3(current));
4396
+ current = parent;
4397
+ }
4398
+ }
4399
+ function existingDirectoryInsideContext(directory, cwd) {
4400
+ if (!existsSync10(directory))
4401
+ return;
4402
+ const canonical = realpathSync5(directory);
4403
+ if (!statSync3(canonical).isDirectory())
4404
+ return;
4405
+ return isPathInside(cwd, canonical) ? canonical : undefined;
4406
+ }
4407
+ function nearestExistingDirectoryInsideContext(directory, cwd) {
4408
+ let current = directory;
4409
+ while (isPathInside(cwd, current)) {
4410
+ const canonical = existingDirectoryInsideContext(current, cwd);
4411
+ if (canonical !== undefined)
4412
+ return canonical;
4413
+ if (current === cwd)
4414
+ return;
4415
+ current = dirname8(current);
4416
+ }
4417
+ return;
4418
+ }
4058
4419
  function formatServerLookupError(result) {
4059
4420
  if (result.status === "not_installed") {
4060
4421
  return formatNotInstalled(result);
@@ -4078,6 +4439,19 @@ function formatServerLookupError(result) {
4078
4439
  ].join(`
4079
4440
  `);
4080
4441
  }
4442
+ function formatInstallOptions(serverId, installHint) {
4443
+ const localHint = LSP_LOCAL_INSTALL_HINTS[serverId];
4444
+ if (localHint === undefined) {
4445
+ return ["To install, run:", ` ${installHint}`];
4446
+ }
4447
+ return [
4448
+ "To install in THIS repository (preferred — no global install needed):",
4449
+ ` ${localHint}`,
4450
+ "",
4451
+ "Or install it globally:",
4452
+ ` ${installHint}`
4453
+ ];
4454
+ }
4081
4455
  function formatNotInstalled(result) {
4082
4456
  const { server: server2, installHint } = result;
4083
4457
  const extensions = server2.extensions.join(", ");
@@ -4092,19 +4466,19 @@ function formatNotInstalled(result) {
4092
4466
  `Command not found: ${server2.command[0]}`,
4093
4467
  ""
4094
4468
  ];
4469
+ const installOptions = formatInstallOptions(server2.id, installHint);
4095
4470
  if (decision === "allowed") {
4096
4471
  return [
4097
4472
  ...header,
4098
4473
  "The user has pre-authorized LSP installation. Run the install command, then retry this tool:",
4099
- ` ${installHint}`
4474
+ ...installOptions.slice(1)
4100
4475
  ].join(`
4101
4476
  `);
4102
4477
  }
4103
4478
  if (!context.capabilities.installDecisionTool) {
4104
4479
  return [
4105
4480
  ...header,
4106
- "To install, run:",
4107
- ` ${installHint}`,
4481
+ ...installOptions,
4108
4482
  "",
4109
4483
  "ACTION REQUIRED — ASK THE USER whether to install this LSP server.",
4110
4484
  "Install-decision recording is unavailable in this harness; proceed without LSP if the user declines."
@@ -4113,8 +4487,7 @@ function formatNotInstalled(result) {
4113
4487
  }
4114
4488
  return [
4115
4489
  ...header,
4116
- "To install, run:",
4117
- ` ${installHint}`,
4490
+ ...installOptions,
4118
4491
  "",
4119
4492
  "ACTION REQUIRED — ASK THE USER whether to install this LSP server.",
4120
4493
  "- If the user agrees: run the install command above, then retry this tool.",
@@ -4125,7 +4498,7 @@ function formatNotInstalled(result) {
4125
4498
  ].join(`
4126
4499
  `);
4127
4500
  }
4128
- var READ_ONLY_RETRY_TOOLS = new Set([
4501
+ var READ_ONLY_TOOLS = new Set([
4129
4502
  "diagnostics",
4130
4503
  "definition",
4131
4504
  "references",
@@ -4134,7 +4507,7 @@ var READ_ONLY_RETRY_TOOLS = new Set([
4134
4507
  "prepareRename"
4135
4508
  ]);
4136
4509
  async function withLspClient(filePath, fn, toolName, options = {}) {
4137
- const absPath = resolvePathInsideContext(filePath);
4510
+ const absPath = READ_ONLY_TOOLS.has(toolName) ? resolveReadablePathInsideContext(filePath) : resolvePathInsideContext(filePath);
4138
4511
  if (isDirectoryPath(absPath)) {
4139
4512
  throw new LspInvalidPathError("Directory paths are not supported by this LSP tool. " + "Use lsp.diagnostics with a directory path for directory diagnostics.");
4140
4513
  }
@@ -4149,9 +4522,9 @@ async function withLspClient(filePath, fn, toolName, options = {}) {
4149
4522
  const acquireAndCall = async (allowRetry) => {
4150
4523
  const client = await manager.getClient(root, server2, options.signal);
4151
4524
  try {
4152
- return await fn(client, root);
4525
+ return await fn(client, root, absPath);
4153
4526
  } catch (err) {
4154
- if (allowRetry && READ_ONLY_RETRY_TOOLS.has(toolName) && isLspDeadConnectionError(err)) {
4527
+ if (allowRetry && READ_ONLY_TOOLS.has(toolName) && isLspDeadConnectionError(err)) {
4155
4528
  manager.invalidateClient(root, server2.id, client);
4156
4529
  return acquireAndCall(false);
4157
4530
  }
@@ -4169,8 +4542,8 @@ async function withLspClient(filePath, fn, toolName, options = {}) {
4169
4542
  }
4170
4543
 
4171
4544
  // ../lsp-core/src/lsp/directory-diagnostics.ts
4172
- import { existsSync as existsSync10, lstatSync as lstatSync4, readdirSync as readdirSync3 } from "node:fs";
4173
- import { join as join5, resolve as resolve8 } from "node:path";
4545
+ import { existsSync as existsSync11, lstatSync as lstatSync4, readdirSync as readdirSync3 } from "node:fs";
4546
+ import { join as join6, resolve as resolve9 } from "node:path";
4174
4547
 
4175
4548
  // ../lsp-core/src/lsp/formatters.ts
4176
4549
  import { fileURLToPath as fileURLToPath2 } from "node:url";
@@ -4300,7 +4673,7 @@ function collectFilesWithExtension(dir, extension, maxFiles) {
4300
4673
  for (const entry of entries) {
4301
4674
  if (files.length >= maxFiles)
4302
4675
  return;
4303
- const fullPath = join5(currentDir, entry);
4676
+ const fullPath = join6(currentDir, entry);
4304
4677
  let stat;
4305
4678
  try {
4306
4679
  stat = lstatSync4(fullPath);
@@ -4325,8 +4698,8 @@ async function aggregateDiagnosticsForDirectory(directory, extension, severity,
4325
4698
  if (!extension.startsWith(".")) {
4326
4699
  throw new LspInvalidPathError(`Extension must start with a dot (e.g., ".ts", not "${extension}"). Use ".${extension}" instead.`);
4327
4700
  }
4328
- const absDir = resolve8(options.workspaceRoot ?? contextCwd(), directory);
4329
- if (!existsSync10(absDir)) {
4701
+ const absDir = resolve9(options.workspaceRoot ?? contextCwd(), directory);
4702
+ if (!existsSync11(absDir)) {
4330
4703
  throw new LspInvalidPathError(`Directory does not exist: ${absDir}`);
4331
4704
  }
4332
4705
  const serverResult = options.server === undefined ? findServerForExtension(extension) : { status: "found", server: options.server };
@@ -4413,7 +4786,7 @@ async function aggregateDiagnosticsForDirectory(directory, extension, severity,
4413
4786
 
4414
4787
  // ../lsp-core/src/lsp/infer-extension.ts
4415
4788
  import { lstatSync as lstatSync5, readdirSync as readdirSync4 } from "node:fs";
4416
- import { join as join6 } from "node:path";
4789
+ import { join as join7 } from "node:path";
4417
4790
  var SKIP_DIRECTORIES2 = new Set(["node_modules", ".git", "dist", "build", ".next", "out"]);
4418
4791
  var MAX_SCAN_ENTRIES = 500;
4419
4792
  function inferExtensionFromDirectory(directory) {
@@ -4431,7 +4804,7 @@ function inferExtensionFromDirectory(directory) {
4431
4804
  for (const entry of entries) {
4432
4805
  if (scanned >= MAX_SCAN_ENTRIES)
4433
4806
  return;
4434
- const fullPath = join6(dir, entry);
4807
+ const fullPath = join7(dir, entry);
4435
4808
  let stat;
4436
4809
  try {
4437
4810
  stat = lstatSync5(fullPath);
@@ -4606,7 +4979,7 @@ async function executeLspDiagnostics(params, signal) {
4606
4979
  const filePath = requireString(params, "filePath");
4607
4980
  const severity = severityFilter(params);
4608
4981
  try {
4609
- const absPath = resolvePathInsideContext(filePath);
4982
+ const absPath = resolveReadablePathInsideContext(filePath);
4610
4983
  if (isDirectoryPath(absPath)) {
4611
4984
  const extension = inferExtensionFromDirectory(absPath);
4612
4985
  if (!extension) {
@@ -4635,7 +5008,7 @@ async function executeLspDiagnostics(params, signal) {
4635
5008
  };
4636
5009
  return text(output2.output, details2);
4637
5010
  }
4638
- const result = await withLspClient(filePath, async (client) => client.diagnostics(filePath, signal), "diagnostics", clientOptions(signal));
5011
+ const result = await withLspClient(filePath, async (client, _workspaceRoot, resolvedFilePath) => client.diagnostics(resolvedFilePath, signal), "diagnostics", clientOptions(signal));
4639
5012
  if (result.transientError) {
4640
5013
  const message = result.transientError.message;
4641
5014
  const details2 = {
@@ -4682,6 +5055,96 @@ async function executeLspDiagnostics(params, signal) {
4682
5055
  throw error;
4683
5056
  }
4684
5057
  }
5058
+ // ../lsp-core/src/lsp/format-document.ts
5059
+ import { readFileSync as readFileSync5, renameSync as renameSync3, unlinkSync, writeFileSync as writeFileSync3 } from "node:fs";
5060
+ var DEFAULT_FORMATTING_OPTIONS = {
5061
+ tabSize: 4,
5062
+ insertSpaces: false,
5063
+ trimTrailingWhitespace: true,
5064
+ insertFinalNewline: true,
5065
+ trimFinalNewlines: true
5066
+ };
5067
+ var UNCHANGED = { status: "unchanged", linesAdded: 0, linesRemoved: 0 };
5068
+ async function formatDocumentWithClient(client, filePath, options = {}) {
5069
+ const edits = await client.formatDocument(filePath, options.formattingOptions ?? DEFAULT_FORMATTING_OPTIONS, options.signal);
5070
+ if (edits === null)
5071
+ return { status: "unavailable", reason: "capability_not_advertised" };
5072
+ if (edits.length === 0)
5073
+ return UNCHANGED;
5074
+ const before = readFileSync5(filePath, "utf-8");
5075
+ const normalized = normalizeTextEdits(before, edits, 0);
5076
+ if (normalized.text === before)
5077
+ return UNCHANGED;
5078
+ writeAtomically(filePath, normalized.text);
5079
+ await client.openFile(filePath);
5080
+ return {
5081
+ status: "formatted",
5082
+ ...lineDelta(normalized.edits)
5083
+ };
5084
+ }
5085
+ function lineDelta(edits) {
5086
+ let linesAdded = 0;
5087
+ let linesRemoved = 0;
5088
+ for (const edit of edits) {
5089
+ linesRemoved += edit.range.end.line - edit.range.start.line + 1;
5090
+ linesAdded += edit.newText.split(`
5091
+ `).length;
5092
+ }
5093
+ return { linesAdded, linesRemoved };
5094
+ }
5095
+ function writeAtomically(filePath, content) {
5096
+ const tempPath = `${filePath}.omo-format.tmp`;
5097
+ writeFileSync3(tempPath, content, "utf-8");
5098
+ try {
5099
+ renameSync3(tempPath, filePath);
5100
+ } catch (error) {
5101
+ try {
5102
+ unlinkSync(tempPath);
5103
+ } catch {}
5104
+ throw error;
5105
+ }
5106
+ }
5107
+
5108
+ // ../lsp-core/src/tools/format.ts
5109
+ async function executeLspFormat(params, signal) {
5110
+ const filePath = requireString(params, "filePath");
5111
+ try {
5112
+ const result = await withLspClient(filePath, async (client, _workspaceRoot, resolvedFilePath) => formatDocumentWithClient(client, resolvedFilePath, signal === undefined ? {} : { signal }), "format", clientOptions(signal));
5113
+ return text(describeResult(filePath, result), formatDetails(filePath, result));
5114
+ } catch (error) {
5115
+ const missingDependency = missingDependencyResult(error, {
5116
+ filePath,
5117
+ status: "unavailable",
5118
+ reason: "server_unavailable",
5119
+ linesAdded: 0,
5120
+ linesRemoved: 0
5121
+ });
5122
+ if (missingDependency)
5123
+ return missingDependency;
5124
+ throw error;
5125
+ }
5126
+ }
5127
+ function formatDetails(filePath, result) {
5128
+ if (result.status === "unavailable") {
5129
+ return { filePath, status: "unavailable", reason: result.reason, linesAdded: 0, linesRemoved: 0 };
5130
+ }
5131
+ return {
5132
+ filePath,
5133
+ status: result.status,
5134
+ linesAdded: result.linesAdded,
5135
+ linesRemoved: result.linesRemoved
5136
+ };
5137
+ }
5138
+ function describeResult(filePath, result) {
5139
+ if (result.status === "unavailable") {
5140
+ return `Formatting unavailable for ${filePath}: the language server does not advertise documentFormattingProvider.`;
5141
+ }
5142
+ if (result.status === "unchanged") {
5143
+ return `Already formatted: ${filePath}`;
5144
+ }
5145
+ return `Formatted ${filePath} (+${result.linesAdded}/-${result.linesRemoved} lines)`;
5146
+ }
5147
+
4685
5148
  // ../lsp-core/src/tools/install-decision.ts
4686
5149
  async function executeLspInstallDecision(params) {
4687
5150
  const serverId = requireString(params, "server_id");
@@ -4710,7 +5173,7 @@ async function executeLspGotoDefinition(params, signal) {
4710
5173
  const line = requireNumber(params, "line");
4711
5174
  const character = requireNumber(params, "character");
4712
5175
  try {
4713
- const result = await withLspClient(filePath, async (client) => client.definition(filePath, line, character, signal), "definition", clientOptions(signal));
5176
+ const result = await withLspClient(filePath, async (client, _workspaceRoot, resolvedFilePath) => client.definition(resolvedFilePath, line, character, signal), "definition", clientOptions(signal));
4714
5177
  const locations = !result ? [] : Array.isArray(result) ? result : [result];
4715
5178
  const details = { filePath, line, character, locations };
4716
5179
  if (locations.length === 0)
@@ -4735,7 +5198,7 @@ async function executeLspFindReferences(params, signal) {
4735
5198
  const character = requireNumber(params, "character");
4736
5199
  const includeDeclaration = optionalBoolean(params, "includeDeclaration") ?? true;
4737
5200
  try {
4738
- const result = await withLspClient(filePath, async (client) => client.references(filePath, line, character, includeDeclaration, signal), "references", clientOptions(signal));
5201
+ const result = await withLspClient(filePath, async (client, _workspaceRoot, resolvedFilePath) => client.references(resolvedFilePath, line, character, includeDeclaration, signal), "references", clientOptions(signal));
4739
5202
  const references = Array.isArray(result) ? result : [];
4740
5203
  const total = references.length;
4741
5204
  const truncated = total > DEFAULT_MAX_REFERENCES;
@@ -4777,7 +5240,7 @@ async function executeLspPrepareRename(params, signal) {
4777
5240
  const line = requireNumber(params, "line");
4778
5241
  const character = requireNumber(params, "character");
4779
5242
  try {
4780
- const result = await withLspClient(filePath, async (client) => client.prepareRename(filePath, line, character, signal), "prepareRename", clientOptions(signal));
5243
+ const result = await withLspClient(filePath, async (client, _workspaceRoot, resolvedFilePath) => client.prepareRename(resolvedFilePath, line, character, signal), "prepareRename", clientOptions(signal));
4781
5244
  const details = { filePath, line, character, result };
4782
5245
  return text(formatPrepareRenameResult(result), details);
4783
5246
  } catch (error) {
@@ -4798,7 +5261,7 @@ async function executeLspRename(params, signal) {
4798
5261
  const character = requireNumber(params, "character");
4799
5262
  const newName = requireString(params, "newName");
4800
5263
  try {
4801
- const result = await withLspClient(filePath, async (client) => client.rename(filePath, line, character, newName, signal), "rename", clientOptions(signal));
5264
+ const result = await withLspClient(filePath, async (client, _workspaceRoot, resolvedFilePath) => client.rename(resolvedFilePath, line, character, newName, signal), "rename", clientOptions(signal));
4802
5265
  const details = { filePath, line, character, newName, apply: result.apply, edit: result.edit };
4803
5266
  return text(formatApplyResult(result.apply), details, !result.apply.success);
4804
5267
  } catch (error) {
@@ -4878,7 +5341,7 @@ async function executeLspSymbols(params, signal) {
4878
5341
  const symbols2 = await withLspClient(filePath, async (client) => client.workspaceSymbols(query, signal), "workspaceSymbols", clientOptions(signal));
4879
5342
  return formatSymbolsResult(filePath, scope, symbols2, limit, query);
4880
5343
  }
4881
- const symbols = await withLspClient(filePath, async (client) => client.documentSymbols(filePath, signal), "documentSymbols", clientOptions(signal));
5344
+ const symbols = await withLspClient(filePath, async (client, _workspaceRoot, resolvedFilePath) => client.documentSymbols(resolvedFilePath, signal), "documentSymbols", clientOptions(signal));
4882
5345
  return formatSymbolsResult(filePath, scope, symbols, limit);
4883
5346
  } catch (error) {
4884
5347
  const query = optionalString(params, "query");
@@ -5014,6 +5477,16 @@ var LSP_MCP_TOOLS = [
5014
5477
  }, ["filePath", "line", "character", "newName"]),
5015
5478
  execute: executeLspRename
5016
5479
  },
5480
+ {
5481
+ name: "format",
5482
+ aliases: ["lsp_format"],
5483
+ title: "LSP Format",
5484
+ description: "Format a source file with its language server and write the returned edits to disk.",
5485
+ inputSchema: objectSchema({
5486
+ filePath: { type: "string", description: "Source file path to format." }
5487
+ }, ["filePath"]),
5488
+ execute: executeLspFormat
5489
+ },
5017
5490
  {
5018
5491
  name: "install_decision",
5019
5492
  aliases: ["lsp_install_decision"],
@@ -5113,11 +5586,10 @@ function requestedProtocolVersion(params) {
5113
5586
  // src/daemon-client.ts
5114
5587
  import { connect } from "node:net";
5115
5588
  import { homedir as homedir3 } from "node:os";
5116
- import { join as join7 } from "node:path";
5589
+ import { join as join8 } from "node:path";
5117
5590
 
5118
5591
  // src/daemon-request-error.ts
5119
5592
  class DaemonRequestError extends Error {
5120
- requestWritten;
5121
5593
  constructor(message, requestWritten) {
5122
5594
  super(message);
5123
5595
  this.name = "DaemonRequestError";
@@ -5140,7 +5612,6 @@ class DaemonRequestCancelledError extends DaemonRequestError {
5140
5612
  }
5141
5613
 
5142
5614
  class DaemonRequestTimedOutError extends DaemonRequestError {
5143
- timeoutMs;
5144
5615
  constructor(requestWritten, timeoutMs) {
5145
5616
  super("daemon request timed out", requestWritten);
5146
5617
  this.name = "DaemonRequestTimedOutError";
@@ -5192,9 +5663,9 @@ function errorText(error) {
5192
5663
 
5193
5664
  // src/ensure-daemon.ts
5194
5665
  import { spawn as spawn2 } from "node:child_process";
5195
- import { closeSync as closeSync2, existsSync as existsSync11, mkdirSync as mkdirSync3, openSync as openSync2, writeSync as writeSync2 } from "node:fs";
5666
+ import { closeSync as closeSync2, existsSync as existsSync12, mkdirSync as mkdirSync3, openSync as openSync2, writeSync as writeSync2 } from "node:fs";
5196
5667
  import { Socket } from "node:net";
5197
- import { dirname as dirname8, isAbsolute as isAbsolute4 } from "node:path";
5668
+ import { dirname as dirname10, isAbsolute as isAbsolute5 } from "node:path";
5198
5669
  import { argv0, execPath } from "node:process";
5199
5670
 
5200
5671
  // src/ipc-protocol.ts
@@ -5208,25 +5679,23 @@ import {
5208
5679
  lstatSync as lstatSync6,
5209
5680
  mkdirSync as mkdirSync2,
5210
5681
  openSync,
5211
- readFileSync as readFileSync5,
5212
- unlinkSync,
5682
+ readFileSync as readFileSync6,
5683
+ unlinkSync as unlinkSync2,
5213
5684
  writeSync
5214
5685
  } from "node:fs";
5215
- import { dirname as dirname7 } from "node:path";
5686
+ import { dirname as dirname9 } from "node:path";
5216
5687
  var OMO_DAEMON_PROTOCOL_VERSION = 1;
5217
5688
  var AUTH_ERROR_CODE = -32001;
5218
5689
  var PROTOCOL_ERROR_CODE = -32002;
5219
5690
  var AUTH_TOKEN_BYTES = 32;
5220
5691
 
5221
5692
  class UnsafePrivateDirectoryError extends Error {
5222
- path;
5223
- reason;
5224
- name = "UnsafePrivateDirectoryError";
5225
- code = "unsafe_private_directory";
5226
5693
  constructor(path, reason) {
5227
5694
  super(`unsafe private directory ${path}: ${reason}`);
5228
5695
  this.path = path;
5229
5696
  this.reason = reason;
5697
+ this.name = "UnsafePrivateDirectoryError";
5698
+ this.code = "unsafe_private_directory";
5230
5699
  }
5231
5700
  }
5232
5701
  function authEnvelope(token) {
@@ -5234,7 +5703,7 @@ function authEnvelope(token) {
5234
5703
  }
5235
5704
  function readAuthToken(paths) {
5236
5705
  try {
5237
- const token = readFileSync5(paths.auth, "utf8").trim();
5706
+ const token = readFileSync6(paths.auth, "utf8").trim();
5238
5707
  return token.length > 0 ? token : null;
5239
5708
  } catch (error) {
5240
5709
  if (error instanceof Error)
@@ -5250,7 +5719,7 @@ function readOrCreateAuthToken(paths) {
5250
5719
  }
5251
5720
  function rotateAuthToken(paths) {
5252
5721
  try {
5253
- unlinkSync(paths.auth);
5722
+ unlinkSync2(paths.auth);
5254
5723
  } catch (error) {
5255
5724
  if (!(error instanceof Error))
5256
5725
  throw error;
@@ -5322,7 +5791,7 @@ function setPrivateFileMode(path) {
5322
5791
  chmodSync(path, 384);
5323
5792
  }
5324
5793
  function createAuthToken(paths) {
5325
- ensurePrivateDirectory(dirname7(paths.auth));
5794
+ ensurePrivateDirectory(dirname9(paths.auth));
5326
5795
  const token = randomBytes(AUTH_TOKEN_BYTES).toString("base64url");
5327
5796
  let fd;
5328
5797
  try {
@@ -5403,27 +5872,25 @@ import { fileURLToPath as fileURLToPath3 } from "node:url";
5403
5872
 
5404
5873
  // src/runtime-contract.ts
5405
5874
  import { statSync as statSync4 } from "node:fs";
5406
- import { isAbsolute as isAbsolute3 } from "node:path";
5875
+ import { isAbsolute as isAbsolute4 } from "node:path";
5407
5876
  var OMO_LSP_DAEMON_DIR = "OMO_LSP_DAEMON_DIR";
5408
5877
  var OMO_LSP_DAEMON_CLI = "OMO_LSP_DAEMON_CLI";
5409
5878
  var OMO_LSP_DAEMON_VERSION = "OMO_LSP_DAEMON_VERSION";
5410
5879
  var DAEMON_VERSION_PATTERN = /^[A-Za-z0-9][A-Za-z0-9._+-]{0,127}$/;
5411
5880
 
5412
5881
  class InvalidRuntimeOverrideError extends Error {
5413
- code = "invalid_runtime_override";
5414
- reason;
5415
5882
  constructor(reason, message) {
5416
5883
  super(message);
5884
+ this.code = "invalid_runtime_override";
5417
5885
  this.name = "InvalidRuntimeOverrideError";
5418
5886
  this.reason = reason;
5419
5887
  }
5420
5888
  }
5421
5889
 
5422
5890
  class InvalidDaemonVersionError extends Error {
5423
- code = "invalid_daemon_version";
5424
- version;
5425
5891
  constructor(version) {
5426
5892
  super("LSP daemon version must match [A-Za-z0-9][A-Za-z0-9._+-]{0,127}");
5893
+ this.code = "invalid_daemon_version";
5427
5894
  this.name = "InvalidDaemonVersionError";
5428
5895
  this.version = version;
5429
5896
  }
@@ -5442,12 +5909,12 @@ function resolveDaemonRuntime(env, defaults) {
5442
5909
  throw new InvalidRuntimeOverrideError("paired_values_required", `${OMO_LSP_DAEMON_CLI} and ${OMO_LSP_DAEMON_VERSION} must be set together`);
5443
5910
  }
5444
5911
  if (!hasCliOverride || !hasVersionOverride) {
5445
- if (!isAbsolute3(defaults.cliPath)) {
5912
+ if (!isAbsolute4(defaults.cliPath)) {
5446
5913
  throw new InvalidRuntimeOverrideError("packaged_cli_must_be_absolute", "Packaged LSP daemon CLI path must be absolute");
5447
5914
  }
5448
5915
  return { cliPath: defaults.cliPath, version: validateDaemonVersion(defaults.version) };
5449
5916
  }
5450
- if (!isAbsolute3(cliOverride)) {
5917
+ if (!isAbsolute4(cliOverride)) {
5451
5918
  throw new InvalidRuntimeOverrideError("cli_must_be_absolute", `${OMO_LSP_DAEMON_CLI} must be an absolute path to an existing regular file`);
5452
5919
  }
5453
5920
  let cliStats;
@@ -5469,10 +5936,9 @@ var requireFromHere = createRequire(import.meta.url);
5469
5936
  var MAX_SOCKET_PATH_LENGTH = 100;
5470
5937
 
5471
5938
  class InvalidDaemonDirectoryError extends Error {
5472
- code = "invalid_daemon_directory";
5473
- directory;
5474
5939
  constructor(directory) {
5475
5940
  super(`${OMO_LSP_DAEMON_DIR} must be an absolute path`);
5941
+ this.code = "invalid_daemon_directory";
5476
5942
  this.name = "InvalidDaemonDirectoryError";
5477
5943
  this.directory = directory;
5478
5944
  }
@@ -5626,7 +6092,7 @@ async function probeDaemon(paths, timeoutMs = PROBE_TIMEOUT_MS, signal) {
5626
6092
  return await pingDaemon(paths, token, timeoutMs, signal) !== null;
5627
6093
  }
5628
6094
  function pingDaemon(paths, token, timeoutMs = PROBE_TIMEOUT_MS, signal) {
5629
- return new Promise((resolve9) => {
6095
+ return new Promise((resolve10) => {
5630
6096
  const socket = new Socket;
5631
6097
  let settled = false;
5632
6098
  let timer;
@@ -5638,7 +6104,7 @@ function pingDaemon(paths, token, timeoutMs = PROBE_TIMEOUT_MS, signal) {
5638
6104
  clearTimeout(timer);
5639
6105
  signal?.removeEventListener("abort", onAbort);
5640
6106
  socket.destroy();
5641
- resolve9(value);
6107
+ resolve10(value);
5642
6108
  };
5643
6109
  const onAbort = () => finish(null);
5644
6110
  const decoder = createLineDecoder((message) => {
@@ -5662,12 +6128,13 @@ function pingDaemon(paths, token, timeoutMs = PROBE_TIMEOUT_MS, signal) {
5662
6128
  });
5663
6129
  }
5664
6130
  function spawnDaemonProcess(paths) {
5665
- mkdirSync3(dirname8(paths.log), { recursive: true });
6131
+ mkdirSync3(dirname10(paths.log), { recursive: true });
5666
6132
  const logFd = openSync2(paths.log, "a");
5667
6133
  try {
5668
6134
  const child = spawn2(resolveDaemonNodeExecutable(), [paths.cliPath, "daemon"], {
5669
6135
  detached: true,
5670
- stdio: ["ignore", logFd, logFd]
6136
+ stdio: ["ignore", logFd, logFd],
6137
+ windowsHide: true
5671
6138
  });
5672
6139
  child.once("spawn", () => closeSync2(logFd));
5673
6140
  child.once("error", (error) => {
@@ -5681,10 +6148,10 @@ function spawnDaemonProcess(paths) {
5681
6148
  throw error;
5682
6149
  }
5683
6150
  }
5684
- function resolveDaemonNodeExecutable(cachedExecPath = execPath, originalArgv0 = argv0, pathExists = existsSync11) {
6151
+ function resolveDaemonNodeExecutable(cachedExecPath = execPath, originalArgv0 = argv0, pathExists = existsSync12) {
5685
6152
  if (pathExists(cachedExecPath))
5686
6153
  return cachedExecPath;
5687
- if (isAbsolute4(originalArgv0) && pathExists(originalArgv0))
6154
+ if (isAbsolute5(originalArgv0) && pathExists(originalArgv0))
5688
6155
  return originalArgv0;
5689
6156
  return "node";
5690
6157
  }
@@ -5697,7 +6164,7 @@ function defaultEnsureDaemonDeps() {
5697
6164
  };
5698
6165
  }
5699
6166
  function sleepWithSignal(ms, signal) {
5700
- return new Promise((resolve9) => {
6167
+ return new Promise((resolve10) => {
5701
6168
  let settled = false;
5702
6169
  const finish = () => {
5703
6170
  if (settled)
@@ -5705,7 +6172,7 @@ function sleepWithSignal(ms, signal) {
5705
6172
  settled = true;
5706
6173
  clearTimeout(timer);
5707
6174
  signal?.removeEventListener("abort", finish);
5708
- resolve9();
6175
+ resolve10();
5709
6176
  };
5710
6177
  const timer = setTimeout(finish, ms);
5711
6178
  if (signal?.aborted) {
@@ -5720,7 +6187,7 @@ function awaitWithSignal2(promise, signal) {
5720
6187
  return promise;
5721
6188
  if (signal.aborted)
5722
6189
  return Promise.reject(abortError3(signal));
5723
- return new Promise((resolve9, reject) => {
6190
+ return new Promise((resolve10, reject) => {
5724
6191
  let settled = false;
5725
6192
  const finish = (run) => {
5726
6193
  if (settled)
@@ -5731,7 +6198,7 @@ function awaitWithSignal2(promise, signal) {
5731
6198
  };
5732
6199
  const onAbort = () => finish(() => reject(abortError3(signal)));
5733
6200
  signal.addEventListener("abort", onAbort, { once: true });
5734
- promise.then((value) => finish(() => resolve9(value)), (error) => finish(() => reject(error)));
6201
+ promise.then((value) => finish(() => resolve10(value)), (error) => finish(() => reject(error)));
5735
6202
  });
5736
6203
  }
5737
6204
  function throwIfAborted(signal) {
@@ -5780,7 +6247,10 @@ function parsePingResponse(message) {
5780
6247
  var CONTEXT_KEY = "_context";
5781
6248
 
5782
6249
  class InvalidDaemonRequestError extends Error {
5783
- name = "InvalidDaemonRequestError";
6250
+ constructor() {
6251
+ super(...arguments);
6252
+ this.name = "InvalidDaemonRequestError";
6253
+ }
5784
6254
  }
5785
6255
  function extractRequestContext(raw) {
5786
6256
  if (!isPlainRecord(raw) || raw["method"] !== "tools/call")
@@ -5896,14 +6366,17 @@ async function callToolViaDaemon(name, args, options) {
5896
6366
  function callDiagnosticsViaDaemon(filePath, options) {
5897
6367
  return callToolViaDaemon("diagnostics", { filePath, severity: "error" }, options);
5898
6368
  }
6369
+ function callFormatViaDaemon(filePath, options) {
6370
+ return callToolViaDaemon("format", { filePath }, options);
6371
+ }
5899
6372
  function currentRequestContext(env = process.env) {
5900
6373
  const cwd = process.cwd();
5901
6374
  const home = env["HOME"] ?? homedir3();
5902
6375
  return parseLspRequestContext({
5903
6376
  cwd,
5904
- projectConfigPaths: [join7(cwd, ".codex", "lsp-client.json")],
5905
- userConfigPath: join7(home, ".codex", "lsp-client.json"),
5906
- installDecisionsPath: join7(home, ".codex", "lsp-install-decisions.json"),
6377
+ projectConfigPaths: [join8(cwd, ".codex", "lsp-client.json")],
6378
+ userConfigPath: join8(home, ".codex", "lsp-client.json"),
6379
+ installDecisionsPath: join8(home, ".codex", "lsp-install-decisions.json"),
5907
6380
  capabilities: { installDecisionTool: true }
5908
6381
  });
5909
6382
  }
@@ -5918,7 +6391,7 @@ function withContext(args, context) {
5918
6391
  function ensureDaemonAvailable(paths, ensure, signal) {
5919
6392
  if (!signal)
5920
6393
  return ensure(paths);
5921
- return new Promise((resolve9, reject) => {
6394
+ return new Promise((resolve10, reject) => {
5922
6395
  let settled = false;
5923
6396
  const finish = (run) => {
5924
6397
  if (settled)
@@ -5933,11 +6406,11 @@ function ensureDaemonAvailable(paths, ensure, signal) {
5933
6406
  return;
5934
6407
  }
5935
6408
  signal.addEventListener("abort", onAbort, { once: true });
5936
- Promise.resolve().then(() => ensure(paths, signal)).then(() => finish(() => resolve9()), (error) => finish(() => reject(signal.aborted ? new DaemonRequestCancelledError(false) : error)));
6409
+ Promise.resolve().then(() => ensure(paths, signal)).then(() => finish(() => resolve10()), (error) => finish(() => reject(signal.aborted ? new DaemonRequestCancelledError(false) : error)));
5937
6410
  });
5938
6411
  }
5939
6412
  function sendToolCall(paths, token, name, args, options) {
5940
- return new Promise((resolve9, reject) => {
6413
+ return new Promise((resolve10, reject) => {
5941
6414
  const socket = connect(paths.socket);
5942
6415
  const requestId = allocateProxyRequestId();
5943
6416
  let settled = false;
@@ -5990,7 +6463,7 @@ function sendToolCall(paths, token, name, args, options) {
5990
6463
  }
5991
6464
  const result = toToolResult(message, requestId);
5992
6465
  if (result)
5993
- finish(() => resolve9(result));
6466
+ finish(() => resolve10(result));
5994
6467
  else
5995
6468
  finish(() => reject(new DaemonRequestError("invalid daemon response", requestWritten)));
5996
6469
  });
@@ -6158,18 +6631,18 @@ function canonicalizePathList(value) {
6158
6631
  return value.split(delimiter4).map((entry) => canonicalizePath(entry) ?? entry).join(delimiter4);
6159
6632
  }
6160
6633
  function canonicalizePath(value) {
6161
- if (value === undefined || !isAbsolute5(value) || !existsSync12(value))
6634
+ if (value === undefined || !isAbsolute6(value) || !existsSync13(value))
6162
6635
  return value;
6163
- return realpathSync4(value);
6636
+ return realpathSync6(value);
6164
6637
  }
6165
6638
  function projectRootFromOpenCodeConfigPath(path2) {
6166
- if (basename3(path2) !== "lsp.json" && basename3(path2) !== "lsp-client.json")
6639
+ if (basename4(path2) !== "lsp.json" && basename4(path2) !== "lsp-client.json")
6167
6640
  return;
6168
- const configDir = dirname9(path2);
6169
- const configDirName = basename3(configDir);
6641
+ const configDir = dirname11(path2);
6642
+ const configDirName = basename4(configDir);
6170
6643
  if (configDirName !== ".opencode" && configDirName !== ".omo")
6171
6644
  return;
6172
- return dirname9(configDir);
6645
+ return dirname11(configDir);
6173
6646
  }
6174
6647
 
6175
6648
  // src/daemon-server.ts
@@ -6178,12 +6651,12 @@ import { createServer as createServer2 } from "node:net";
6178
6651
 
6179
6652
  // src/ownership.ts
6180
6653
  import { randomUUID } from "node:crypto";
6181
- import { existsSync as existsSync13, lstatSync as lstatSync7, readFileSync as readFileSync7, statSync as statSync5, unlinkSync as unlinkSync3 } from "node:fs";
6182
- import { dirname as dirname11 } from "node:path";
6654
+ import { existsSync as existsSync14, lstatSync as lstatSync7, readFileSync as readFileSync8, statSync as statSync5, unlinkSync as unlinkSync4 } from "node:fs";
6655
+ import { dirname as dirname13 } from "node:path";
6183
6656
 
6184
6657
  // src/lock.ts
6185
- import { closeSync as closeSync3, mkdirSync as mkdirSync4, openSync as openSync3, readFileSync as readFileSync6, unlinkSync as unlinkSync2, writeSync as writeSync3 } from "node:fs";
6186
- import { dirname as dirname10 } from "node:path";
6658
+ import { closeSync as closeSync3, mkdirSync as mkdirSync4, openSync as openSync3, readFileSync as readFileSync7, unlinkSync as unlinkSync3, writeSync as writeSync3 } from "node:fs";
6659
+ import { dirname as dirname12 } from "node:path";
6187
6660
  function isProcessAlive2(pid) {
6188
6661
  if (!Number.isInteger(pid) || pid <= 0)
6189
6662
  return false;
@@ -6198,14 +6671,14 @@ function isProcessAlive2(pid) {
6198
6671
  }
6199
6672
  function readLockPid(lockPath) {
6200
6673
  try {
6201
- const pid = Number.parseInt(readFileSync6(lockPath, "utf8").trim(), 10);
6674
+ const pid = Number.parseInt(readFileSync7(lockPath, "utf8").trim(), 10);
6202
6675
  return Number.isInteger(pid) ? pid : null;
6203
6676
  } catch {
6204
6677
  return null;
6205
6678
  }
6206
6679
  }
6207
6680
  function tryAcquireLock(lockPath, ownerPid = process.pid) {
6208
- mkdirSync4(dirname10(lockPath), { recursive: true });
6681
+ mkdirSync4(dirname12(lockPath), { recursive: true });
6209
6682
  for (let attempt = 0;attempt < 2; attempt += 1) {
6210
6683
  const handle = writeLockFile(lockPath, ownerPid);
6211
6684
  if (handle)
@@ -6237,7 +6710,7 @@ function reapStaleLock(lockPath) {
6237
6710
  }
6238
6711
  function unlinkQuietly(path2) {
6239
6712
  try {
6240
- unlinkSync2(path2);
6713
+ unlinkSync3(path2);
6241
6714
  } catch (error) {
6242
6715
  if (error instanceof Error)
6243
6716
  return;
@@ -6253,17 +6726,19 @@ function errorCode3(error) {
6253
6726
 
6254
6727
  // src/ownership.ts
6255
6728
  class DaemonAlreadyRunningError extends Error {
6256
- name = "DaemonAlreadyRunningError";
6257
- code = "daemon_already_running";
6729
+ constructor() {
6730
+ super(...arguments);
6731
+ this.name = "DaemonAlreadyRunningError";
6732
+ this.code = "daemon_already_running";
6733
+ }
6258
6734
  }
6259
6735
 
6260
6736
  class DaemonStartupDeferredError extends Error {
6261
- reason;
6262
- name = "DaemonStartupDeferredError";
6263
- code = "daemon_startup_deferred";
6264
6737
  constructor(reason) {
6265
6738
  super(`LSP daemon startup deferred: ${reason}`);
6266
6739
  this.reason = reason;
6740
+ this.name = "DaemonStartupDeferredError";
6741
+ this.code = "daemon_startup_deferred";
6267
6742
  }
6268
6743
  }
6269
6744
  async function acquireStartupLease(paths, pingOwner) {
@@ -6286,11 +6761,11 @@ async function acquireStartupLease(paths, pingOwner) {
6286
6761
  function ensureDaemonDirectories(paths) {
6287
6762
  ensurePrivateDirectory(paths.dir);
6288
6763
  if (process.platform !== "win32")
6289
- ensurePrivateDirectory(dirname11(paths.socket));
6764
+ ensurePrivateDirectory(dirname13(paths.socket));
6290
6765
  }
6291
6766
  function readDaemonOwner(paths) {
6292
6767
  try {
6293
- return parseOwner(JSON.parse(readFileSync7(paths.owner, "utf8")));
6768
+ return parseOwner(JSON.parse(readFileSync8(paths.owner, "utf8")));
6294
6769
  } catch (error) {
6295
6770
  if (error instanceof Error)
6296
6771
  return null;
@@ -6366,10 +6841,10 @@ async function validateExistingOwner(paths, pingOwner) {
6366
6841
  throw new DaemonStartupDeferredError("reachable_owner_mismatch");
6367
6842
  }
6368
6843
  function cleanupDeadOwner(paths, owner) {
6369
- if (process.platform !== "win32" && existsSync13(owner.endpoint.path)) {
6844
+ if (process.platform !== "win32" && existsSync14(owner.endpoint.path)) {
6370
6845
  const stat = lstatSync7(owner.endpoint.path);
6371
6846
  if (stat.isSocket())
6372
- unlinkSync3(owner.endpoint.path);
6847
+ unlinkSync4(owner.endpoint.path);
6373
6848
  }
6374
6849
  unlinkQuietly(paths.pid);
6375
6850
  unlinkQuietly(paths.endpoint);
@@ -6417,7 +6892,7 @@ function parseEndpoint(value) {
6417
6892
  // src/version-reap.ts
6418
6893
  import { execFile } from "node:child_process";
6419
6894
  import { readdir, readFile, rm } from "node:fs/promises";
6420
- import { basename as basename4, dirname as dirname12, join as join8 } from "node:path";
6895
+ import { basename as basename5, dirname as dirname14, join as join9 } from "node:path";
6421
6896
  var TERM_GRACE_MS = 5000;
6422
6897
  var KILL_GRACE_MS = 1000;
6423
6898
  var VERSION_ENTRY_PATTERN = /^v([A-Za-z0-9][A-Za-z0-9._+-]{0,127})$/;
@@ -6438,7 +6913,7 @@ async function attestDaemonCliProcess(pid, platform, deps = {}) {
6438
6913
  return isNodeCliDaemonCommand(command.trim());
6439
6914
  }
6440
6915
  async function reapStaleDaemonVersions(ownPaths, deps = {}) {
6441
- const baseDir = dirname12(ownPaths.dir);
6916
+ const baseDir = dirname14(ownPaths.dir);
6442
6917
  const platform = deps.platform ?? process.platform;
6443
6918
  const isAlive = deps.isAlive ?? isProcessAlive2;
6444
6919
  const attest = deps.attest ?? ((pid) => attestDaemonCliProcess(pid, platform));
@@ -6457,7 +6932,7 @@ async function reapStaleDaemonVersions(ownPaths, deps = {}) {
6457
6932
  const version = parseVersionEntry(entry.name);
6458
6933
  if (version === null || !entry.isDirectory())
6459
6934
  continue;
6460
- const versionDir = join8(baseDir, entry.name);
6935
+ const versionDir = join9(baseDir, entry.name);
6461
6936
  const siblingPaths = daemonPaths({ [OMO_LSP_DAEMON_DIR]: baseDir }, { cliPath: ownPaths.cliPath, version });
6462
6937
  results.push(await reapOneVersion({
6463
6938
  version,
@@ -6481,7 +6956,7 @@ async function reapOneVersion(context) {
6481
6956
  const { version, versionDir } = context;
6482
6957
  const owner = context.readOwner(context.siblingPaths);
6483
6958
  if (!owner) {
6484
- const lockPid = readLockPid(join8(versionDir, "daemon.lock"));
6959
+ const lockPid = readLockPid(join9(versionDir, "daemon.lock"));
6485
6960
  if (lockPid !== null && context.isAlive(lockPid)) {
6486
6961
  context.log(`reap: sparing v${version}: owner metadata missing but daemon.lock is held by live pid ${lockPid}`);
6487
6962
  return { version, status: "spared", reason: `owner metadata missing but lock held by live pid ${lockPid}` };
@@ -6547,7 +7022,7 @@ function splitCmdline(buffer) {
6547
7022
  function isNodeCliDaemonArgv(argv) {
6548
7023
  if (argv.length < 2 || !argv.includes("daemon"))
6549
7024
  return false;
6550
- const executable = basename4(argv[0] ?? "");
7025
+ const executable = basename5(argv[0] ?? "");
6551
7026
  if (!/^node(?:\.exe)?$/i.test(executable))
6552
7027
  return false;
6553
7028
  return argv.some((value) => value === "cli.js" || value.endsWith("/cli.js") || value.endsWith("\\cli.js"));
@@ -6559,13 +7034,13 @@ function defaultReadProcFile(path2) {
6559
7034
  return readFile(path2);
6560
7035
  }
6561
7036
  function defaultExecuteForStdout(file, args) {
6562
- return new Promise((resolve9) => {
6563
- execFile(file, [...args], { encoding: "utf8", maxBuffer: 1024 * 1024, timeout: 1000 }, (error, stdout) => {
7037
+ return new Promise((resolve10) => {
7038
+ execFile(file, [...args], { encoding: "utf8", maxBuffer: 1024 * 1024, timeout: 1000, windowsHide: true }, (error, stdout) => {
6564
7039
  if (error !== null) {
6565
- resolve9(null);
7040
+ resolve10(null);
6566
7041
  return;
6567
7042
  }
6568
- resolve9(stdout);
7043
+ resolve10(stdout);
6569
7044
  });
6570
7045
  });
6571
7046
  }
@@ -6584,7 +7059,7 @@ async function defaultWaitForExit(pid, timeoutMs) {
6584
7059
  return true;
6585
7060
  if (Date.now() >= deadline)
6586
7061
  return false;
6587
- await new Promise((resolve9) => setTimeout(resolve9, 100));
7062
+ await new Promise((resolve10) => setTimeout(resolve10, 100));
6588
7063
  }
6589
7064
  }
6590
7065
  function defaultLog(message) {
@@ -6691,17 +7166,17 @@ async function assertSelfProbe(paths, token, owner) {
6691
7166
  throw new DaemonStartupDeferredError("self_probe_failed");
6692
7167
  }
6693
7168
  function listen(server2, socketPath) {
6694
- return new Promise((resolve9, reject) => {
7169
+ return new Promise((resolve10, reject) => {
6695
7170
  const onError = (error) => reject(error);
6696
7171
  server2.once("error", onError);
6697
7172
  server2.listen(socketPath, () => {
6698
7173
  server2.removeListener("error", onError);
6699
- resolve9();
7174
+ resolve10();
6700
7175
  });
6701
7176
  });
6702
7177
  }
6703
7178
  function closeServer(server2) {
6704
- return new Promise((resolve9) => server2.close(() => resolve9()));
7179
+ return new Promise((resolve10) => server2.close(() => resolve10()));
6705
7180
  }
6706
7181
  function installSignalHandlers(close) {
6707
7182
  const handler = () => {