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

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 (538) 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 +66932 -64746
  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 +66795 -64586
  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 +793 -323
  26. package/packages/lsp-daemon/dist/client.d.ts +10 -0
  27. package/packages/lsp-daemon/dist/client.js +753 -280
  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 +757 -289
  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 +712 -244
  36. package/packages/lsp-tools-mcp/dist/lsp/manager.js +248 -119
  37. package/packages/lsp-tools-mcp/dist/mcp.js +714 -246
  38. package/packages/lsp-tools-mcp/dist/request-context.js +12 -13
  39. package/packages/lsp-tools-mcp/dist/tools.js +718 -254
  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 +741 -294
  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 +3 -2
  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 +36 -13
  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/coding-agent-sessions/AGENTS.md +62 -0
  296. package/packages/omo-codex/plugin/skills/coding-agent-sessions/SKILL.md +3 -2
  297. package/packages/omo-codex/plugin/skills/coding-agent-sessions/references/all-platforms.md +1 -1
  298. package/packages/omo-codex/plugin/skills/coding-agent-sessions/references/senpi.md +4 -4
  299. package/packages/omo-codex/plugin/skills/coding-agent-sessions/scripts/agent_sessions/pi_family.py +1 -1
  300. package/packages/omo-codex/plugin/skills/data-scientist/SKILL.md +99 -239
  301. package/packages/omo-codex/plugin/skills/data-scientist/references/execution-surfaces.md +91 -0
  302. package/packages/omo-codex/plugin/skills/data-scientist/references/placement.md +74 -0
  303. package/packages/omo-codex/plugin/skills/data-scientist/references/polars-lane.md +95 -0
  304. package/packages/omo-codex/plugin/skills/data-scientist/references/uv-setup.md +1 -1
  305. package/packages/omo-codex/plugin/skills/data-scientist/references/visualization.md +64 -0
  306. package/packages/omo-codex/plugin/skills/data-scientist/scripts/ensure-js-deps.sh +28 -0
  307. package/packages/omo-codex/plugin/skills/data-scientist/scripts/ensure-py-deps.sh +37 -0
  308. package/packages/omo-codex/plugin/skills/debugging/SKILL.md +2 -0
  309. package/packages/omo-codex/plugin/skills/debugging/references/methodology/00-setup.md +12 -0
  310. package/packages/omo-codex/plugin/skills/debugging/references/methodology/02-investigate.md +21 -0
  311. package/packages/omo-codex/plugin/skills/debugging/references/runtimes/go.md +15 -1
  312. package/packages/omo-codex/plugin/skills/debugging/references/runtimes/native-binary.md +38 -0
  313. package/packages/omo-codex/plugin/skills/debugging/references/runtimes/node.md +25 -0
  314. package/packages/omo-codex/plugin/skills/debugging/references/runtimes/python.md +13 -0
  315. package/packages/omo-codex/plugin/skills/debugging/references/runtimes/rust.md +41 -0
  316. package/packages/omo-codex/plugin/skills/debugging/references/scripts/dap.mjs +267 -0
  317. package/packages/omo-codex/plugin/skills/debugging/references/scripts/fixture-adapter.mjs +59 -0
  318. package/packages/omo-codex/plugin/skills/debugging/references/tools/dap.md +103 -0
  319. package/packages/omo-codex/plugin/skills/debugging/references/tools/frida.md +193 -0
  320. package/packages/omo-codex/plugin/skills/frontend/SKILL.md +11 -7
  321. package/packages/omo-codex/plugin/skills/frontend/references/design/_INDEX.md +1 -0
  322. package/packages/omo-codex/plugin/skills/frontend/references/design/print-paged-media.md +76 -0
  323. package/packages/omo-codex/plugin/skills/frontend/references/design/stylegallery.md +80 -0
  324. package/packages/omo-codex/plugin/skills/frontend/references/designpowers/README.md +1 -1
  325. package/packages/omo-codex/plugin/skills/frontend/references/designpowers/lane-a-direction.md +1 -1
  326. package/packages/omo-codex/plugin/skills/frontend/references/designpowers/lane-b-execution.md +11 -11
  327. package/packages/omo-codex/plugin/skills/frontend/references/designpowers/lane-d-memory.md +3 -3
  328. package/packages/omo-codex/plugin/skills/frontend/references/designpowers/orchestration.md +1 -1
  329. package/packages/omo-codex/plugin/skills/frontend/references/designpowers/routing.md +5 -5
  330. package/packages/omo-codex/plugin/skills/init-deep/SKILL.md +13 -13
  331. package/packages/omo-codex/plugin/skills/lcx-doctor/SKILL.md +1 -1
  332. package/packages/omo-codex/plugin/skills/review-work/SKILL.md +4 -4
  333. package/packages/omo-codex/plugin/skills/ultimate-browsing/ATTRIBUTION.md +37 -10
  334. package/packages/omo-codex/plugin/skills/ultimate-browsing/SKILL.md +2 -0
  335. package/packages/omo-codex/plugin/skills/ultimate-browsing/engine/AGENTS.md +110 -0
  336. package/packages/omo-codex/plugin/skills/ultimate-browsing/engine/templates/package.json +1 -1
  337. package/packages/omo-codex/plugin/skills/ultimate-browsing/references/chrome-stealth.md +13 -11
  338. package/packages/omo-codex/plugin/skills/ultimate-browsing/references/insane-search/README.md +9 -2
  339. package/packages/omo-codex/plugin/skills/ultrawork/SKILL.md +15 -3
  340. package/packages/omo-codex/plugin/skills/{start-work → ulw-execute}/SKILL.md +19 -26
  341. package/packages/omo-codex/plugin/skills/ulw-execute/agents/openai.yaml +2 -0
  342. package/packages/omo-codex/plugin/skills/ulw-loop/SKILL.md +3 -2
  343. package/packages/omo-codex/plugin/skills/ulw-loop/references/define-goal.md +108 -0
  344. package/packages/omo-codex/plugin/skills/ulw-loop/references/full-workflow.md +22 -1
  345. package/packages/omo-codex/plugin/skills/ulw-plan/SKILL.md +6 -7
  346. package/packages/omo-codex/plugin/skills/ulw-plan/references/full-workflow.md +31 -7
  347. package/packages/omo-codex/plugin/skills/ulw-plan/references/intent-clear.md +2 -1
  348. package/packages/omo-codex/plugin/skills/ulw-plan/references/intent-unclear.md +5 -5
  349. package/packages/omo-codex/plugin/skills/ulw-research/SKILL.md +4 -2
  350. package/packages/omo-codex/plugin/skills/visual-qa/AGENTS.md +58 -0
  351. package/packages/omo-codex/plugin/skills/visual-qa/SKILL.md +3 -2
  352. package/packages/omo-codex/plugin/test/AGENTS.md +47 -0
  353. package/packages/omo-codex/plugin/test/aggregate-agents.test.mjs +19 -173
  354. package/packages/omo-codex/plugin/test/aggregate-hooks.test.mjs +9 -48
  355. package/packages/omo-codex/plugin/test/aggregate-manifest.test.mjs +2 -3
  356. package/packages/omo-codex/plugin/test/aggregate-mcp.test.mjs +2 -7
  357. package/packages/omo-codex/plugin/test/aggregate-model-catalog.test.mjs +1 -1
  358. package/packages/omo-codex/plugin/test/aggregate-plugin-fixture.mjs +175 -13
  359. package/packages/omo-codex/plugin/test/aggregate.test.mjs +78 -2
  360. package/packages/omo-codex/plugin/test/auto-update-release-notes.test.mjs +19 -33
  361. package/packages/omo-codex/plugin/test/auto-update.test.mjs +2 -27
  362. package/packages/omo-codex/plugin/test/bootstrap-setup.test.mjs +0 -31
  363. package/packages/omo-codex/plugin/test/canonical-ultrawork-directive.test.mjs +53 -0
  364. package/packages/omo-codex/plugin/test/component-bin-names.test.mjs +2 -2
  365. package/packages/omo-codex/plugin/test/component-bundled-cli.test.mjs +1 -51
  366. package/packages/omo-codex/plugin/test/component-hook-contract-cases.mjs +2 -2
  367. package/packages/omo-codex/plugin/test/hook-status-message.test.mjs +4 -5
  368. package/packages/omo-codex/plugin/test/lcx-contribute-bug-fix-template.test.mjs +21 -27
  369. package/packages/omo-codex/plugin/test/mcp-research-servers.test.mjs +1 -3
  370. package/packages/omo-codex/plugin/test/migrate-codex-config.test.mjs +8 -8
  371. package/packages/omo-codex/plugin/test/scaffold-plan.test.mjs +0 -36
  372. package/packages/omo-codex/plugin/test/sync-skills-codex-compatibility.test.mjs +101 -0
  373. package/packages/omo-codex/plugin/test/sync-skills-test-support.mjs +23 -13
  374. package/packages/omo-codex/plugin/test/sync-skills.test.mjs +14 -119
  375. package/packages/omo-codex/plugin/test/teammode-archive-ambiguity.test.mjs +0 -40
  376. package/packages/omo-codex/plugin/test/teammode-communication.test.mjs +6 -62
  377. package/packages/omo-codex/plugin/test/teammode-thread-links.test.mjs +3 -36
  378. package/packages/omo-codex/plugin/test/teammode-transport.test.mjs +0 -44
  379. package/packages/omo-codex/plugin/test/teammode-worktree.test.mjs +2 -6
  380. package/packages/omo-codex/plugin/test/ultrawork-skill-pointer.test.mjs +5 -5
  381. package/packages/omo-codex/plugin/test/ulw-plan-review-state-contract.test.mjs +0 -3
  382. package/packages/omo-codex/scripts/install-dist/install-local.mjs +2817 -913
  383. package/packages/{omo-codex/plugin/components/ultrawork/skills/ultrawork/SKILL.md → prompts-core/prompts/ultrawork/codex.md} +15 -10
  384. package/packages/shared-skills/skills/ast-grep/AGENTS.md +51 -0
  385. package/packages/shared-skills/skills/coding-agent-sessions/AGENTS.md +62 -0
  386. package/packages/shared-skills/skills/coding-agent-sessions/SKILL.md +3 -2
  387. package/packages/shared-skills/skills/coding-agent-sessions/references/all-platforms.md +1 -1
  388. package/packages/shared-skills/skills/coding-agent-sessions/references/senpi.md +4 -4
  389. package/packages/shared-skills/skills/coding-agent-sessions/scripts/agent_sessions/pi_family.py +1 -1
  390. package/packages/shared-skills/skills/data-scientist/SKILL.md +99 -239
  391. package/packages/shared-skills/skills/data-scientist/references/execution-surfaces.md +91 -0
  392. package/packages/shared-skills/skills/data-scientist/references/placement.md +74 -0
  393. package/packages/shared-skills/skills/data-scientist/references/polars-lane.md +95 -0
  394. package/packages/shared-skills/skills/data-scientist/references/uv-setup.md +1 -1
  395. package/packages/shared-skills/skills/data-scientist/references/visualization.md +64 -0
  396. package/packages/shared-skills/skills/data-scientist/scripts/ensure-js-deps.sh +28 -0
  397. package/packages/shared-skills/skills/data-scientist/scripts/ensure-py-deps.sh +37 -0
  398. package/packages/shared-skills/skills/debugging/SKILL.md +2 -0
  399. package/packages/shared-skills/skills/debugging/references/methodology/00-setup.md +12 -0
  400. package/packages/shared-skills/skills/debugging/references/methodology/02-investigate.md +21 -0
  401. package/packages/shared-skills/skills/debugging/references/runtimes/go.md +15 -1
  402. package/packages/shared-skills/skills/debugging/references/runtimes/native-binary.md +38 -0
  403. package/packages/shared-skills/skills/debugging/references/runtimes/node.md +25 -0
  404. package/packages/shared-skills/skills/debugging/references/runtimes/python.md +13 -0
  405. package/packages/shared-skills/skills/debugging/references/runtimes/rust.md +41 -0
  406. package/packages/shared-skills/skills/debugging/references/scripts/dap.mjs +267 -0
  407. package/packages/shared-skills/skills/debugging/references/scripts/dap.test.ts +86 -0
  408. package/packages/shared-skills/skills/debugging/references/scripts/fixture-adapter.mjs +59 -0
  409. package/packages/shared-skills/skills/debugging/references/tools/dap.md +103 -0
  410. package/packages/shared-skills/skills/debugging/references/tools/frida.md +193 -0
  411. package/packages/shared-skills/skills/frontend/SKILL.md +11 -7
  412. package/packages/shared-skills/skills/frontend/references/design/_INDEX.md +1 -0
  413. package/packages/shared-skills/skills/frontend/references/design/print-paged-media.md +76 -0
  414. package/packages/shared-skills/skills/frontend/references/design/stylegallery.md +80 -0
  415. package/packages/shared-skills/skills/frontend/references/designpowers/README.md +1 -1
  416. package/packages/shared-skills/skills/frontend/references/designpowers/lane-a-direction.md +1 -1
  417. package/packages/shared-skills/skills/frontend/references/designpowers/lane-b-execution.md +11 -11
  418. package/packages/shared-skills/skills/frontend/references/designpowers/lane-d-memory.md +3 -3
  419. package/packages/shared-skills/skills/frontend/references/designpowers/orchestration.md +1 -1
  420. package/packages/shared-skills/skills/frontend/references/designpowers/routing.md +5 -5
  421. package/packages/shared-skills/skills/init-deep/SKILL.md +13 -13
  422. package/packages/shared-skills/skills/review-work/SKILL.md +3 -3
  423. package/packages/shared-skills/skills/ultimate-browsing/ATTRIBUTION.md +37 -10
  424. package/packages/shared-skills/skills/ultimate-browsing/SKILL.md +2 -0
  425. package/packages/shared-skills/skills/ultimate-browsing/engine/AGENTS.md +110 -0
  426. package/packages/shared-skills/skills/ultimate-browsing/engine/templates/package.json +1 -1
  427. package/packages/shared-skills/skills/ultimate-browsing/references/chrome-stealth.md +13 -11
  428. package/packages/shared-skills/skills/ultimate-browsing/references/insane-search/README.md +9 -2
  429. package/packages/shared-skills/skills/{start-work → ulw-execute}/SKILL.md +17 -16
  430. package/packages/shared-skills/skills/ulw-plan/SKILL.md +6 -7
  431. package/packages/shared-skills/skills/ulw-plan/references/full-workflow.md +31 -7
  432. package/packages/shared-skills/skills/ulw-plan/references/intent-clear.md +2 -1
  433. package/packages/shared-skills/skills/ulw-plan/references/intent-unclear.md +5 -5
  434. package/packages/shared-skills/skills/ulw-research/SKILL.md +4 -2
  435. package/packages/shared-skills/skills/visual-qa/AGENTS.md +58 -0
  436. package/packages/shared-skills/skills/visual-qa/SKILL.md +3 -2
  437. package/script/qa/web-terminal-visual-qa.mjs +2 -0
  438. package/script/qa/xterm-live-terminal.mjs +18 -2
  439. package/packages/lsp-tools-mcp/dist/lsp/cleanup-errors.d.ts +0 -1
  440. package/packages/lsp-tools-mcp/dist/lsp/constants.d.ts +0 -1
  441. package/packages/lsp-tools-mcp/dist/lsp/language-mappings.d.ts +0 -1
  442. package/packages/lsp-tools-mcp/dist/lsp/process-signal-cleanup.d.ts +0 -1
  443. package/packages/lsp-tools-mcp/dist/missing-dependency-result.d.ts +0 -1
  444. package/packages/omo-codex/plugin/components/codegraph/AGENTS.md +0 -58
  445. package/packages/omo-codex/plugin/components/codegraph/NODE-RUNTIME-LICENSES.md +0 -2951
  446. package/packages/omo-codex/plugin/components/codegraph/NOTICE +0 -16
  447. package/packages/omo-codex/plugin/components/codegraph/dist/cli.js +0 -12136
  448. package/packages/omo-codex/plugin/components/codegraph/dist/serve.js +0 -9734
  449. package/packages/omo-codex/plugin/components/codegraph/package.json +0 -33
  450. package/packages/omo-codex/plugin/components/codegraph/src/cache-gc.ts +0 -29
  451. package/packages/omo-codex/plugin/components/codegraph/src/cli.ts +0 -79
  452. package/packages/omo-codex/plugin/components/codegraph/src/hook-input.ts +0 -33
  453. package/packages/omo-codex/plugin/components/codegraph/src/hook-sweep.ts +0 -25
  454. package/packages/omo-codex/plugin/components/codegraph/src/hook-types.ts +0 -131
  455. package/packages/omo-codex/plugin/components/codegraph/src/hook.ts +0 -258
  456. package/packages/omo-codex/plugin/components/codegraph/src/mcp-bridge.ts +0 -309
  457. package/packages/omo-codex/plugin/components/codegraph/src/mcp-unavailable.ts +0 -80
  458. package/packages/omo-codex/plugin/components/codegraph/src/post-tool-use-hook.ts +0 -34
  459. package/packages/omo-codex/plugin/components/codegraph/src/serve-invocation.ts +0 -29
  460. package/packages/omo-codex/plugin/components/codegraph/src/serve.ts +0 -263
  461. package/packages/omo-codex/plugin/components/codegraph/src/session-start-command.ts +0 -106
  462. package/packages/omo-codex/plugin/components/codegraph/src/session-start-cooldown.ts +0 -145
  463. package/packages/omo-codex/plugin/components/codegraph/src/session-start-hook-runtime.ts +0 -21
  464. package/packages/omo-codex/plugin/components/codegraph/src/session-start-lock.ts +0 -139
  465. package/packages/omo-codex/plugin/components/codegraph/src/session-start-outcome.ts +0 -15
  466. package/packages/omo-codex/plugin/components/codegraph/src/session-start-paths.ts +0 -32
  467. package/packages/omo-codex/plugin/components/codegraph/src/session-start-project.ts +0 -109
  468. package/packages/omo-codex/plugin/components/codegraph/src/session-start-worker-result.ts +0 -148
  469. package/packages/omo-codex/plugin/components/codegraph/src/session-start-worker.ts +0 -175
  470. package/packages/omo-codex/plugin/components/codegraph/src/sweep-cli.ts +0 -81
  471. package/packages/omo-codex/plugin/components/codegraph/test/cache-gc.test.ts +0 -34
  472. package/packages/omo-codex/plugin/components/codegraph/test/hook-exclusion.test.ts +0 -112
  473. package/packages/omo-codex/plugin/components/codegraph/test/hook-registration.test.ts +0 -26
  474. package/packages/omo-codex/plugin/components/codegraph/test/hook-session-start-guard.test.ts +0 -160
  475. package/packages/omo-codex/plugin/components/codegraph/test/hook-store-upgrade.test.ts +0 -50
  476. package/packages/omo-codex/plugin/components/codegraph/test/hook-sweep.test.ts +0 -29
  477. package/packages/omo-codex/plugin/components/codegraph/test/hook.test.ts +0 -320
  478. package/packages/omo-codex/plugin/components/codegraph/test/mcp-bridge-fixtures.ts +0 -172
  479. package/packages/omo-codex/plugin/components/codegraph/test/package-runtime.test.ts +0 -91
  480. package/packages/omo-codex/plugin/components/codegraph/test/provisioned-node-guard.test.ts +0 -100
  481. package/packages/omo-codex/plugin/components/codegraph/test/serve-built-wrapper.test.ts +0 -76
  482. package/packages/omo-codex/plugin/components/codegraph/test/serve-mcp-bridge-lifecycle.test.ts +0 -133
  483. package/packages/omo-codex/plugin/components/codegraph/test/serve-mcp-bridge.test.ts +0 -245
  484. package/packages/omo-codex/plugin/components/codegraph/test/serve-mcp-facade.test.ts +0 -69
  485. package/packages/omo-codex/plugin/components/codegraph/test/serve-node-support.test.ts +0 -43
  486. package/packages/omo-codex/plugin/components/codegraph/test/serve-provision.test.ts +0 -147
  487. package/packages/omo-codex/plugin/components/codegraph/test/serve-unavailable.test.ts +0 -175
  488. package/packages/omo-codex/plugin/components/codegraph/test/serve.test.ts +0 -385
  489. package/packages/omo-codex/plugin/components/codegraph/test/session-start-node-support.test.ts +0 -206
  490. package/packages/omo-codex/plugin/components/codegraph/test/session-start-project.test.ts +0 -58
  491. package/packages/omo-codex/plugin/components/codegraph/test/session-start-state.test.ts +0 -104
  492. package/packages/omo-codex/plugin/components/codegraph/test/session-start-trust-boundary.test.ts +0 -65
  493. package/packages/omo-codex/plugin/components/codegraph/test/session-start-worker-availability.test.ts +0 -106
  494. package/packages/omo-codex/plugin/components/codegraph/test/session-start-worker-cooldown.test.ts +0 -116
  495. package/packages/omo-codex/plugin/components/codegraph/test/session-start-worker-flow.test.ts +0 -258
  496. package/packages/omo-codex/plugin/components/codegraph/test/sweep-cli.test.ts +0 -56
  497. package/packages/omo-codex/plugin/components/codegraph/tsconfig.build.json +0 -13
  498. package/packages/omo-codex/plugin/components/codegraph/tsconfig.json +0 -25
  499. package/packages/omo-codex/plugin/components/start-work-continuation/LICENSE +0 -21
  500. package/packages/omo-codex/plugin/components/start-work-continuation/hooks/hooks.json +0 -28
  501. package/packages/omo-codex/plugin/components/ultrawork/directive.md +0 -471
  502. package/packages/omo-codex/plugin/hooks/post-tool-use-checking-codegraph-init-guidance.json +0 -18
  503. package/packages/omo-codex/plugin/hooks/session-start-checking-codegraph-bootstrap.json +0 -17
  504. package/packages/omo-codex/plugin/hooks/stop-checking-start-work-continuation.json +0 -17
  505. package/packages/omo-codex/plugin/hooks/subagent-stop-checking-start-work-continuation.json +0 -17
  506. package/packages/omo-codex/plugin/scripts/migrate-omo-sot/editor.mjs +0 -125
  507. package/packages/omo-codex/plugin/scripts/migrate-omo-sot/jsonc.mjs +0 -43
  508. package/packages/omo-codex/plugin/scripts/migrate-omo-sot/scaffold.mjs +0 -29
  509. package/packages/omo-codex/plugin/scripts/migrate-omo-sot.mjs +0 -121
  510. package/packages/omo-codex/plugin/skills/data-scientist/references/common-scenarios.md +0 -176
  511. package/packages/omo-codex/plugin/skills/data-scientist/references/execution-templates.md +0 -197
  512. package/packages/omo-codex/plugin/skills/data-scientist/references/integration-patterns.md +0 -153
  513. package/packages/omo-codex/plugin/skills/data-scientist/references/performance-benchmarks.md +0 -37
  514. package/packages/omo-codex/plugin/skills/start-work/agents/openai.yaml +0 -2
  515. package/packages/omo-codex/plugin/test/aggregate-skills.test.mjs +0 -92
  516. package/packages/omo-codex/plugin/test/component-codegraph-mcp-smoke.test.mjs +0 -76
  517. package/packages/omo-codex/plugin/test/migrate-omo-sot.test.mjs +0 -179
  518. package/packages/omo-codex/plugin/test/sync-skills-orchestration.test.mjs +0 -314
  519. package/packages/omo-codex/plugin/test/ulw-plan-scope-contract.test.mjs +0 -24
  520. package/packages/shared-skills/skills/data-scientist/references/common-scenarios.md +0 -176
  521. package/packages/shared-skills/skills/data-scientist/references/execution-templates.md +0 -197
  522. package/packages/shared-skills/skills/data-scientist/references/integration-patterns.md +0 -153
  523. package/packages/shared-skills/skills/data-scientist/references/performance-benchmarks.md +0 -37
  524. /package/packages/omo-codex/plugin/components/{start-work-continuation → ulw-execute-continuation}/.gitattributes +0 -0
  525. /package/packages/omo-codex/plugin/components/{start-work-continuation → ulw-execute-continuation}/CHANGELOG.md +0 -0
  526. /package/packages/omo-codex/plugin/components/{codegraph → ulw-execute-continuation}/LICENSE +0 -0
  527. /package/packages/omo-codex/plugin/components/{start-work-continuation → ulw-execute-continuation}/src/plan-checklist.ts +0 -0
  528. /package/packages/omo-codex/plugin/components/{start-work-continuation → ulw-execute-continuation}/src/types.ts +0 -0
  529. /package/packages/omo-codex/plugin/components/{start-work-continuation → ulw-execute-continuation}/test/fixtures/boulder-completed.json +0 -0
  530. /package/packages/omo-codex/plugin/components/{start-work-continuation → ulw-execute-continuation}/test/fixtures/boulder-mixed-platforms.json +0 -0
  531. /package/packages/omo-codex/plugin/components/{start-work-continuation → ulw-execute-continuation}/test/fixtures/boulder-single-codex-work.json +0 -0
  532. /package/packages/omo-codex/plugin/components/{start-work-continuation → ulw-execute-continuation}/test/fixtures/plan-all-done.md +0 -0
  533. /package/packages/omo-codex/plugin/components/{start-work-continuation → ulw-execute-continuation}/test/fixtures/plan-scaffold.md +0 -0
  534. /package/packages/omo-codex/plugin/components/{start-work-continuation → ulw-execute-continuation}/test/fixtures/plan-with-nested-checkboxes.md +0 -0
  535. /package/packages/omo-codex/plugin/components/{start-work-continuation → ulw-execute-continuation}/test/fixtures/plan-with-unchecked.md +0 -0
  536. /package/packages/omo-codex/plugin/components/{start-work-continuation → ulw-execute-continuation}/tsconfig.build.json +0 -0
  537. /package/packages/omo-codex/plugin/components/{start-work-continuation → ulw-execute-continuation}/tsconfig.json +0 -0
  538. /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)
@@ -741,19 +772,6 @@ class JsonRpcConnection {
741
772
  this.notificationHandlers.clear();
742
773
  this.requestHandlers.clear();
743
774
  }
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
775
  drainInputBuffer() {
758
776
  while (true) {
759
777
  const headerEnd = this.inputBuffer.indexOf(HEADER_SEPARATOR2);
@@ -1101,33 +1119,29 @@ function isPosition(value) {
1101
1119
 
1102
1120
  // ../lsp-core/src/lsp/transport.ts
1103
1121
  class LspClientNotStartedError extends Error {
1104
- serverId;
1105
- root;
1106
- name = "LspClientNotStartedError";
1107
1122
  constructor(serverId, root) {
1108
1123
  super("LSP client not started");
1109
1124
  this.serverId = serverId;
1110
1125
  this.root = root;
1126
+ this.name = "LspClientNotStartedError";
1111
1127
  }
1112
1128
  }
1113
1129
 
1114
1130
  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
1131
  constructor(root, server2, timeouts = {}) {
1127
1132
  this.root = root;
1128
1133
  this.server = server2;
1134
+ this.proc = null;
1135
+ this.connection = null;
1136
+ this.stderrBuffer = [];
1137
+ this.processExited = false;
1138
+ this.diagnosticsStore = new Map;
1139
+ this.workspaceApplyEditHandler = null;
1140
+ this.diagnosticPullSupported = false;
1141
+ this.documentFormattingSupported = false;
1129
1142
  this.requestTimeoutMs = timeouts.requestTimeoutMs ?? REQUEST_TIMEOUT_MS;
1130
1143
  this.initializeTimeoutMs = timeouts.initializeTimeoutMs ?? INIT_TIMEOUT_MS;
1144
+ this.timerProvider = timeouts.timerProvider ?? realTimerProvider;
1131
1145
  }
1132
1146
  pid() {
1133
1147
  return this.proc?.pid;
@@ -1147,6 +1161,12 @@ class LspClientTransport {
1147
1161
  isDiagnosticPullSupported() {
1148
1162
  return this.diagnosticPullSupported;
1149
1163
  }
1164
+ setDocumentFormattingSupported(supported) {
1165
+ this.documentFormattingSupported = supported;
1166
+ }
1167
+ isDocumentFormattingSupported() {
1168
+ return this.documentFormattingSupported;
1169
+ }
1150
1170
  handlePublishDiagnostics(params) {
1151
1171
  this.diagnosticsStore.set(params.uri, [...params.diagnostics]);
1152
1172
  }
@@ -1222,7 +1242,7 @@ class LspClientTransport {
1222
1242
  const options = args[1];
1223
1243
  const timeoutMs = options?.timeoutMs ?? this.requestTimeoutMs;
1224
1244
  const timeoutController = new AbortController;
1225
- const timeoutHandle = setTimeout(() => {
1245
+ const timeoutHandle = this.timerProvider.setTimeout(() => {
1226
1246
  const stderrTail = this.stderrBuffer.slice(-5).join(`
1227
1247
  `);
1228
1248
  timeoutController.abort(new LspRequestTimeoutError(method, stderrTail || undefined));
@@ -1241,7 +1261,7 @@ class LspClientTransport {
1241
1261
  }
1242
1262
  throw error;
1243
1263
  } finally {
1244
- clearTimeout(timeoutHandle);
1264
+ this.timerProvider.clearTimeout(timeoutHandle);
1245
1265
  combinedSignal.dispose();
1246
1266
  }
1247
1267
  }
@@ -1360,6 +1380,14 @@ function supportsDiagnosticPull(capabilities) {
1360
1380
  return false;
1361
1381
  return Object.hasOwn(capabilities, "diagnosticProvider");
1362
1382
  }
1383
+ function supportsDocumentFormatting(capabilities) {
1384
+ if (capabilities === undefined)
1385
+ return false;
1386
+ const provider = capabilities.documentFormattingProvider;
1387
+ if (provider === undefined || provider === null || provider === false)
1388
+ return false;
1389
+ return provider === true || typeof provider === "object";
1390
+ }
1363
1391
 
1364
1392
  class LspClientConnection extends LspClientTransport {
1365
1393
  async initialize() {
@@ -1376,6 +1404,7 @@ class LspClientConnection extends LspClientTransport {
1376
1404
  references: {},
1377
1405
  documentSymbol: { hierarchicalDocumentSymbolSupport: true },
1378
1406
  publishDiagnostics: {},
1407
+ formatting: { dynamicRegistration: false },
1379
1408
  rename: {
1380
1409
  prepareSupport: true,
1381
1410
  prepareSupportDefaultBehavior: 1
@@ -1417,6 +1446,7 @@ class LspClientConnection extends LspClientTransport {
1417
1446
  initializationOptions: this.server.initialization
1418
1447
  }, { timeoutMs: this.initializeTimeoutMs });
1419
1448
  this.setDiagnosticPullSupported(supportsDiagnosticPull(result?.capabilities));
1449
+ this.setDocumentFormattingSupported(supportsDocumentFormatting(result?.capabilities));
1420
1450
  await this.sendNotification("initialized", {});
1421
1451
  await this.sendNotification("workspace/didChangeConfiguration", {
1422
1452
  settings: { json: { validate: { enable: true } } }
@@ -1612,6 +1642,17 @@ function canonicalPath(filePath) {
1612
1642
  return absolute;
1613
1643
  }
1614
1644
  }
1645
+ function normalizeDocumentUri(uri) {
1646
+ let decoded = uri;
1647
+ try {
1648
+ decoded = decodeURIComponent(uri);
1649
+ } catch {
1650
+ decoded = uri;
1651
+ }
1652
+ if (process.platform !== "win32")
1653
+ return decoded;
1654
+ return decoded.replace(/^(file:\/\/\/)([a-z]):/, (_match, prefix, drive) => `${prefix}${drive.toUpperCase()}:`);
1655
+ }
1615
1656
  function isSameOrDescendant(candidate, parent) {
1616
1657
  const suffix = relative2(parent, candidate);
1617
1658
  return suffix === "" || !suffix.startsWith("..") && suffix !== "..";
@@ -1622,17 +1663,18 @@ function movedPath(candidate, oldPath, newPath) {
1622
1663
  }
1623
1664
 
1624
1665
  class WorkspaceDocumentState {
1625
- sendNotification;
1626
- clearDiagnostics;
1627
- openDocuments = new Map;
1628
- openByUri = new Map;
1629
- openPromises = new Map;
1630
- now;
1631
- versionlessPublishQuiescenceMs;
1632
1666
  constructor(sendNotification, clearDiagnostics, options = {}) {
1633
1667
  this.sendNotification = sendNotification;
1634
1668
  this.clearDiagnostics = clearDiagnostics;
1635
- this.now = options.now ?? (() => Date.now());
1669
+ this.openDocuments = new Map;
1670
+ this.openByUri = new Map;
1671
+ this.openPromises = new Map;
1672
+ this.timerProvider = options.timerProvider ?? {
1673
+ now: options.now ?? (() => Date.now()),
1674
+ setTimeout: (callback, delayMs) => setTimeout(callback, delayMs),
1675
+ clearTimeout: (handle) => clearTimeout(handle)
1676
+ };
1677
+ this.now = () => this.timerProvider.now();
1636
1678
  this.versionlessPublishQuiescenceMs = options.versionlessPublishQuiescenceMs ?? DEFAULT_VERSIONLESS_PUBLISH_QUIESCENCE_MS;
1637
1679
  }
1638
1680
  async openFile(filePath) {
@@ -1654,7 +1696,7 @@ class WorkspaceDocumentState {
1654
1696
  return this.openDocuments.get(canonicalPath(filePath))?.version;
1655
1697
  }
1656
1698
  getStoredDiagnostics(uri) {
1657
- const state = this.openByUri.get(uri);
1699
+ const state = this.openByUri.get(normalizeDocumentUri(uri));
1658
1700
  if (!state)
1659
1701
  return [];
1660
1702
  return state.lastPublish?.diagnostics ?? state.pullCache?.diagnostics ?? [];
@@ -1676,13 +1718,13 @@ class WorkspaceDocumentState {
1676
1718
  return state !== undefined && state.uri === snapshot.uri && state.version === snapshot.version && state.generation === snapshot.documentGeneration;
1677
1719
  }
1678
1720
  getPullCache(snapshot) {
1679
- const state = this.openByUri.get(snapshot.uri);
1721
+ const state = this.openByUri.get(normalizeDocumentUri(snapshot.uri));
1680
1722
  if (!state?.pullCache || state.pullCache.documentVersion !== snapshot.version)
1681
1723
  return null;
1682
1724
  return state.pullCache;
1683
1725
  }
1684
1726
  recordPullDiagnostics(snapshot, report) {
1685
- const state = this.openByUri.get(snapshot.uri);
1727
+ const state = this.openByUri.get(normalizeDocumentUri(snapshot.uri));
1686
1728
  if (!state)
1687
1729
  return;
1688
1730
  state.pullCache = {
@@ -1692,7 +1734,7 @@ class WorkspaceDocumentState {
1692
1734
  };
1693
1735
  }
1694
1736
  recordPublishedDiagnostics(params) {
1695
- const state = this.openByUri.get(params.uri);
1737
+ const state = this.openByUri.get(normalizeDocumentUri(params.uri));
1696
1738
  if (!state)
1697
1739
  return;
1698
1740
  state.publishGeneration += 1;
@@ -1706,7 +1748,7 @@ class WorkspaceDocumentState {
1706
1748
  this.notifyWaiters(state);
1707
1749
  }
1708
1750
  resolvePushDiagnostics(snapshot) {
1709
- const state = this.openByUri.get(snapshot.uri);
1751
+ const state = this.openByUri.get(normalizeDocumentUri(snapshot.uri));
1710
1752
  if (!state?.lastPublish)
1711
1753
  return { status: "missing" };
1712
1754
  const publish = state.lastPublish;
@@ -1720,7 +1762,7 @@ class WorkspaceDocumentState {
1720
1762
  return waitMs === 0 ? { status: "ready", diagnostics: publish.diagnostics } : { status: "wait", waitMs };
1721
1763
  }
1722
1764
  waitForDiagnosticsActivity(snapshot, timeoutMs) {
1723
- const state = this.openByUri.get(snapshot.uri);
1765
+ const state = this.openByUri.get(normalizeDocumentUri(snapshot.uri));
1724
1766
  if (!state || timeoutMs <= 0)
1725
1767
  return Promise.resolve();
1726
1768
  return new Promise((resolveActivity) => {
@@ -1729,11 +1771,11 @@ class WorkspaceDocumentState {
1729
1771
  if (settled)
1730
1772
  return;
1731
1773
  settled = true;
1732
- clearTimeout(timer);
1774
+ this.timerProvider.clearTimeout(timer);
1733
1775
  state.waiters.delete(finish);
1734
1776
  resolveActivity();
1735
1777
  };
1736
- const timer = setTimeout(finish, timeoutMs);
1778
+ const timer = this.timerProvider.setTimeout(finish, timeoutMs);
1737
1779
  if (typeof timer.unref === "function")
1738
1780
  timer.unref();
1739
1781
  state.waiters.add(finish);
@@ -1841,7 +1883,7 @@ class WorkspaceDocumentState {
1841
1883
  waiters: new Set
1842
1884
  };
1843
1885
  this.openDocuments.set(path, state);
1844
- this.openByUri.set(state.uri, state);
1886
+ this.openByUri.set(normalizeDocumentUri(state.uri), state);
1845
1887
  this.notifyWaiters(state);
1846
1888
  await this.sendNotification("textDocument/didOpen", {
1847
1889
  textDocument: { uri: state.uri, languageId: state.languageId, version: state.version, text }
@@ -1866,7 +1908,7 @@ class WorkspaceDocumentState {
1866
1908
  }
1867
1909
  async closeDocument(state) {
1868
1910
  this.openDocuments.delete(state.path);
1869
- this.openByUri.delete(state.uri);
1911
+ this.openByUri.delete(normalizeDocumentUri(state.uri));
1870
1912
  this.clearDiagnostics(state.uri);
1871
1913
  this.notifyWaiters(state);
1872
1914
  await this.sendNotification("textDocument/didClose", { textDocument: { uri: state.uri } });
@@ -1895,13 +1937,11 @@ import { dirname as dirname2, isAbsolute as isAbsolute2, relative as relative3,
1895
1937
  import { fileURLToPath } from "node:url";
1896
1938
 
1897
1939
  class WorkspaceEditPathError extends Error {
1898
- path;
1899
- detail;
1900
- name = "WorkspaceEditPathError";
1901
1940
  constructor(path, detail) {
1902
1941
  super(`${detail}: ${path}`);
1903
1942
  this.path = path;
1904
1943
  this.detail = detail;
1944
+ this.name = "WorkspaceEditPathError";
1905
1945
  }
1906
1946
  }
1907
1947
  function isPathInsideWorkspace(filePath, workspaceRoot) {
@@ -2193,13 +2233,11 @@ function canonicalFingerprint(operations) {
2193
2233
 
2194
2234
  // ../lsp-core/src/lsp/workspace-edit-types.ts
2195
2235
  class WorkspaceEditValidationError extends Error {
2196
- changeIndex;
2197
- detail;
2198
- name = "WorkspaceEditValidationError";
2199
2236
  constructor(changeIndex, detail) {
2200
2237
  super(`change ${changeIndex}: ${detail}`);
2201
2238
  this.changeIndex = changeIndex;
2202
2239
  this.detail = detail;
2240
+ this.name = "WorkspaceEditValidationError";
2203
2241
  }
2204
2242
  }
2205
2243
 
@@ -2697,10 +2735,9 @@ function simulateDelete(operation, virtual) {
2697
2735
  import { existsSync as existsSync5, lstatSync as lstatSync3, readdirSync as readdirSync2 } from "node:fs";
2698
2736
  import { dirname as dirname4, resolve as resolve5 } from "node:path";
2699
2737
  class WorkspaceSnapshotBuilder {
2700
- workspaceRoot;
2701
- snapshots = new Map;
2702
2738
  constructor(workspaceRoot) {
2703
2739
  this.workspaceRoot = workspaceRoot;
2740
+ this.snapshots = new Map;
2704
2741
  }
2705
2742
  build(operations) {
2706
2743
  this.add(this.workspaceRoot, false);
@@ -2744,8 +2781,10 @@ function snapshotOperations(operations, workspaceRoot) {
2744
2781
 
2745
2782
  // ../lsp-core/src/lsp/workspace-edit-plan.ts
2746
2783
  class PlanPathIndex {
2747
- firstChangeByPath = new Map;
2748
- reportedPathByCanonical = new Map;
2784
+ constructor() {
2785
+ this.firstChangeByPath = new Map;
2786
+ this.reportedPathByCanonical = new Map;
2787
+ }
2749
2788
  build(operations) {
2750
2789
  for (const operation of operations) {
2751
2790
  switch (operation.kind) {
@@ -2834,14 +2873,11 @@ function isRecord4(value) {
2834
2873
  }
2835
2874
 
2836
2875
  class WorkspaceMutationController {
2837
- workspaceRoot;
2838
- documents;
2839
- activeLease = null;
2840
- nextLeaseId = 1;
2841
- io;
2842
2876
  constructor(workspaceRoot, documents) {
2843
2877
  this.workspaceRoot = workspaceRoot;
2844
2878
  this.documents = documents;
2879
+ this.activeLease = null;
2880
+ this.nextLeaseId = 1;
2845
2881
  }
2846
2882
  setIo(io) {
2847
2883
  this.io = io;
@@ -2954,14 +2990,12 @@ var DIAGNOSTICS_FRESHNESS_TIMEOUT_MS = 3000;
2954
2990
  var VERSIONLESS_PUBLISH_QUIESCENCE_MS = 250;
2955
2991
 
2956
2992
  class LspClient extends LspClientConnection {
2957
- diagnosticPullErrors = [];
2958
- documents;
2959
- workspaceMutations;
2960
- diagnosticsFreshnessTimeoutMs;
2961
2993
  constructor(root, server2, options = {}) {
2962
2994
  super(root, server2, options);
2995
+ this.diagnosticPullErrors = [];
2963
2996
  this.diagnosticsFreshnessTimeoutMs = options.diagnosticsFreshnessTimeoutMs ?? DIAGNOSTICS_FRESHNESS_TIMEOUT_MS;
2964
2997
  this.documents = new WorkspaceDocumentState((method, params) => this.sendNotification(method, params), (uri) => this.diagnosticsStore.delete(uri), {
2998
+ timerProvider: this.timerProvider,
2965
2999
  versionlessPublishQuiescenceMs: options.versionlessPublishQuiescenceMs ?? VERSIONLESS_PUBLISH_QUIESCENCE_MS
2966
3000
  });
2967
3001
  this.workspaceMutations = new WorkspaceMutationController(root, this.documents);
@@ -3014,6 +3048,18 @@ class LspClient extends LspClientConnection {
3014
3048
  textDocument: { uri: pathToFileURL3(absPath).href }
3015
3049
  }, options);
3016
3050
  }
3051
+ async formatDocument(filePath, options, signal) {
3052
+ if (!this.isDocumentFormattingSupported())
3053
+ return null;
3054
+ const absPath = this.resolveWorkspacePath(filePath);
3055
+ await this.openFile(absPath);
3056
+ const requestOptions = signal === undefined ? {} : { signal };
3057
+ const edits = await this.sendRequest("textDocument/formatting", {
3058
+ textDocument: { uri: pathToFileURL3(absPath).href },
3059
+ options
3060
+ }, requestOptions);
3061
+ return edits ?? [];
3062
+ }
3017
3063
  async workspaceSymbols(query, signal) {
3018
3064
  const options = signal === undefined ? {} : { signal };
3019
3065
  return this.sendRequest("workspace/symbol", { query }, options);
@@ -3053,7 +3099,7 @@ class LspClient extends LspClientConnection {
3053
3099
  const absPath = this.resolveWorkspacePath(filePath);
3054
3100
  const uri = pathToFileURL3(absPath).href;
3055
3101
  await this.openFile(absPath);
3056
- const deadlineAt = Date.now() + this.diagnosticsFreshnessTimeoutMs;
3102
+ const deadlineAt = this.timerProvider.now() + this.diagnosticsFreshnessTimeoutMs;
3057
3103
  for (;; ) {
3058
3104
  signal?.throwIfAborted();
3059
3105
  const snapshot = this.documents.captureDiagnosticSnapshot(absPath);
@@ -3066,7 +3112,7 @@ class LspClient extends LspClientConnection {
3066
3112
  if (!pushFallbackOnly) {
3067
3113
  const cached = this.documents.getPullCache(snapshot);
3068
3114
  try {
3069
- const remainingMs2 = deadlineAt - Date.now();
3115
+ const remainingMs2 = deadlineAt - this.timerProvider.now();
3070
3116
  if (remainingMs2 <= 0)
3071
3117
  return this.freshnessTimeout(absPath);
3072
3118
  const result = await this.sendRequest("textDocument/diagnostic", {
@@ -3101,7 +3147,7 @@ class LspClient extends LspClientConnection {
3101
3147
  }
3102
3148
  if (!pushFallbackOnly)
3103
3149
  continue;
3104
- const remainingMs = deadlineAt - Date.now();
3150
+ const remainingMs = deadlineAt - this.timerProvider.now();
3105
3151
  if (remainingMs <= 0) {
3106
3152
  if (!this.isDiagnosticPullSupported() && snapshot.publishGeneration === 0) {
3107
3153
  const cached = this.documents.getPullCache(snapshot);
@@ -3259,18 +3305,16 @@ function awaitWithSignal(promise, signal) {
3259
3305
  }
3260
3306
 
3261
3307
  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
3308
  constructor(options = {}) {
3309
+ this.clients = new Map;
3310
+ this.pendingStops = new Map;
3311
+ this.respawnBudgets = new Map;
3312
+ this.reaperHandle = null;
3313
+ this.signalDisposer = null;
3314
+ this.disposed = false;
3272
3315
  this.idleTimeoutMs = options.idleTimeoutMs ?? IDLE_TIMEOUT_MS;
3273
3316
  this.initTimeoutMs = options.initTimeoutMs ?? INIT_TIMEOUT_MS;
3317
+ this.maxResidentClients = options.maxResidentClients ?? MAX_RESIDENT_CLIENTS;
3274
3318
  this.reaperIntervalMs = options.reaperIntervalMs ?? REAPER_INTERVAL_MS;
3275
3319
  this.clientFactory = options.clientFactory ?? ((root, server2) => new LspClient(root, server2));
3276
3320
  this.now = options.now ?? (() => Date.now());
@@ -3290,24 +3334,79 @@ class LspManager {
3290
3334
  getKey(root, serverId) {
3291
3335
  return `${root}::${serverId}`;
3292
3336
  }
3337
+ tombstoneStop(key, client) {
3338
+ const stop = stopClientBestEffort(client);
3339
+ this.pendingStops.set(key, stop);
3340
+ stop.finally(() => {
3341
+ if (this.pendingStops.get(key) === stop) {
3342
+ this.pendingStops.delete(key);
3343
+ }
3344
+ });
3345
+ return stop;
3346
+ }
3347
+ recordDeadGeneration(key) {
3348
+ let budget = this.respawnBudgets.get(key);
3349
+ if (budget === undefined) {
3350
+ budget = { deadGenerations: 0, exhaustedAt: null };
3351
+ this.respawnBudgets.set(key, budget);
3352
+ }
3353
+ budget.deadGenerations += 1;
3354
+ }
3355
+ markHealthyGeneration(key) {
3356
+ this.respawnBudgets.delete(key);
3357
+ }
3358
+ ensureRespawnAllowed(key, root, serverId) {
3359
+ const budget = this.respawnBudgets.get(key);
3360
+ if (budget === undefined || budget.deadGenerations < CLIENT_RESPAWN_RETRY_LIMIT)
3361
+ return;
3362
+ if (budget.exhaustedAt === null) {
3363
+ budget.exhaustedAt = this.now();
3364
+ throw new LspClientRespawnBudgetExceededError(serverId, root, CLIENT_RESPAWN_RETRY_LIMIT);
3365
+ }
3366
+ if (this.now() - budget.exhaustedAt < CLIENT_RESPAWN_COOLDOWN_MS) {
3367
+ throw new LspClientRespawnBudgetExceededError(serverId, root, CLIENT_RESPAWN_RETRY_LIMIT);
3368
+ }
3369
+ budget.deadGenerations = 0;
3370
+ budget.exhaustedAt = null;
3371
+ }
3293
3372
  reapStale() {
3294
3373
  const t = this.now();
3295
3374
  for (const [key, managed] of this.clients) {
3296
3375
  if (managed.isInitializing && managed.initializingSince !== null && t - managed.initializingSince > this.initTimeoutMs) {
3297
- stopClientBestEffort(managed.client);
3298
3376
  this.clients.delete(key);
3377
+ this.tombstoneStop(key, managed.client);
3299
3378
  continue;
3300
3379
  }
3301
3380
  if (!managed.isInitializing && managed.refCount === 0 && managed.pendingWaiters === 0 && t - managed.lastUsedAt > this.idleTimeoutMs) {
3302
- stopClientBestEffort(managed.client);
3303
3381
  this.clients.delete(key);
3382
+ this.tombstoneStop(key, managed.client);
3304
3383
  }
3305
3384
  }
3306
3385
  }
3386
+ evictForAdmission() {
3387
+ while (this.clients.size >= this.maxResidentClients) {
3388
+ const victim = this.leastRecentlyUsedIdleClient();
3389
+ if (!victim)
3390
+ return;
3391
+ this.clients.delete(victim.key);
3392
+ this.tombstoneStop(victim.key, victim.managed.client);
3393
+ }
3394
+ }
3395
+ leastRecentlyUsedIdleClient() {
3396
+ let candidate = null;
3397
+ for (const [key, managed] of this.clients) {
3398
+ if (managed.refCount > 0 || managed.pendingWaiters > 0 || managed.isInitializing)
3399
+ continue;
3400
+ if (candidate === null || managed.lastUsedAt < candidate.managed.lastUsedAt) {
3401
+ candidate = { key, managed };
3402
+ }
3403
+ }
3404
+ return candidate;
3405
+ }
3307
3406
  async tryDeleteIfOrphaned(key, managed) {
3308
3407
  if (managed.refCount === 0 && managed.pendingWaiters === 0 && !managed.isInitializing && this.clients.get(key) === managed) {
3309
3408
  this.clients.delete(key);
3310
- await stopClientBestEffort(managed.client);
3409
+ await this.tombstoneStop(key, managed.client);
3311
3410
  }
3312
3411
  }
3313
3412
  async getClient(root, server2, signal) {
@@ -3316,12 +3415,22 @@ class LspManager {
3316
3415
  }
3317
3416
  signal?.throwIfAborted();
3318
3417
  const key = this.getKey(root, server2.id);
3418
+ for (;; ) {
3419
+ const pendingStop = this.pendingStops.get(key);
3420
+ if (pendingStop === undefined)
3421
+ break;
3422
+ await awaitWithSignal(pendingStop, signal);
3423
+ signal?.throwIfAborted();
3424
+ }
3425
+ if (this.disposed) {
3426
+ throw new Error("LspManager has been disposed");
3427
+ }
3319
3428
  let managed = this.clients.get(key);
3320
3429
  if (managed) {
3321
3430
  const t = this.now();
3322
3431
  if (managed.isInitializing && managed.initializingSince !== null && t - managed.initializingSince > this.initTimeoutMs) {
3323
- await stopClientBestEffort(managed.client);
3324
3432
  this.clients.delete(key);
3433
+ await this.tombstoneStop(key, managed.client);
3325
3434
  managed = undefined;
3326
3435
  }
3327
3436
  }
@@ -3342,14 +3451,20 @@ class LspManager {
3342
3451
  signal.throwIfAborted();
3343
3452
  }
3344
3453
  if (!managed.client.isAlive()) {
3345
- await stopClientBestEffort(managed.client);
3346
- this.clients.delete(key);
3454
+ this.recordDeadGeneration(key);
3455
+ if (this.clients.get(key) === managed) {
3456
+ this.clients.delete(key);
3457
+ }
3458
+ await this.tombstoneStop(key, managed.client);
3347
3459
  return this.getClient(root, server2, signal);
3348
3460
  }
3461
+ this.markHealthyGeneration(key);
3349
3462
  managed.refCount++;
3350
3463
  managed.lastUsedAt = this.now();
3351
3464
  return managed.client;
3352
3465
  }
3466
+ this.evictForAdmission();
3467
+ this.ensureRespawnAllowed(key, root, server2.id);
3353
3468
  const client = this.clientFactory(root, server2);
3354
3469
  const initStartedAt = this.now();
3355
3470
  const initPromise = (async () => {
@@ -3373,7 +3488,7 @@ class LspManager {
3373
3488
  if (this.clients.get(key) === newManaged) {
3374
3489
  this.clients.delete(key);
3375
3490
  }
3376
- await stopClientBestEffort(client);
3491
+ await this.tombstoneStop(key, client);
3377
3492
  throw err;
3378
3493
  }
3379
3494
  newManaged.pendingWaiters--;
@@ -3384,6 +3499,15 @@ class LspManager {
3384
3499
  await this.tryDeleteIfOrphaned(key, newManaged);
3385
3500
  signal.throwIfAborted();
3386
3501
  }
3502
+ if (!client.isAlive()) {
3503
+ this.recordDeadGeneration(key);
3504
+ if (this.clients.get(key) === newManaged) {
3505
+ this.clients.delete(key);
3506
+ }
3507
+ await this.tombstoneStop(key, client);
3508
+ return this.getClient(root, server2, signal);
3509
+ }
3510
+ this.markHealthyGeneration(key);
3387
3511
  newManaged.refCount++;
3388
3512
  newManaged.lastUsedAt = this.now();
3389
3513
  return client;
@@ -3404,14 +3528,20 @@ class LspManager {
3404
3528
  if (client && managed.client !== client)
3405
3529
  return;
3406
3530
  this.clients.delete(key);
3407
- stopClientBestEffort(managed.client);
3531
+ this.tombstoneStop(key, managed.client);
3408
3532
  }
3409
3533
  warmupClient(root, server2) {
3410
3534
  if (this.disposed)
3411
3535
  return;
3412
3536
  const key = this.getKey(root, server2.id);
3413
- if (this.clients.has(key))
3537
+ if (this.clients.has(key) || this.pendingStops.has(key))
3414
3538
  return;
3539
+ this.evictForAdmission();
3540
+ try {
3541
+ this.ensureRespawnAllowed(key, root, server2.id);
3542
+ } catch {
3543
+ return;
3544
+ }
3415
3545
  const client = this.clientFactory(root, server2);
3416
3546
  const initStartedAt = this.now();
3417
3547
  const initPromise = (async () => {
@@ -3437,7 +3567,7 @@ class LspManager {
3437
3567
  if (this.clients.get(key) === managed) {
3438
3568
  this.clients.delete(key);
3439
3569
  }
3440
- stopClientBestEffort(client);
3570
+ this.tombstoneStop(key, client);
3441
3571
  });
3442
3572
  }
3443
3573
  isServerInitializing(root, serverId) {
@@ -3481,8 +3611,11 @@ class LspManager {
3481
3611
  for (const managed of this.clients.values()) {
3482
3612
  stopPromises.push(stopClientBestEffort(managed.client));
3483
3613
  }
3614
+ const tombstonedStops = [...this.pendingStops.values()];
3484
3615
  this.clients.clear();
3485
- await Promise.allSettled(stopPromises);
3616
+ this.respawnBudgets.clear();
3617
+ await Promise.allSettled([...stopPromises, ...tombstonedStops]);
3618
+ this.pendingStops.clear();
3486
3619
  }
3487
3620
  }
3488
3621
  var _defaultInstance = null;
@@ -3500,57 +3633,52 @@ async function disposeDefaultLspManager() {
3500
3633
  }
3501
3634
  }
3502
3635
 
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 {};
3636
+ // ../lsp-core/src/lsp/outside-context-workspace.ts
3637
+ import { existsSync as existsSync6, realpathSync as realpathSync4 } from "node:fs";
3638
+ import { dirname as dirname5, join as join3 } from "node:path";
3639
+
3640
+ // ../lsp-core/src/lsp/workspace-markers.ts
3641
+ var GIT_WORKSPACE_MARKER = ".git";
3642
+ var PROJECT_WORKSPACE_MARKERS = [
3643
+ "package.json",
3644
+ "pyproject.toml",
3645
+ "Cargo.toml",
3646
+ "go.mod",
3647
+ "pom.xml",
3648
+ "build.gradle"
3649
+ ];
3650
+ var WORKSPACE_MARKERS = [GIT_WORKSPACE_MARKER, ...PROJECT_WORKSPACE_MARKERS];
3651
+
3652
+ // ../lsp-core/src/lsp/outside-context-workspace.ts
3653
+ function findWorkspaceRootOutsideContext(directory) {
3654
+ const marked = nearestMarkedAncestor(directory);
3655
+ if (marked !== undefined)
3656
+ return marked;
3657
+ return realpathSync4(nearestExistingAncestor(directory));
3658
+ }
3659
+ function nearestMarkedAncestor(directory) {
3660
+ let current = directory;
3661
+ for (;; ) {
3662
+ if (existsSync6(current) && WORKSPACE_MARKERS.some((marker) => existsSync6(join3(current, marker)))) {
3663
+ return realpathSync4(current);
3664
+ }
3665
+ const parent = dirname5(current);
3666
+ if (parent === current)
3667
+ return;
3668
+ current = parent;
3518
3669
  }
3519
3670
  }
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);
3671
+ function nearestExistingAncestor(directory) {
3672
+ let current = directory;
3673
+ while (!existsSync6(current)) {
3674
+ const parent = dirname5(current);
3675
+ if (parent === current)
3676
+ return current;
3677
+ current = parent;
3678
+ }
3679
+ return current;
3549
3680
  }
3550
3681
 
3551
- // ../lsp-core/src/lsp/config-loader.ts
3552
- import { existsSync as existsSync7, readFileSync as readFileSync4 } from "node:fs";
3553
-
3554
3682
  // ../lsp-core/src/lsp/server-definitions.ts
3555
3683
  var LSP_INSTALL_HINTS = {
3556
3684
  typescript: "npm install -g typescript-language-server typescript",
@@ -3596,6 +3724,26 @@ var LSP_INSTALL_HINTS = {
3596
3724
  julials: `julia -e 'using Pkg; Pkg.add("LanguageServer")'`,
3597
3725
  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
3726
  };
3727
+ var LSP_LOCAL_INSTALL_HINTS = {
3728
+ typescript: "bun add -d typescript-language-server typescript",
3729
+ vue: "bun add -d @vue/language-server",
3730
+ eslint: "bun add -d vscode-langservers-extracted",
3731
+ oxlint: "bun add -d oxlint",
3732
+ biome: "bun add -d @biomejs/biome",
3733
+ svelte: "bun add -d svelte-language-server",
3734
+ astro: "bun add -d @astrojs/language-server",
3735
+ bash: "bun add -d bash-language-server",
3736
+ "bash-ls": "bun add -d bash-language-server",
3737
+ "yaml-ls": "bun add -d yaml-language-server",
3738
+ php: "bun add -d intelephense",
3739
+ prisma: "bun add -d prisma",
3740
+ dockerfile: "bun add -d dockerfile-language-server-nodejs",
3741
+ pyright: "uv add --dev pyright",
3742
+ basedpyright: "uv add --dev basedpyright",
3743
+ ruff: "uv add --dev ruff",
3744
+ ty: "uv add --dev ty",
3745
+ "ruby-lsp": "bundle add ruby-lsp --group development"
3746
+ };
3599
3747
  var BUILTIN_SERVERS = {
3600
3748
  typescript: {
3601
3749
  command: ["typescript-language-server", "--stdio"],
@@ -3698,7 +3846,56 @@ var BUILTIN_SERVERS = {
3698
3846
  }
3699
3847
  };
3700
3848
 
3849
+ // ../lsp-core/src/lsp/server-install-state.ts
3850
+ import { existsSync as existsSync7, mkdirSync, readFileSync as readFileSync3, renameSync as renameSync2, writeFileSync as writeFileSync2 } from "node:fs";
3851
+ import { dirname as dirname6 } from "node:path";
3852
+ function getInstallDecisionsPath() {
3853
+ return lspRequestContext().installDecisionsPath;
3854
+ }
3855
+ function loadInstallDecisions() {
3856
+ const path = getInstallDecisionsPath();
3857
+ if (!existsSync7(path))
3858
+ return {};
3859
+ try {
3860
+ const parsed = JSON.parse(readFileSync3(path, "utf8"));
3861
+ return isInstallDecisions(parsed) ? parsed : {};
3862
+ } catch {
3863
+ return {};
3864
+ }
3865
+ }
3866
+ function loadInstallDecision(serverId) {
3867
+ return loadInstallDecisions()[serverId];
3868
+ }
3869
+ function recordInstallDecision(serverId, decision, decidedAt = new Date().toISOString()) {
3870
+ const decisions = loadInstallDecisions();
3871
+ decisions[serverId] = { decision, decidedAt };
3872
+ writeInstallDecisions(decisions);
3873
+ }
3874
+ function isInstallDecision(value) {
3875
+ return value === "declined" || value === "allowed";
3876
+ }
3877
+ function writeInstallDecisions(decisions) {
3878
+ const path = getInstallDecisionsPath();
3879
+ mkdirSync(dirname6(path), { recursive: true });
3880
+ const tmpPath = `${path}.tmp`;
3881
+ writeFileSync2(tmpPath, `${JSON.stringify(decisions, null, 2)}
3882
+ `, "utf8");
3883
+ renameSync2(tmpPath, path);
3884
+ }
3885
+ function isInstallDecisions(value) {
3886
+ return isRecord5(value) && Object.values(value).every(isInstallDecisionRecord);
3887
+ }
3888
+ function isInstallDecisionRecord(value) {
3889
+ if (!isRecord5(value))
3890
+ return false;
3891
+ return isInstallDecision(value["decision"]) && typeof value["decidedAt"] === "string";
3892
+ }
3893
+ function isRecord5(value) {
3894
+ return typeof value === "object" && value !== null && !Array.isArray(value);
3895
+ }
3896
+
3701
3897
  // ../lsp-core/src/lsp/config-loader.ts
3898
+ import { existsSync as existsSync8, readFileSync as readFileSync4 } from "node:fs";
3702
3899
  function getProjectConfigPaths() {
3703
3900
  return lspRequestContext().projectConfigPaths;
3704
3901
  }
@@ -3706,7 +3903,7 @@ function getUserConfigPath() {
3706
3903
  return lspRequestContext().userConfigPath;
3707
3904
  }
3708
3905
  function loadJsonFile(path) {
3709
- if (!existsSync7(path))
3906
+ if (!existsSync8(path))
3710
3907
  return null;
3711
3908
  try {
3712
3909
  const parsed = JSON.parse(readFileSync4(path, "utf-8"));
@@ -3894,54 +4091,155 @@ function getDisabledServerIds() {
3894
4091
  }
3895
4092
 
3896
4093
  // ../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;
4094
+ import { existsSync as existsSync9 } from "node:fs";
4095
+ import { delimiter as delimiter3, dirname as dirname7, isAbsolute as isAbsolute3, join as join4, resolve as resolve7 } from "node:path";
4096
+ var LOCAL_BIN_RULES = [
4097
+ {
4098
+ markers: ["package.json", "bun.lock", "bun.lockb", "package-lock.json", "yarn.lock", "pnpm-lock.yaml"],
4099
+ binDirs: [join4("node_modules", ".bin")]
4100
+ },
4101
+ {
4102
+ markers: [
4103
+ "pyproject.toml",
4104
+ "ty.toml",
4105
+ "requirements.txt",
4106
+ "setup.py",
4107
+ "setup.cfg",
4108
+ "Pipfile",
4109
+ "pyrightconfig.json",
4110
+ "ruff.toml",
4111
+ ".ruff.toml"
4112
+ ],
4113
+ binDirs: [
4114
+ join4(".venv", "bin"),
4115
+ join4(".venv", "Scripts"),
4116
+ join4("venv", "bin"),
4117
+ join4("venv", "Scripts"),
4118
+ join4(".env", "bin"),
4119
+ join4(".env", "Scripts")
4120
+ ]
4121
+ },
4122
+ {
4123
+ markers: ["Gemfile", "Gemfile.lock"],
4124
+ binDirs: [join4("vendor", "bundle", "bin"), "bin"]
4125
+ },
4126
+ {
4127
+ markers: ["go.mod", "go.sum", "go.work"],
4128
+ binDirs: ["bin"]
4129
+ }
4130
+ ];
4131
+ var resolutionCache = new Map;
4132
+ var probeCount = 0;
4133
+ function probe(path) {
4134
+ probeCount += 1;
4135
+ return existsSync9(path);
4136
+ }
4137
+ function executableSuffixes(platform, pathExt) {
4138
+ if (platform !== "win32")
4139
+ return [""];
4140
+ const configured = pathExt ?? process.env["PATHEXT"] ?? "";
4141
+ const systemExts = configured.split(";").filter((entry) => entry.length > 0).map((entry) => entry.toLowerCase());
4142
+ return [...new Set(["", ...systemExts, ".exe", ".cmd", ".bat", ".ps1"])];
4143
+ }
4144
+ function probeWithSuffixes(directory, command, suffixes) {
4145
+ for (const suffix of suffixes) {
4146
+ const candidate = join4(directory, command + suffix);
4147
+ if (probe(candidate))
4148
+ return candidate;
3908
4149
  }
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"];
4150
+ return null;
4151
+ }
4152
+ function resolveLocal(command, workingDirectory, suffixes, stopAt) {
4153
+ const boundary = stopAt === undefined ? undefined : resolve7(stopAt);
4154
+ let current = resolve7(workingDirectory);
4155
+ while (true) {
4156
+ for (const rule of LOCAL_BIN_RULES) {
4157
+ if (!rule.markers.some((marker) => probe(join4(current, marker))))
4158
+ continue;
4159
+ for (const binDir of rule.binDirs) {
4160
+ const found = probeWithSuffixes(join4(current, binDir), command, suffixes);
4161
+ if (found !== null)
4162
+ return found;
4163
+ }
3918
4164
  }
4165
+ if (probe(join4(current, ".git")))
4166
+ return null;
4167
+ if (boundary !== undefined && current === boundary)
4168
+ return null;
4169
+ const parent = dirname7(current);
4170
+ if (parent === current)
4171
+ return null;
4172
+ current = parent;
3919
4173
  }
3920
- let pathEnv = process.env["PATH"] ?? "";
3921
- if (isWindows && !pathEnv) {
4174
+ }
4175
+ function resolveFromPath(command, suffixes, platform, pathEnvOverride) {
4176
+ let pathEnv = pathEnvOverride ?? process.env["PATH"] ?? "";
4177
+ if (platform === "win32" && !pathEnv) {
3922
4178
  pathEnv = process.env["Path"] ?? "";
3923
4179
  }
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
- }
4180
+ for (const entry of pathEnv.split(delimiter3)) {
4181
+ if (entry.length === 0)
4182
+ continue;
4183
+ const found = probeWithSuffixes(entry, command, suffixes);
4184
+ if (found !== null)
4185
+ return found;
3931
4186
  }
3932
- if (cmd === "node")
3933
- return true;
3934
- return false;
4187
+ return null;
4188
+ }
4189
+ function resolveServerBinary(command, workingDirectory, options = {}) {
4190
+ if (command.length === 0)
4191
+ return null;
4192
+ const [cmd] = command;
4193
+ if (cmd === undefined || cmd.length === 0)
4194
+ return null;
4195
+ const platform = options.platform ?? process.platform;
4196
+ const suffixes = executableSuffixes(platform, options.pathExt);
4197
+ if (cmd.includes("/") || cmd.includes("\\")) {
4198
+ const explicit = isAbsolute3(cmd) ? cmd : resolve7(workingDirectory ?? process.cwd(), cmd);
4199
+ return probe(explicit) ? explicit : null;
4200
+ }
4201
+ const cacheKey = JSON.stringify([
4202
+ workingDirectory ?? "",
4203
+ cmd,
4204
+ platform,
4205
+ options.stopAt ?? "",
4206
+ options.pathExt ?? "",
4207
+ options.pathEnv ?? process.env["PATH"] ?? ""
4208
+ ]);
4209
+ const cached = resolutionCache.get(cacheKey);
4210
+ if (cached !== undefined)
4211
+ return cached;
4212
+ let resolved = null;
4213
+ if (workingDirectory !== undefined && workingDirectory.length > 0) {
4214
+ resolved = resolveLocal(cmd, workingDirectory, suffixes, options.stopAt);
4215
+ }
4216
+ resolved ??= resolveFromPath(cmd, suffixes, platform, options.pathEnv);
4217
+ if (resolved === null && cmd === "node")
4218
+ resolved = cmd;
4219
+ resolutionCache.set(cacheKey, resolved);
4220
+ return resolved;
4221
+ }
4222
+ function isServerInstalled(command, workingDirectory, options = {}) {
4223
+ if (command.length === 0)
4224
+ return false;
4225
+ return resolveServerBinary(command, workingDirectory, options) !== null;
3935
4226
  }
3936
4227
 
3937
4228
  // ../lsp-core/src/lsp/server-resolution.ts
4229
+ function withResolvedCommand(command, binaryPath) {
4230
+ return [binaryPath, ...command.slice(1)];
4231
+ }
3938
4232
  function findServerForExtension(ext) {
3939
4233
  const servers = getMergedServers();
4234
+ const workingDirectory = contextCwd();
3940
4235
  for (const server2 of servers) {
3941
- if (server2.extensions.includes(ext) && isServerInstalled(server2.command)) {
4236
+ if (!server2.extensions.includes(ext))
4237
+ continue;
4238
+ const binaryPath = resolveServerBinary(server2.command, workingDirectory);
4239
+ if (binaryPath !== null) {
3942
4240
  const resolvedServer = {
3943
4241
  id: server2.id,
3944
- command: server2.command,
4242
+ command: withResolvedCommand(server2.command, binaryPath),
3945
4243
  extensions: server2.extensions,
3946
4244
  priority: server2.priority
3947
4245
  };
@@ -3988,6 +4286,7 @@ function findServerForExtension(ext) {
3988
4286
  function getAllServers() {
3989
4287
  const servers = getMergedServers();
3990
4288
  const disabled = getDisabledServerIds();
4289
+ const workingDirectory = contextCwd();
3991
4290
  const result = [];
3992
4291
  const seen = new Set;
3993
4292
  for (const server2 of servers) {
@@ -3995,7 +4294,7 @@ function getAllServers() {
3995
4294
  continue;
3996
4295
  result.push({
3997
4296
  id: server2.id,
3998
- installed: isServerInstalled(server2.command),
4297
+ installed: isServerInstalled(server2.command, workingDirectory),
3999
4298
  extensions: server2.extensions,
4000
4299
  disabled: false,
4001
4300
  source: server2.source,
@@ -4009,7 +4308,7 @@ function getAllServers() {
4009
4308
  const builtin = BUILTIN_SERVERS[id];
4010
4309
  result.push({
4011
4310
  id,
4012
- installed: builtin ? isServerInstalled(builtin.command) : false,
4311
+ installed: builtin ? isServerInstalled(builtin.command, workingDirectory) : false,
4013
4312
  extensions: builtin?.extensions ?? [],
4014
4313
  disabled: true,
4015
4314
  source: "disabled",
@@ -4020,7 +4319,6 @@ function getAllServers() {
4020
4319
  }
4021
4320
 
4022
4321
  // ../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
4322
  function isDirectoryPath(filePath) {
4025
4323
  try {
4026
4324
  return statSync3(filePath).isDirectory();
@@ -4029,32 +4327,90 @@ function isDirectoryPath(filePath) {
4029
4327
  }
4030
4328
  }
4031
4329
  function findWorkspaceRoot(filePath) {
4032
- const abs = resolvePathInsideContext(filePath);
4330
+ const cwd = contextCwd();
4331
+ const abs = resolveReadablePathInsideContext(filePath);
4033
4332
  let dir = abs;
4034
4333
  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;
4334
+ dir = dirname8(dir);
4335
+ }
4336
+ if (!isPathInside(cwd, abs))
4337
+ return findWorkspaceRootOutsideContext(dir);
4338
+ const fallbackRoot = nearestExistingDirectoryInsideContext(dir, cwd) ?? cwd;
4339
+ let nearestPackageRoot;
4340
+ while (isPathInside(cwd, dir)) {
4341
+ const canonicalDir = existingDirectoryInsideContext(dir, cwd);
4342
+ if (canonicalDir !== undefined) {
4343
+ if (existsSync10(join5(dir, GIT_WORKSPACE_MARKER))) {
4344
+ return canonicalDir;
4345
+ }
4346
+ if (nearestPackageRoot === undefined && hasProjectWorkspaceMarker(dir)) {
4347
+ nearestPackageRoot = canonicalDir;
4042
4348
  }
4043
4349
  }
4044
- prevDir = dir;
4045
- dir = dirname6(dir);
4350
+ if (dir === cwd)
4351
+ break;
4352
+ dir = dirname8(dir);
4046
4353
  }
4047
- return dirname6(abs);
4354
+ return nearestPackageRoot ?? fallbackRoot;
4355
+ }
4356
+ function hasProjectWorkspaceMarker(directory) {
4357
+ return PROJECT_WORKSPACE_MARKERS.some((marker) => existsSync10(join5(directory, marker)));
4358
+ }
4359
+ function resolveReadablePathInsideContext(filePath) {
4360
+ const cwd = contextCwd();
4361
+ const abs = resolve8(cwd, filePath);
4362
+ if (isPathInside(cwd, abs))
4363
+ return abs;
4364
+ const rebased = rebaseThroughCanonicalAncestor(abs, cwd);
4365
+ if (rebased !== undefined)
4366
+ return rebased;
4367
+ return canonicalizeExistingOrNearestAncestor(abs);
4048
4368
  }
4049
4369
  function resolvePathInsideContext(filePath) {
4050
4370
  const cwd = contextCwd();
4051
- const abs = resolve7(cwd, filePath);
4371
+ const abs = resolveReadablePathInsideContext(filePath);
4052
4372
  const canonical = canonicalizeExistingOrNearestAncestor(abs);
4053
4373
  if (!isPathInside(cwd, canonical)) {
4054
4374
  throw new LspInvalidPathError(`LSP file path must be inside request cwd: ${filePath}`);
4055
4375
  }
4056
4376
  return canonical;
4057
4377
  }
4378
+ function rebaseThroughCanonicalAncestor(path, cwd) {
4379
+ let current = path;
4380
+ const suffix = [];
4381
+ while (true) {
4382
+ if (existsSync10(current)) {
4383
+ const canonical = realpathSync5(current);
4384
+ if (isPathInside(cwd, canonical))
4385
+ return suffix.length === 0 ? canonical : join5(canonical, ...suffix);
4386
+ }
4387
+ const parent = dirname8(current);
4388
+ if (parent === current)
4389
+ return;
4390
+ suffix.unshift(basename3(current));
4391
+ current = parent;
4392
+ }
4393
+ }
4394
+ function existingDirectoryInsideContext(directory, cwd) {
4395
+ if (!existsSync10(directory))
4396
+ return;
4397
+ const canonical = realpathSync5(directory);
4398
+ if (!statSync3(canonical).isDirectory())
4399
+ return;
4400
+ return isPathInside(cwd, canonical) ? canonical : undefined;
4401
+ }
4402
+ function nearestExistingDirectoryInsideContext(directory, cwd) {
4403
+ let current = directory;
4404
+ while (isPathInside(cwd, current)) {
4405
+ const canonical = existingDirectoryInsideContext(current, cwd);
4406
+ if (canonical !== undefined)
4407
+ return canonical;
4408
+ if (current === cwd)
4409
+ return;
4410
+ current = dirname8(current);
4411
+ }
4412
+ return;
4413
+ }
4058
4414
  function formatServerLookupError(result) {
4059
4415
  if (result.status === "not_installed") {
4060
4416
  return formatNotInstalled(result);
@@ -4078,6 +4434,19 @@ function formatServerLookupError(result) {
4078
4434
  ].join(`
4079
4435
  `);
4080
4436
  }
4437
+ function formatInstallOptions(serverId, installHint) {
4438
+ const localHint = LSP_LOCAL_INSTALL_HINTS[serverId];
4439
+ if (localHint === undefined) {
4440
+ return ["To install, run:", ` ${installHint}`];
4441
+ }
4442
+ return [
4443
+ "To install in THIS repository (preferred — no global install needed):",
4444
+ ` ${localHint}`,
4445
+ "",
4446
+ "Or install it globally:",
4447
+ ` ${installHint}`
4448
+ ];
4449
+ }
4081
4450
  function formatNotInstalled(result) {
4082
4451
  const { server: server2, installHint } = result;
4083
4452
  const extensions = server2.extensions.join(", ");
@@ -4092,19 +4461,19 @@ function formatNotInstalled(result) {
4092
4461
  `Command not found: ${server2.command[0]}`,
4093
4462
  ""
4094
4463
  ];
4464
+ const installOptions = formatInstallOptions(server2.id, installHint);
4095
4465
  if (decision === "allowed") {
4096
4466
  return [
4097
4467
  ...header,
4098
4468
  "The user has pre-authorized LSP installation. Run the install command, then retry this tool:",
4099
- ` ${installHint}`
4469
+ ...installOptions.slice(1)
4100
4470
  ].join(`
4101
4471
  `);
4102
4472
  }
4103
4473
  if (!context.capabilities.installDecisionTool) {
4104
4474
  return [
4105
4475
  ...header,
4106
- "To install, run:",
4107
- ` ${installHint}`,
4476
+ ...installOptions,
4108
4477
  "",
4109
4478
  "ACTION REQUIRED — ASK THE USER whether to install this LSP server.",
4110
4479
  "Install-decision recording is unavailable in this harness; proceed without LSP if the user declines."
@@ -4113,8 +4482,7 @@ function formatNotInstalled(result) {
4113
4482
  }
4114
4483
  return [
4115
4484
  ...header,
4116
- "To install, run:",
4117
- ` ${installHint}`,
4485
+ ...installOptions,
4118
4486
  "",
4119
4487
  "ACTION REQUIRED — ASK THE USER whether to install this LSP server.",
4120
4488
  "- If the user agrees: run the install command above, then retry this tool.",
@@ -4125,7 +4493,7 @@ function formatNotInstalled(result) {
4125
4493
  ].join(`
4126
4494
  `);
4127
4495
  }
4128
- var READ_ONLY_RETRY_TOOLS = new Set([
4496
+ var READ_ONLY_TOOLS = new Set([
4129
4497
  "diagnostics",
4130
4498
  "definition",
4131
4499
  "references",
@@ -4134,7 +4502,7 @@ var READ_ONLY_RETRY_TOOLS = new Set([
4134
4502
  "prepareRename"
4135
4503
  ]);
4136
4504
  async function withLspClient(filePath, fn, toolName, options = {}) {
4137
- const absPath = resolvePathInsideContext(filePath);
4505
+ const absPath = READ_ONLY_TOOLS.has(toolName) ? resolveReadablePathInsideContext(filePath) : resolvePathInsideContext(filePath);
4138
4506
  if (isDirectoryPath(absPath)) {
4139
4507
  throw new LspInvalidPathError("Directory paths are not supported by this LSP tool. " + "Use lsp.diagnostics with a directory path for directory diagnostics.");
4140
4508
  }
@@ -4149,9 +4517,9 @@ async function withLspClient(filePath, fn, toolName, options = {}) {
4149
4517
  const acquireAndCall = async (allowRetry) => {
4150
4518
  const client = await manager.getClient(root, server2, options.signal);
4151
4519
  try {
4152
- return await fn(client, root);
4520
+ return await fn(client, root, absPath);
4153
4521
  } catch (err) {
4154
- if (allowRetry && READ_ONLY_RETRY_TOOLS.has(toolName) && isLspDeadConnectionError(err)) {
4522
+ if (allowRetry && READ_ONLY_TOOLS.has(toolName) && isLspDeadConnectionError(err)) {
4155
4523
  manager.invalidateClient(root, server2.id, client);
4156
4524
  return acquireAndCall(false);
4157
4525
  }
@@ -4169,8 +4537,8 @@ async function withLspClient(filePath, fn, toolName, options = {}) {
4169
4537
  }
4170
4538
 
4171
4539
  // ../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";
4540
+ import { existsSync as existsSync11, lstatSync as lstatSync4, readdirSync as readdirSync3 } from "node:fs";
4541
+ import { join as join6, resolve as resolve9 } from "node:path";
4174
4542
 
4175
4543
  // ../lsp-core/src/lsp/formatters.ts
4176
4544
  import { fileURLToPath as fileURLToPath2 } from "node:url";
@@ -4300,7 +4668,7 @@ function collectFilesWithExtension(dir, extension, maxFiles) {
4300
4668
  for (const entry of entries) {
4301
4669
  if (files.length >= maxFiles)
4302
4670
  return;
4303
- const fullPath = join5(currentDir, entry);
4671
+ const fullPath = join6(currentDir, entry);
4304
4672
  let stat;
4305
4673
  try {
4306
4674
  stat = lstatSync4(fullPath);
@@ -4325,8 +4693,8 @@ async function aggregateDiagnosticsForDirectory(directory, extension, severity,
4325
4693
  if (!extension.startsWith(".")) {
4326
4694
  throw new LspInvalidPathError(`Extension must start with a dot (e.g., ".ts", not "${extension}"). Use ".${extension}" instead.`);
4327
4695
  }
4328
- const absDir = resolve8(options.workspaceRoot ?? contextCwd(), directory);
4329
- if (!existsSync10(absDir)) {
4696
+ const absDir = resolve9(options.workspaceRoot ?? contextCwd(), directory);
4697
+ if (!existsSync11(absDir)) {
4330
4698
  throw new LspInvalidPathError(`Directory does not exist: ${absDir}`);
4331
4699
  }
4332
4700
  const serverResult = options.server === undefined ? findServerForExtension(extension) : { status: "found", server: options.server };
@@ -4413,7 +4781,7 @@ async function aggregateDiagnosticsForDirectory(directory, extension, severity,
4413
4781
 
4414
4782
  // ../lsp-core/src/lsp/infer-extension.ts
4415
4783
  import { lstatSync as lstatSync5, readdirSync as readdirSync4 } from "node:fs";
4416
- import { join as join6 } from "node:path";
4784
+ import { join as join7 } from "node:path";
4417
4785
  var SKIP_DIRECTORIES2 = new Set(["node_modules", ".git", "dist", "build", ".next", "out"]);
4418
4786
  var MAX_SCAN_ENTRIES = 500;
4419
4787
  function inferExtensionFromDirectory(directory) {
@@ -4431,7 +4799,7 @@ function inferExtensionFromDirectory(directory) {
4431
4799
  for (const entry of entries) {
4432
4800
  if (scanned >= MAX_SCAN_ENTRIES)
4433
4801
  return;
4434
- const fullPath = join6(dir, entry);
4802
+ const fullPath = join7(dir, entry);
4435
4803
  let stat;
4436
4804
  try {
4437
4805
  stat = lstatSync5(fullPath);
@@ -4606,7 +4974,7 @@ async function executeLspDiagnostics(params, signal) {
4606
4974
  const filePath = requireString(params, "filePath");
4607
4975
  const severity = severityFilter(params);
4608
4976
  try {
4609
- const absPath = resolvePathInsideContext(filePath);
4977
+ const absPath = resolveReadablePathInsideContext(filePath);
4610
4978
  if (isDirectoryPath(absPath)) {
4611
4979
  const extension = inferExtensionFromDirectory(absPath);
4612
4980
  if (!extension) {
@@ -4635,7 +5003,7 @@ async function executeLspDiagnostics(params, signal) {
4635
5003
  };
4636
5004
  return text(output2.output, details2);
4637
5005
  }
4638
- const result = await withLspClient(filePath, async (client) => client.diagnostics(filePath, signal), "diagnostics", clientOptions(signal));
5006
+ const result = await withLspClient(filePath, async (client, _workspaceRoot, resolvedFilePath) => client.diagnostics(resolvedFilePath, signal), "diagnostics", clientOptions(signal));
4639
5007
  if (result.transientError) {
4640
5008
  const message = result.transientError.message;
4641
5009
  const details2 = {
@@ -4682,6 +5050,96 @@ async function executeLspDiagnostics(params, signal) {
4682
5050
  throw error;
4683
5051
  }
4684
5052
  }
5053
+ // ../lsp-core/src/lsp/format-document.ts
5054
+ import { readFileSync as readFileSync5, renameSync as renameSync3, unlinkSync, writeFileSync as writeFileSync3 } from "node:fs";
5055
+ var DEFAULT_FORMATTING_OPTIONS = {
5056
+ tabSize: 4,
5057
+ insertSpaces: false,
5058
+ trimTrailingWhitespace: true,
5059
+ insertFinalNewline: true,
5060
+ trimFinalNewlines: true
5061
+ };
5062
+ var UNCHANGED = { status: "unchanged", linesAdded: 0, linesRemoved: 0 };
5063
+ async function formatDocumentWithClient(client, filePath, options = {}) {
5064
+ const edits = await client.formatDocument(filePath, options.formattingOptions ?? DEFAULT_FORMATTING_OPTIONS, options.signal);
5065
+ if (edits === null)
5066
+ return { status: "unavailable", reason: "capability_not_advertised" };
5067
+ if (edits.length === 0)
5068
+ return UNCHANGED;
5069
+ const before = readFileSync5(filePath, "utf-8");
5070
+ const normalized = normalizeTextEdits(before, edits, 0);
5071
+ if (normalized.text === before)
5072
+ return UNCHANGED;
5073
+ writeAtomically(filePath, normalized.text);
5074
+ await client.openFile(filePath);
5075
+ return {
5076
+ status: "formatted",
5077
+ ...lineDelta(normalized.edits)
5078
+ };
5079
+ }
5080
+ function lineDelta(edits) {
5081
+ let linesAdded = 0;
5082
+ let linesRemoved = 0;
5083
+ for (const edit of edits) {
5084
+ linesRemoved += edit.range.end.line - edit.range.start.line + 1;
5085
+ linesAdded += edit.newText.split(`
5086
+ `).length;
5087
+ }
5088
+ return { linesAdded, linesRemoved };
5089
+ }
5090
+ function writeAtomically(filePath, content) {
5091
+ const tempPath = `${filePath}.omo-format.tmp`;
5092
+ writeFileSync3(tempPath, content, "utf-8");
5093
+ try {
5094
+ renameSync3(tempPath, filePath);
5095
+ } catch (error) {
5096
+ try {
5097
+ unlinkSync(tempPath);
5098
+ } catch {}
5099
+ throw error;
5100
+ }
5101
+ }
5102
+
5103
+ // ../lsp-core/src/tools/format.ts
5104
+ async function executeLspFormat(params, signal) {
5105
+ const filePath = requireString(params, "filePath");
5106
+ try {
5107
+ const result = await withLspClient(filePath, async (client, _workspaceRoot, resolvedFilePath) => formatDocumentWithClient(client, resolvedFilePath, signal === undefined ? {} : { signal }), "format", clientOptions(signal));
5108
+ return text(describeResult(filePath, result), formatDetails(filePath, result));
5109
+ } catch (error) {
5110
+ const missingDependency = missingDependencyResult(error, {
5111
+ filePath,
5112
+ status: "unavailable",
5113
+ reason: "server_unavailable",
5114
+ linesAdded: 0,
5115
+ linesRemoved: 0
5116
+ });
5117
+ if (missingDependency)
5118
+ return missingDependency;
5119
+ throw error;
5120
+ }
5121
+ }
5122
+ function formatDetails(filePath, result) {
5123
+ if (result.status === "unavailable") {
5124
+ return { filePath, status: "unavailable", reason: result.reason, linesAdded: 0, linesRemoved: 0 };
5125
+ }
5126
+ return {
5127
+ filePath,
5128
+ status: result.status,
5129
+ linesAdded: result.linesAdded,
5130
+ linesRemoved: result.linesRemoved
5131
+ };
5132
+ }
5133
+ function describeResult(filePath, result) {
5134
+ if (result.status === "unavailable") {
5135
+ return `Formatting unavailable for ${filePath}: the language server does not advertise documentFormattingProvider.`;
5136
+ }
5137
+ if (result.status === "unchanged") {
5138
+ return `Already formatted: ${filePath}`;
5139
+ }
5140
+ return `Formatted ${filePath} (+${result.linesAdded}/-${result.linesRemoved} lines)`;
5141
+ }
5142
+
4685
5143
  // ../lsp-core/src/tools/install-decision.ts
4686
5144
  async function executeLspInstallDecision(params) {
4687
5145
  const serverId = requireString(params, "server_id");
@@ -4710,7 +5168,7 @@ async function executeLspGotoDefinition(params, signal) {
4710
5168
  const line = requireNumber(params, "line");
4711
5169
  const character = requireNumber(params, "character");
4712
5170
  try {
4713
- const result = await withLspClient(filePath, async (client) => client.definition(filePath, line, character, signal), "definition", clientOptions(signal));
5171
+ const result = await withLspClient(filePath, async (client, _workspaceRoot, resolvedFilePath) => client.definition(resolvedFilePath, line, character, signal), "definition", clientOptions(signal));
4714
5172
  const locations = !result ? [] : Array.isArray(result) ? result : [result];
4715
5173
  const details = { filePath, line, character, locations };
4716
5174
  if (locations.length === 0)
@@ -4735,7 +5193,7 @@ async function executeLspFindReferences(params, signal) {
4735
5193
  const character = requireNumber(params, "character");
4736
5194
  const includeDeclaration = optionalBoolean(params, "includeDeclaration") ?? true;
4737
5195
  try {
4738
- const result = await withLspClient(filePath, async (client) => client.references(filePath, line, character, includeDeclaration, signal), "references", clientOptions(signal));
5196
+ const result = await withLspClient(filePath, async (client, _workspaceRoot, resolvedFilePath) => client.references(resolvedFilePath, line, character, includeDeclaration, signal), "references", clientOptions(signal));
4739
5197
  const references = Array.isArray(result) ? result : [];
4740
5198
  const total = references.length;
4741
5199
  const truncated = total > DEFAULT_MAX_REFERENCES;
@@ -4777,7 +5235,7 @@ async function executeLspPrepareRename(params, signal) {
4777
5235
  const line = requireNumber(params, "line");
4778
5236
  const character = requireNumber(params, "character");
4779
5237
  try {
4780
- const result = await withLspClient(filePath, async (client) => client.prepareRename(filePath, line, character, signal), "prepareRename", clientOptions(signal));
5238
+ const result = await withLspClient(filePath, async (client, _workspaceRoot, resolvedFilePath) => client.prepareRename(resolvedFilePath, line, character, signal), "prepareRename", clientOptions(signal));
4781
5239
  const details = { filePath, line, character, result };
4782
5240
  return text(formatPrepareRenameResult(result), details);
4783
5241
  } catch (error) {
@@ -4798,7 +5256,7 @@ async function executeLspRename(params, signal) {
4798
5256
  const character = requireNumber(params, "character");
4799
5257
  const newName = requireString(params, "newName");
4800
5258
  try {
4801
- const result = await withLspClient(filePath, async (client) => client.rename(filePath, line, character, newName, signal), "rename", clientOptions(signal));
5259
+ const result = await withLspClient(filePath, async (client, _workspaceRoot, resolvedFilePath) => client.rename(resolvedFilePath, line, character, newName, signal), "rename", clientOptions(signal));
4802
5260
  const details = { filePath, line, character, newName, apply: result.apply, edit: result.edit };
4803
5261
  return text(formatApplyResult(result.apply), details, !result.apply.success);
4804
5262
  } catch (error) {
@@ -4878,7 +5336,7 @@ async function executeLspSymbols(params, signal) {
4878
5336
  const symbols2 = await withLspClient(filePath, async (client) => client.workspaceSymbols(query, signal), "workspaceSymbols", clientOptions(signal));
4879
5337
  return formatSymbolsResult(filePath, scope, symbols2, limit, query);
4880
5338
  }
4881
- const symbols = await withLspClient(filePath, async (client) => client.documentSymbols(filePath, signal), "documentSymbols", clientOptions(signal));
5339
+ const symbols = await withLspClient(filePath, async (client, _workspaceRoot, resolvedFilePath) => client.documentSymbols(resolvedFilePath, signal), "documentSymbols", clientOptions(signal));
4882
5340
  return formatSymbolsResult(filePath, scope, symbols, limit);
4883
5341
  } catch (error) {
4884
5342
  const query = optionalString(params, "query");
@@ -5014,6 +5472,16 @@ var LSP_MCP_TOOLS = [
5014
5472
  }, ["filePath", "line", "character", "newName"]),
5015
5473
  execute: executeLspRename
5016
5474
  },
5475
+ {
5476
+ name: "format",
5477
+ aliases: ["lsp_format"],
5478
+ title: "LSP Format",
5479
+ description: "Format a source file with its language server and write the returned edits to disk.",
5480
+ inputSchema: objectSchema({
5481
+ filePath: { type: "string", description: "Source file path to format." }
5482
+ }, ["filePath"]),
5483
+ execute: executeLspFormat
5484
+ },
5017
5485
  {
5018
5486
  name: "install_decision",
5019
5487
  aliases: ["lsp_install_decision"],
@@ -5113,11 +5581,10 @@ function requestedProtocolVersion(params) {
5113
5581
  // src/daemon-client.ts
5114
5582
  import { connect } from "node:net";
5115
5583
  import { homedir as homedir3 } from "node:os";
5116
- import { join as join7 } from "node:path";
5584
+ import { join as join8 } from "node:path";
5117
5585
 
5118
5586
  // src/daemon-request-error.ts
5119
5587
  class DaemonRequestError extends Error {
5120
- requestWritten;
5121
5588
  constructor(message, requestWritten) {
5122
5589
  super(message);
5123
5590
  this.name = "DaemonRequestError";
@@ -5140,7 +5607,6 @@ class DaemonRequestCancelledError extends DaemonRequestError {
5140
5607
  }
5141
5608
 
5142
5609
  class DaemonRequestTimedOutError extends DaemonRequestError {
5143
- timeoutMs;
5144
5610
  constructor(requestWritten, timeoutMs) {
5145
5611
  super("daemon request timed out", requestWritten);
5146
5612
  this.name = "DaemonRequestTimedOutError";
@@ -5192,9 +5658,9 @@ function errorText(error) {
5192
5658
 
5193
5659
  // src/ensure-daemon.ts
5194
5660
  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";
5661
+ import { closeSync as closeSync2, existsSync as existsSync12, mkdirSync as mkdirSync3, openSync as openSync2, writeSync as writeSync2 } from "node:fs";
5196
5662
  import { Socket } from "node:net";
5197
- import { dirname as dirname8, isAbsolute as isAbsolute4 } from "node:path";
5663
+ import { dirname as dirname10, isAbsolute as isAbsolute5 } from "node:path";
5198
5664
  import { argv0, execPath } from "node:process";
5199
5665
 
5200
5666
  // src/ipc-protocol.ts
@@ -5208,25 +5674,23 @@ import {
5208
5674
  lstatSync as lstatSync6,
5209
5675
  mkdirSync as mkdirSync2,
5210
5676
  openSync,
5211
- readFileSync as readFileSync5,
5212
- unlinkSync,
5677
+ readFileSync as readFileSync6,
5678
+ unlinkSync as unlinkSync2,
5213
5679
  writeSync
5214
5680
  } from "node:fs";
5215
- import { dirname as dirname7 } from "node:path";
5681
+ import { dirname as dirname9 } from "node:path";
5216
5682
  var OMO_DAEMON_PROTOCOL_VERSION = 1;
5217
5683
  var AUTH_ERROR_CODE = -32001;
5218
5684
  var PROTOCOL_ERROR_CODE = -32002;
5219
5685
  var AUTH_TOKEN_BYTES = 32;
5220
5686
 
5221
5687
  class UnsafePrivateDirectoryError extends Error {
5222
- path;
5223
- reason;
5224
- name = "UnsafePrivateDirectoryError";
5225
- code = "unsafe_private_directory";
5226
5688
  constructor(path, reason) {
5227
5689
  super(`unsafe private directory ${path}: ${reason}`);
5228
5690
  this.path = path;
5229
5691
  this.reason = reason;
5692
+ this.name = "UnsafePrivateDirectoryError";
5693
+ this.code = "unsafe_private_directory";
5230
5694
  }
5231
5695
  }
5232
5696
  function authEnvelope(token) {
@@ -5234,7 +5698,7 @@ function authEnvelope(token) {
5234
5698
  }
5235
5699
  function readAuthToken(paths) {
5236
5700
  try {
5237
- const token = readFileSync5(paths.auth, "utf8").trim();
5701
+ const token = readFileSync6(paths.auth, "utf8").trim();
5238
5702
  return token.length > 0 ? token : null;
5239
5703
  } catch (error) {
5240
5704
  if (error instanceof Error)
@@ -5250,7 +5714,7 @@ function readOrCreateAuthToken(paths) {
5250
5714
  }
5251
5715
  function rotateAuthToken(paths) {
5252
5716
  try {
5253
- unlinkSync(paths.auth);
5717
+ unlinkSync2(paths.auth);
5254
5718
  } catch (error) {
5255
5719
  if (!(error instanceof Error))
5256
5720
  throw error;
@@ -5322,7 +5786,7 @@ function setPrivateFileMode(path) {
5322
5786
  chmodSync(path, 384);
5323
5787
  }
5324
5788
  function createAuthToken(paths) {
5325
- ensurePrivateDirectory(dirname7(paths.auth));
5789
+ ensurePrivateDirectory(dirname9(paths.auth));
5326
5790
  const token = randomBytes(AUTH_TOKEN_BYTES).toString("base64url");
5327
5791
  let fd;
5328
5792
  try {
@@ -5403,27 +5867,25 @@ import { fileURLToPath as fileURLToPath3 } from "node:url";
5403
5867
 
5404
5868
  // src/runtime-contract.ts
5405
5869
  import { statSync as statSync4 } from "node:fs";
5406
- import { isAbsolute as isAbsolute3 } from "node:path";
5870
+ import { isAbsolute as isAbsolute4 } from "node:path";
5407
5871
  var OMO_LSP_DAEMON_DIR = "OMO_LSP_DAEMON_DIR";
5408
5872
  var OMO_LSP_DAEMON_CLI = "OMO_LSP_DAEMON_CLI";
5409
5873
  var OMO_LSP_DAEMON_VERSION = "OMO_LSP_DAEMON_VERSION";
5410
5874
  var DAEMON_VERSION_PATTERN = /^[A-Za-z0-9][A-Za-z0-9._+-]{0,127}$/;
5411
5875
 
5412
5876
  class InvalidRuntimeOverrideError extends Error {
5413
- code = "invalid_runtime_override";
5414
- reason;
5415
5877
  constructor(reason, message) {
5416
5878
  super(message);
5879
+ this.code = "invalid_runtime_override";
5417
5880
  this.name = "InvalidRuntimeOverrideError";
5418
5881
  this.reason = reason;
5419
5882
  }
5420
5883
  }
5421
5884
 
5422
5885
  class InvalidDaemonVersionError extends Error {
5423
- code = "invalid_daemon_version";
5424
- version;
5425
5886
  constructor(version) {
5426
5887
  super("LSP daemon version must match [A-Za-z0-9][A-Za-z0-9._+-]{0,127}");
5888
+ this.code = "invalid_daemon_version";
5427
5889
  this.name = "InvalidDaemonVersionError";
5428
5890
  this.version = version;
5429
5891
  }
@@ -5442,12 +5904,12 @@ function resolveDaemonRuntime(env, defaults) {
5442
5904
  throw new InvalidRuntimeOverrideError("paired_values_required", `${OMO_LSP_DAEMON_CLI} and ${OMO_LSP_DAEMON_VERSION} must be set together`);
5443
5905
  }
5444
5906
  if (!hasCliOverride || !hasVersionOverride) {
5445
- if (!isAbsolute3(defaults.cliPath)) {
5907
+ if (!isAbsolute4(defaults.cliPath)) {
5446
5908
  throw new InvalidRuntimeOverrideError("packaged_cli_must_be_absolute", "Packaged LSP daemon CLI path must be absolute");
5447
5909
  }
5448
5910
  return { cliPath: defaults.cliPath, version: validateDaemonVersion(defaults.version) };
5449
5911
  }
5450
- if (!isAbsolute3(cliOverride)) {
5912
+ if (!isAbsolute4(cliOverride)) {
5451
5913
  throw new InvalidRuntimeOverrideError("cli_must_be_absolute", `${OMO_LSP_DAEMON_CLI} must be an absolute path to an existing regular file`);
5452
5914
  }
5453
5915
  let cliStats;
@@ -5469,10 +5931,9 @@ var requireFromHere = createRequire(import.meta.url);
5469
5931
  var MAX_SOCKET_PATH_LENGTH = 100;
5470
5932
 
5471
5933
  class InvalidDaemonDirectoryError extends Error {
5472
- code = "invalid_daemon_directory";
5473
- directory;
5474
5934
  constructor(directory) {
5475
5935
  super(`${OMO_LSP_DAEMON_DIR} must be an absolute path`);
5936
+ this.code = "invalid_daemon_directory";
5476
5937
  this.name = "InvalidDaemonDirectoryError";
5477
5938
  this.directory = directory;
5478
5939
  }
@@ -5626,7 +6087,7 @@ async function probeDaemon(paths, timeoutMs = PROBE_TIMEOUT_MS, signal) {
5626
6087
  return await pingDaemon(paths, token, timeoutMs, signal) !== null;
5627
6088
  }
5628
6089
  function pingDaemon(paths, token, timeoutMs = PROBE_TIMEOUT_MS, signal) {
5629
- return new Promise((resolve9) => {
6090
+ return new Promise((resolve10) => {
5630
6091
  const socket = new Socket;
5631
6092
  let settled = false;
5632
6093
  let timer;
@@ -5638,7 +6099,7 @@ function pingDaemon(paths, token, timeoutMs = PROBE_TIMEOUT_MS, signal) {
5638
6099
  clearTimeout(timer);
5639
6100
  signal?.removeEventListener("abort", onAbort);
5640
6101
  socket.destroy();
5641
- resolve9(value);
6102
+ resolve10(value);
5642
6103
  };
5643
6104
  const onAbort = () => finish(null);
5644
6105
  const decoder = createLineDecoder((message) => {
@@ -5662,12 +6123,13 @@ function pingDaemon(paths, token, timeoutMs = PROBE_TIMEOUT_MS, signal) {
5662
6123
  });
5663
6124
  }
5664
6125
  function spawnDaemonProcess(paths) {
5665
- mkdirSync3(dirname8(paths.log), { recursive: true });
6126
+ mkdirSync3(dirname10(paths.log), { recursive: true });
5666
6127
  const logFd = openSync2(paths.log, "a");
5667
6128
  try {
5668
6129
  const child = spawn2(resolveDaemonNodeExecutable(), [paths.cliPath, "daemon"], {
5669
6130
  detached: true,
5670
- stdio: ["ignore", logFd, logFd]
6131
+ stdio: ["ignore", logFd, logFd],
6132
+ windowsHide: true
5671
6133
  });
5672
6134
  child.once("spawn", () => closeSync2(logFd));
5673
6135
  child.once("error", (error) => {
@@ -5681,10 +6143,10 @@ function spawnDaemonProcess(paths) {
5681
6143
  throw error;
5682
6144
  }
5683
6145
  }
5684
- function resolveDaemonNodeExecutable(cachedExecPath = execPath, originalArgv0 = argv0, pathExists = existsSync11) {
6146
+ function resolveDaemonNodeExecutable(cachedExecPath = execPath, originalArgv0 = argv0, pathExists = existsSync12) {
5685
6147
  if (pathExists(cachedExecPath))
5686
6148
  return cachedExecPath;
5687
- if (isAbsolute4(originalArgv0) && pathExists(originalArgv0))
6149
+ if (isAbsolute5(originalArgv0) && pathExists(originalArgv0))
5688
6150
  return originalArgv0;
5689
6151
  return "node";
5690
6152
  }
@@ -5697,7 +6159,7 @@ function defaultEnsureDaemonDeps() {
5697
6159
  };
5698
6160
  }
5699
6161
  function sleepWithSignal(ms, signal) {
5700
- return new Promise((resolve9) => {
6162
+ return new Promise((resolve10) => {
5701
6163
  let settled = false;
5702
6164
  const finish = () => {
5703
6165
  if (settled)
@@ -5705,7 +6167,7 @@ function sleepWithSignal(ms, signal) {
5705
6167
  settled = true;
5706
6168
  clearTimeout(timer);
5707
6169
  signal?.removeEventListener("abort", finish);
5708
- resolve9();
6170
+ resolve10();
5709
6171
  };
5710
6172
  const timer = setTimeout(finish, ms);
5711
6173
  if (signal?.aborted) {
@@ -5720,7 +6182,7 @@ function awaitWithSignal2(promise, signal) {
5720
6182
  return promise;
5721
6183
  if (signal.aborted)
5722
6184
  return Promise.reject(abortError3(signal));
5723
- return new Promise((resolve9, reject) => {
6185
+ return new Promise((resolve10, reject) => {
5724
6186
  let settled = false;
5725
6187
  const finish = (run) => {
5726
6188
  if (settled)
@@ -5731,7 +6193,7 @@ function awaitWithSignal2(promise, signal) {
5731
6193
  };
5732
6194
  const onAbort = () => finish(() => reject(abortError3(signal)));
5733
6195
  signal.addEventListener("abort", onAbort, { once: true });
5734
- promise.then((value) => finish(() => resolve9(value)), (error) => finish(() => reject(error)));
6196
+ promise.then((value) => finish(() => resolve10(value)), (error) => finish(() => reject(error)));
5735
6197
  });
5736
6198
  }
5737
6199
  function throwIfAborted(signal) {
@@ -5780,7 +6242,10 @@ function parsePingResponse(message) {
5780
6242
  var CONTEXT_KEY = "_context";
5781
6243
 
5782
6244
  class InvalidDaemonRequestError extends Error {
5783
- name = "InvalidDaemonRequestError";
6245
+ constructor() {
6246
+ super(...arguments);
6247
+ this.name = "InvalidDaemonRequestError";
6248
+ }
5784
6249
  }
5785
6250
  function extractRequestContext(raw) {
5786
6251
  if (!isPlainRecord(raw) || raw["method"] !== "tools/call")
@@ -5896,14 +6361,17 @@ async function callToolViaDaemon(name, args, options) {
5896
6361
  function callDiagnosticsViaDaemon(filePath, options) {
5897
6362
  return callToolViaDaemon("diagnostics", { filePath, severity: "error" }, options);
5898
6363
  }
6364
+ function callFormatViaDaemon(filePath, options) {
6365
+ return callToolViaDaemon("format", { filePath }, options);
6366
+ }
5899
6367
  function currentRequestContext(env = process.env) {
5900
6368
  const cwd = process.cwd();
5901
6369
  const home = env["HOME"] ?? homedir3();
5902
6370
  return parseLspRequestContext({
5903
6371
  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"),
6372
+ projectConfigPaths: [join8(cwd, ".codex", "lsp-client.json")],
6373
+ userConfigPath: join8(home, ".codex", "lsp-client.json"),
6374
+ installDecisionsPath: join8(home, ".codex", "lsp-install-decisions.json"),
5907
6375
  capabilities: { installDecisionTool: true }
5908
6376
  });
5909
6377
  }
@@ -5918,7 +6386,7 @@ function withContext(args, context) {
5918
6386
  function ensureDaemonAvailable(paths, ensure, signal) {
5919
6387
  if (!signal)
5920
6388
  return ensure(paths);
5921
- return new Promise((resolve9, reject) => {
6389
+ return new Promise((resolve10, reject) => {
5922
6390
  let settled = false;
5923
6391
  const finish = (run) => {
5924
6392
  if (settled)
@@ -5933,11 +6401,11 @@ function ensureDaemonAvailable(paths, ensure, signal) {
5933
6401
  return;
5934
6402
  }
5935
6403
  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)));
6404
+ Promise.resolve().then(() => ensure(paths, signal)).then(() => finish(() => resolve10()), (error) => finish(() => reject(signal.aborted ? new DaemonRequestCancelledError(false) : error)));
5937
6405
  });
5938
6406
  }
5939
6407
  function sendToolCall(paths, token, name, args, options) {
5940
- return new Promise((resolve9, reject) => {
6408
+ return new Promise((resolve10, reject) => {
5941
6409
  const socket = connect(paths.socket);
5942
6410
  const requestId = allocateProxyRequestId();
5943
6411
  let settled = false;
@@ -5990,7 +6458,7 @@ function sendToolCall(paths, token, name, args, options) {
5990
6458
  }
5991
6459
  const result = toToolResult(message, requestId);
5992
6460
  if (result)
5993
- finish(() => resolve9(result));
6461
+ finish(() => resolve10(result));
5994
6462
  else
5995
6463
  finish(() => reject(new DaemonRequestError("invalid daemon response", requestWritten)));
5996
6464
  });
@@ -6158,18 +6626,18 @@ function canonicalizePathList(value) {
6158
6626
  return value.split(delimiter4).map((entry) => canonicalizePath(entry) ?? entry).join(delimiter4);
6159
6627
  }
6160
6628
  function canonicalizePath(value) {
6161
- if (value === undefined || !isAbsolute5(value) || !existsSync12(value))
6629
+ if (value === undefined || !isAbsolute6(value) || !existsSync13(value))
6162
6630
  return value;
6163
- return realpathSync4(value);
6631
+ return realpathSync6(value);
6164
6632
  }
6165
6633
  function projectRootFromOpenCodeConfigPath(path2) {
6166
- if (basename3(path2) !== "lsp.json" && basename3(path2) !== "lsp-client.json")
6634
+ if (basename4(path2) !== "lsp.json" && basename4(path2) !== "lsp-client.json")
6167
6635
  return;
6168
- const configDir = dirname9(path2);
6169
- const configDirName = basename3(configDir);
6636
+ const configDir = dirname11(path2);
6637
+ const configDirName = basename4(configDir);
6170
6638
  if (configDirName !== ".opencode" && configDirName !== ".omo")
6171
6639
  return;
6172
- return dirname9(configDir);
6640
+ return dirname11(configDir);
6173
6641
  }
6174
6642
 
6175
6643
  // src/daemon-server.ts
@@ -6178,12 +6646,12 @@ import { createServer as createServer2 } from "node:net";
6178
6646
 
6179
6647
  // src/ownership.ts
6180
6648
  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";
6649
+ import { existsSync as existsSync14, lstatSync as lstatSync7, readFileSync as readFileSync8, statSync as statSync5, unlinkSync as unlinkSync4 } from "node:fs";
6650
+ import { dirname as dirname13 } from "node:path";
6183
6651
 
6184
6652
  // 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";
6653
+ import { closeSync as closeSync3, mkdirSync as mkdirSync4, openSync as openSync3, readFileSync as readFileSync7, unlinkSync as unlinkSync3, writeSync as writeSync3 } from "node:fs";
6654
+ import { dirname as dirname12 } from "node:path";
6187
6655
  function isProcessAlive2(pid) {
6188
6656
  if (!Number.isInteger(pid) || pid <= 0)
6189
6657
  return false;
@@ -6198,14 +6666,14 @@ function isProcessAlive2(pid) {
6198
6666
  }
6199
6667
  function readLockPid(lockPath) {
6200
6668
  try {
6201
- const pid = Number.parseInt(readFileSync6(lockPath, "utf8").trim(), 10);
6669
+ const pid = Number.parseInt(readFileSync7(lockPath, "utf8").trim(), 10);
6202
6670
  return Number.isInteger(pid) ? pid : null;
6203
6671
  } catch {
6204
6672
  return null;
6205
6673
  }
6206
6674
  }
6207
6675
  function tryAcquireLock(lockPath, ownerPid = process.pid) {
6208
- mkdirSync4(dirname10(lockPath), { recursive: true });
6676
+ mkdirSync4(dirname12(lockPath), { recursive: true });
6209
6677
  for (let attempt = 0;attempt < 2; attempt += 1) {
6210
6678
  const handle = writeLockFile(lockPath, ownerPid);
6211
6679
  if (handle)
@@ -6237,7 +6705,7 @@ function reapStaleLock(lockPath) {
6237
6705
  }
6238
6706
  function unlinkQuietly(path2) {
6239
6707
  try {
6240
- unlinkSync2(path2);
6708
+ unlinkSync3(path2);
6241
6709
  } catch (error) {
6242
6710
  if (error instanceof Error)
6243
6711
  return;
@@ -6253,17 +6721,19 @@ function errorCode3(error) {
6253
6721
 
6254
6722
  // src/ownership.ts
6255
6723
  class DaemonAlreadyRunningError extends Error {
6256
- name = "DaemonAlreadyRunningError";
6257
- code = "daemon_already_running";
6724
+ constructor() {
6725
+ super(...arguments);
6726
+ this.name = "DaemonAlreadyRunningError";
6727
+ this.code = "daemon_already_running";
6728
+ }
6258
6729
  }
6259
6730
 
6260
6731
  class DaemonStartupDeferredError extends Error {
6261
- reason;
6262
- name = "DaemonStartupDeferredError";
6263
- code = "daemon_startup_deferred";
6264
6732
  constructor(reason) {
6265
6733
  super(`LSP daemon startup deferred: ${reason}`);
6266
6734
  this.reason = reason;
6735
+ this.name = "DaemonStartupDeferredError";
6736
+ this.code = "daemon_startup_deferred";
6267
6737
  }
6268
6738
  }
6269
6739
  async function acquireStartupLease(paths, pingOwner) {
@@ -6286,11 +6756,11 @@ async function acquireStartupLease(paths, pingOwner) {
6286
6756
  function ensureDaemonDirectories(paths) {
6287
6757
  ensurePrivateDirectory(paths.dir);
6288
6758
  if (process.platform !== "win32")
6289
- ensurePrivateDirectory(dirname11(paths.socket));
6759
+ ensurePrivateDirectory(dirname13(paths.socket));
6290
6760
  }
6291
6761
  function readDaemonOwner(paths) {
6292
6762
  try {
6293
- return parseOwner(JSON.parse(readFileSync7(paths.owner, "utf8")));
6763
+ return parseOwner(JSON.parse(readFileSync8(paths.owner, "utf8")));
6294
6764
  } catch (error) {
6295
6765
  if (error instanceof Error)
6296
6766
  return null;
@@ -6366,10 +6836,10 @@ async function validateExistingOwner(paths, pingOwner) {
6366
6836
  throw new DaemonStartupDeferredError("reachable_owner_mismatch");
6367
6837
  }
6368
6838
  function cleanupDeadOwner(paths, owner) {
6369
- if (process.platform !== "win32" && existsSync13(owner.endpoint.path)) {
6839
+ if (process.platform !== "win32" && existsSync14(owner.endpoint.path)) {
6370
6840
  const stat = lstatSync7(owner.endpoint.path);
6371
6841
  if (stat.isSocket())
6372
- unlinkSync3(owner.endpoint.path);
6842
+ unlinkSync4(owner.endpoint.path);
6373
6843
  }
6374
6844
  unlinkQuietly(paths.pid);
6375
6845
  unlinkQuietly(paths.endpoint);
@@ -6417,7 +6887,7 @@ function parseEndpoint(value) {
6417
6887
  // src/version-reap.ts
6418
6888
  import { execFile } from "node:child_process";
6419
6889
  import { readdir, readFile, rm } from "node:fs/promises";
6420
- import { basename as basename4, dirname as dirname12, join as join8 } from "node:path";
6890
+ import { basename as basename5, dirname as dirname14, join as join9 } from "node:path";
6421
6891
  var TERM_GRACE_MS = 5000;
6422
6892
  var KILL_GRACE_MS = 1000;
6423
6893
  var VERSION_ENTRY_PATTERN = /^v([A-Za-z0-9][A-Za-z0-9._+-]{0,127})$/;
@@ -6438,7 +6908,7 @@ async function attestDaemonCliProcess(pid, platform, deps = {}) {
6438
6908
  return isNodeCliDaemonCommand(command.trim());
6439
6909
  }
6440
6910
  async function reapStaleDaemonVersions(ownPaths, deps = {}) {
6441
- const baseDir = dirname12(ownPaths.dir);
6911
+ const baseDir = dirname14(ownPaths.dir);
6442
6912
  const platform = deps.platform ?? process.platform;
6443
6913
  const isAlive = deps.isAlive ?? isProcessAlive2;
6444
6914
  const attest = deps.attest ?? ((pid) => attestDaemonCliProcess(pid, platform));
@@ -6457,7 +6927,7 @@ async function reapStaleDaemonVersions(ownPaths, deps = {}) {
6457
6927
  const version = parseVersionEntry(entry.name);
6458
6928
  if (version === null || !entry.isDirectory())
6459
6929
  continue;
6460
- const versionDir = join8(baseDir, entry.name);
6930
+ const versionDir = join9(baseDir, entry.name);
6461
6931
  const siblingPaths = daemonPaths({ [OMO_LSP_DAEMON_DIR]: baseDir }, { cliPath: ownPaths.cliPath, version });
6462
6932
  results.push(await reapOneVersion({
6463
6933
  version,
@@ -6481,7 +6951,7 @@ async function reapOneVersion(context) {
6481
6951
  const { version, versionDir } = context;
6482
6952
  const owner = context.readOwner(context.siblingPaths);
6483
6953
  if (!owner) {
6484
- const lockPid = readLockPid(join8(versionDir, "daemon.lock"));
6954
+ const lockPid = readLockPid(join9(versionDir, "daemon.lock"));
6485
6955
  if (lockPid !== null && context.isAlive(lockPid)) {
6486
6956
  context.log(`reap: sparing v${version}: owner metadata missing but daemon.lock is held by live pid ${lockPid}`);
6487
6957
  return { version, status: "spared", reason: `owner metadata missing but lock held by live pid ${lockPid}` };
@@ -6547,7 +7017,7 @@ function splitCmdline(buffer) {
6547
7017
  function isNodeCliDaemonArgv(argv) {
6548
7018
  if (argv.length < 2 || !argv.includes("daemon"))
6549
7019
  return false;
6550
- const executable = basename4(argv[0] ?? "");
7020
+ const executable = basename5(argv[0] ?? "");
6551
7021
  if (!/^node(?:\.exe)?$/i.test(executable))
6552
7022
  return false;
6553
7023
  return argv.some((value) => value === "cli.js" || value.endsWith("/cli.js") || value.endsWith("\\cli.js"));
@@ -6559,13 +7029,13 @@ function defaultReadProcFile(path2) {
6559
7029
  return readFile(path2);
6560
7030
  }
6561
7031
  function defaultExecuteForStdout(file, args) {
6562
- return new Promise((resolve9) => {
6563
- execFile(file, [...args], { encoding: "utf8", maxBuffer: 1024 * 1024, timeout: 1000 }, (error, stdout) => {
7032
+ return new Promise((resolve10) => {
7033
+ execFile(file, [...args], { encoding: "utf8", maxBuffer: 1024 * 1024, timeout: 1000, windowsHide: true }, (error, stdout) => {
6564
7034
  if (error !== null) {
6565
- resolve9(null);
7035
+ resolve10(null);
6566
7036
  return;
6567
7037
  }
6568
- resolve9(stdout);
7038
+ resolve10(stdout);
6569
7039
  });
6570
7040
  });
6571
7041
  }
@@ -6584,7 +7054,7 @@ async function defaultWaitForExit(pid, timeoutMs) {
6584
7054
  return true;
6585
7055
  if (Date.now() >= deadline)
6586
7056
  return false;
6587
- await new Promise((resolve9) => setTimeout(resolve9, 100));
7057
+ await new Promise((resolve10) => setTimeout(resolve10, 100));
6588
7058
  }
6589
7059
  }
6590
7060
  function defaultLog(message) {
@@ -6691,17 +7161,17 @@ async function assertSelfProbe(paths, token, owner) {
6691
7161
  throw new DaemonStartupDeferredError("self_probe_failed");
6692
7162
  }
6693
7163
  function listen(server2, socketPath) {
6694
- return new Promise((resolve9, reject) => {
7164
+ return new Promise((resolve10, reject) => {
6695
7165
  const onError = (error) => reject(error);
6696
7166
  server2.once("error", onError);
6697
7167
  server2.listen(socketPath, () => {
6698
7168
  server2.removeListener("error", onError);
6699
- resolve9();
7169
+ resolve10();
6700
7170
  });
6701
7171
  });
6702
7172
  }
6703
7173
  function closeServer(server2) {
6704
- return new Promise((resolve9) => server2.close(() => resolve9()));
7174
+ return new Promise((resolve10) => server2.close(() => resolve10()));
6705
7175
  }
6706
7176
  function installSignalHandlers(close) {
6707
7177
  const handler = () => {