oh-my-opencode 5.0.0-beta.21 → 5.0.0-beta.23

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 (151) hide show
  1. package/dist/cli/index.js +290 -288
  2. package/dist/cli-node/index.js +290 -288
  3. package/dist/index.js +1675 -1657
  4. package/dist/skills/debugging/SKILL.md +2 -0
  5. package/dist/skills/debugging/references/methodology/00-setup.md +12 -0
  6. package/dist/skills/debugging/references/methodology/02-investigate.md +21 -0
  7. package/dist/skills/debugging/references/runtimes/go.md +15 -1
  8. package/dist/skills/debugging/references/runtimes/native-binary.md +38 -0
  9. package/dist/skills/debugging/references/runtimes/node.md +25 -0
  10. package/dist/skills/debugging/references/runtimes/python.md +13 -0
  11. package/dist/skills/debugging/references/runtimes/rust.md +41 -0
  12. package/dist/skills/debugging/references/scripts/dap.mjs +267 -0
  13. package/dist/skills/debugging/references/scripts/dap.test.ts +86 -0
  14. package/dist/skills/debugging/references/scripts/fixture-adapter.mjs +59 -0
  15. package/dist/skills/debugging/references/tools/dap.md +103 -0
  16. package/dist/skills/debugging/references/tools/frida.md +193 -0
  17. package/dist/tools/delegate-task/types.d.ts +3 -0
  18. package/dist/tui.js +131 -147
  19. package/package.json +18 -15
  20. package/packages/lsp-core/src/index.ts +1 -0
  21. package/packages/lsp-core/src/lsp/client-wrapper.ts +25 -5
  22. package/packages/lsp-core/src/lsp/client.ts +26 -0
  23. package/packages/lsp-core/src/lsp/connection.ts +16 -0
  24. package/packages/lsp-core/src/lsp/constants.ts +1 -0
  25. package/packages/lsp-core/src/lsp/format-document.test.ts +143 -0
  26. package/packages/lsp-core/src/lsp/format-document.ts +90 -0
  27. package/packages/lsp-core/src/lsp/manager-max-clients.test.ts +151 -0
  28. package/packages/lsp-core/src/lsp/manager.ts +34 -1
  29. package/packages/lsp-core/src/lsp/server-definitions.ts +29 -0
  30. package/packages/lsp-core/src/lsp/server-installation.test.ts +376 -0
  31. package/packages/lsp-core/src/lsp/server-installation.ts +200 -27
  32. package/packages/lsp-core/src/lsp/server-resolution-local-binary.test.ts +170 -0
  33. package/packages/lsp-core/src/lsp/server-resolution.ts +18 -5
  34. package/packages/lsp-core/src/lsp/transport.ts +9 -0
  35. package/packages/lsp-core/src/lsp/types.ts +8 -0
  36. package/packages/lsp-core/src/tool-surface.test.ts +13 -1
  37. package/packages/lsp-core/src/tools/definitions.ts +14 -0
  38. package/packages/lsp-core/src/tools/format.test.ts +56 -0
  39. package/packages/lsp-core/src/tools/format.ts +56 -0
  40. package/packages/lsp-core/src/tools/index.ts +1 -0
  41. package/packages/lsp-core/src/tools/types.ts +10 -0
  42. package/packages/lsp-daemon/dist/cli.js +432 -144
  43. package/packages/lsp-daemon/dist/client.d.ts +10 -0
  44. package/packages/lsp-daemon/dist/client.js +401 -107
  45. package/packages/lsp-daemon/dist/daemon-client.d.ts +1 -0
  46. package/packages/lsp-daemon/dist/daemon-client.js +3 -0
  47. package/packages/lsp-daemon/dist/index.js +395 -107
  48. package/packages/lsp-daemon/package.json +1 -1
  49. package/packages/lsp-tools-mcp/dist/cli.js +384 -99
  50. package/packages/lsp-tools-mcp/dist/lsp/manager.js +53 -0
  51. package/packages/lsp-tools-mcp/dist/mcp.js +384 -99
  52. package/packages/lsp-tools-mcp/dist/tools.js +385 -99
  53. package/packages/omo-codex/plugin/.codex-plugin/plugin.json +1 -1
  54. package/packages/omo-codex/plugin/components/bootstrap/dist/cli.js +2 -2
  55. package/packages/omo-codex/plugin/components/bootstrap/hooks/hooks.json +1 -1
  56. package/packages/omo-codex/plugin/components/bootstrap/package.json +1 -1
  57. package/packages/omo-codex/plugin/components/codegraph/dist/cli.js +69 -35
  58. package/packages/omo-codex/plugin/components/codegraph/dist/serve.js +21 -2
  59. package/packages/omo-codex/plugin/components/codegraph/package.json +1 -1
  60. package/packages/omo-codex/plugin/components/comment-checker/hooks/hooks.json +1 -1
  61. package/packages/omo-codex/plugin/components/comment-checker/package.json +1 -1
  62. package/packages/omo-codex/plugin/components/git-bash/hooks/hooks.json +2 -2
  63. package/packages/omo-codex/plugin/components/git-bash/package.json +1 -1
  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 +1 -1
  66. package/packages/omo-codex/plugin/components/lsp/dist/.omo-runtime-manifest.json +3 -3
  67. package/packages/omo-codex/plugin/components/lsp/dist/cli.js +404 -121
  68. package/packages/omo-codex/plugin/components/lsp/hooks/hooks.json +2 -2
  69. package/packages/omo-codex/plugin/components/lsp/package.json +1 -1
  70. package/packages/omo-codex/plugin/components/rules/dist/cli.js +3 -3
  71. package/packages/omo-codex/plugin/components/rules/hooks/hooks.json +4 -4
  72. package/packages/omo-codex/plugin/components/rules/package.json +1 -1
  73. package/packages/omo-codex/plugin/components/rules/src/post-compact-budget.ts +3 -3
  74. package/packages/omo-codex/plugin/components/rules/test/post-compact-budget.test.ts +4 -4
  75. package/packages/omo-codex/plugin/components/teammode/hooks/hooks.json +1 -1
  76. package/packages/omo-codex/plugin/components/teammode/package.json +1 -1
  77. package/packages/omo-codex/plugin/components/telemetry/dist/cli.js +30 -15
  78. package/packages/omo-codex/plugin/components/telemetry/dist/posthog.js +30 -15
  79. package/packages/omo-codex/plugin/components/telemetry/hooks/hooks.json +1 -1
  80. package/packages/omo-codex/plugin/components/telemetry/package.json +1 -1
  81. package/packages/omo-codex/plugin/components/ultrawork/hooks/hooks.json +1 -1
  82. package/packages/omo-codex/plugin/components/ultrawork/package.json +1 -1
  83. package/packages/omo-codex/plugin/components/ulw-execute-continuation/hooks/hooks.json +2 -2
  84. package/packages/omo-codex/plugin/components/ulw-execute-continuation/package.json +1 -1
  85. package/packages/omo-codex/plugin/components/ulw-loop/dist/cli-commands.js +5 -1
  86. package/packages/omo-codex/plugin/components/ulw-loop/dist/cli-output.d.ts +2 -1
  87. package/packages/omo-codex/plugin/components/ulw-loop/dist/cli-output.js +11 -1
  88. package/packages/omo-codex/plugin/components/ulw-loop/dist/cli.js +22 -10
  89. package/packages/omo-codex/plugin/components/ulw-loop/hooks/hooks.json +4 -4
  90. package/packages/omo-codex/plugin/components/ulw-loop/package.json +1 -1
  91. package/packages/omo-codex/plugin/components/ulw-loop/src/cli-commands.ts +5 -1
  92. package/packages/omo-codex/plugin/components/ulw-loop/src/cli-output.ts +13 -1
  93. package/packages/omo-codex/plugin/components/ulw-loop/src/cli.ts +3 -5
  94. package/packages/omo-codex/plugin/components/ulw-loop/test/cli-entrypoint.test.ts +26 -2
  95. package/packages/omo-codex/plugin/hooks/post-compact-resetting-git-bash-mcp-reminder.json +1 -1
  96. package/packages/omo-codex/plugin/hooks/post-compact-resetting-lsp-diagnostics-cache.json +1 -1
  97. package/packages/omo-codex/plugin/hooks/post-compact-resetting-project-rule-cache.json +1 -1
  98. package/packages/omo-codex/plugin/hooks/post-tool-use-checking-codegraph-init-guidance.json +1 -1
  99. package/packages/omo-codex/plugin/hooks/post-tool-use-checking-comments.json +1 -1
  100. package/packages/omo-codex/plugin/hooks/post-tool-use-checking-lsp-diagnostics.json +1 -1
  101. package/packages/omo-codex/plugin/hooks/post-tool-use-checking-thread-title-hygiene.json +1 -1
  102. package/packages/omo-codex/plugin/hooks/post-tool-use-matching-project-rules.json +1 -1
  103. package/packages/omo-codex/plugin/hooks/pre-tool-use-enforcing-unlimited-goal-budget.json +1 -1
  104. package/packages/omo-codex/plugin/hooks/pre-tool-use-guarding-ulw-loop-spawns.json +1 -1
  105. package/packages/omo-codex/plugin/hooks/pre-tool-use-recommending-git-bash-mcp.json +1 -1
  106. package/packages/omo-codex/plugin/hooks/session-start-checking-auto-update.json +1 -1
  107. package/packages/omo-codex/plugin/hooks/session-start-checking-bootstrap-provisioning.json +1 -1
  108. package/packages/omo-codex/plugin/hooks/session-start-checking-codegraph-bootstrap.json +1 -1
  109. package/packages/omo-codex/plugin/hooks/session-start-loading-project-rules.json +1 -1
  110. package/packages/omo-codex/plugin/hooks/session-start-recording-session-telemetry.json +1 -1
  111. package/packages/omo-codex/plugin/hooks/stop-checking-ulw-execute-continuation.json +1 -1
  112. package/packages/omo-codex/plugin/hooks/stop-checking-ulw-loop-resume.json +1 -1
  113. package/packages/omo-codex/plugin/hooks/subagent-stop-checking-ulw-execute-continuation.json +1 -1
  114. package/packages/omo-codex/plugin/hooks/subagent-stop-verifying-lazycodex-executor-evidence.json +1 -1
  115. package/packages/omo-codex/plugin/hooks/user-prompt-submit-checking-ultrawork-trigger.json +1 -1
  116. package/packages/omo-codex/plugin/hooks/user-prompt-submit-checking-ulw-loop-steering.json +1 -1
  117. package/packages/omo-codex/plugin/hooks/user-prompt-submit-loading-project-rules.json +1 -1
  118. package/packages/omo-codex/plugin/model-catalog.json +3 -3
  119. package/packages/omo-codex/plugin/package-lock.json +13 -13
  120. package/packages/omo-codex/plugin/package.json +1 -1
  121. package/packages/omo-codex/plugin/scripts/migrate-codex-config/catalog.mjs +3 -3
  122. package/packages/omo-codex/plugin/skills/debugging/SKILL.md +2 -0
  123. package/packages/omo-codex/plugin/skills/debugging/references/methodology/00-setup.md +12 -0
  124. package/packages/omo-codex/plugin/skills/debugging/references/methodology/02-investigate.md +21 -0
  125. package/packages/omo-codex/plugin/skills/debugging/references/runtimes/go.md +15 -1
  126. package/packages/omo-codex/plugin/skills/debugging/references/runtimes/native-binary.md +38 -0
  127. package/packages/omo-codex/plugin/skills/debugging/references/runtimes/node.md +25 -0
  128. package/packages/omo-codex/plugin/skills/debugging/references/runtimes/python.md +13 -0
  129. package/packages/omo-codex/plugin/skills/debugging/references/runtimes/rust.md +41 -0
  130. package/packages/omo-codex/plugin/skills/debugging/references/scripts/dap.mjs +267 -0
  131. package/packages/omo-codex/plugin/skills/debugging/references/scripts/fixture-adapter.mjs +59 -0
  132. package/packages/omo-codex/plugin/skills/debugging/references/tools/dap.md +103 -0
  133. package/packages/omo-codex/plugin/skills/debugging/references/tools/frida.md +193 -0
  134. package/packages/omo-codex/plugin/test/aggregate-model-catalog.test.mjs +1 -1
  135. package/packages/omo-codex/plugin/test/auto-update.test.mjs +2 -2
  136. package/packages/omo-codex/plugin/test/migrate-codex-config.test.mjs +8 -8
  137. package/packages/omo-codex/scripts/install-config-reasoning.test.mjs +2 -2
  138. package/packages/omo-codex/scripts/install-dist/install-local.mjs +38 -23
  139. package/packages/shared-skills/skills/debugging/SKILL.md +2 -0
  140. package/packages/shared-skills/skills/debugging/references/methodology/00-setup.md +12 -0
  141. package/packages/shared-skills/skills/debugging/references/methodology/02-investigate.md +21 -0
  142. package/packages/shared-skills/skills/debugging/references/runtimes/go.md +15 -1
  143. package/packages/shared-skills/skills/debugging/references/runtimes/native-binary.md +38 -0
  144. package/packages/shared-skills/skills/debugging/references/runtimes/node.md +25 -0
  145. package/packages/shared-skills/skills/debugging/references/runtimes/python.md +13 -0
  146. package/packages/shared-skills/skills/debugging/references/runtimes/rust.md +41 -0
  147. package/packages/shared-skills/skills/debugging/references/scripts/dap.mjs +267 -0
  148. package/packages/shared-skills/skills/debugging/references/scripts/dap.test.ts +86 -0
  149. package/packages/shared-skills/skills/debugging/references/scripts/fixture-adapter.mjs +59 -0
  150. package/packages/shared-skills/skills/debugging/references/tools/dap.md +103 -0
  151. package/packages/shared-skills/skills/debugging/references/tools/frida.md +193 -0
@@ -1,3 +1,7 @@
1
+ // src/client.ts
2
+ import { statSync as statSync5 } from "node:fs";
3
+ import { isAbsolute as isAbsolute6 } from "node:path";
4
+
1
5
  // src/daemon-client.ts
2
6
  import { connect } from "node:net";
3
7
  import { homedir as homedir3 } from "node:os";
@@ -1139,7 +1143,7 @@ function createIdleTimer(idleTimeoutMs, log, onTimeout) {
1139
1143
  }
1140
1144
  // ../lsp-core/src/lsp/client-wrapper.ts
1141
1145
  import { existsSync as existsSync11, realpathSync as realpathSync5, statSync as statSync4 } from "node:fs";
1142
- import { basename as basename3, dirname as dirname9, join as join5, resolve as resolve7 } from "node:path";
1146
+ import { basename as basename3, dirname as dirname10, join as join5, resolve as resolve8 } from "node:path";
1143
1147
 
1144
1148
  // ../lsp-core/src/lsp/effective-extension.ts
1145
1149
  import { basename as basename2, extname } from "node:path";
@@ -1243,6 +1247,7 @@ var DEFAULT_MAX_DIRECTORY_FILES = 50;
1243
1247
  var REQUEST_TIMEOUT_MS = 15000;
1244
1248
  var INIT_TIMEOUT_MS = 60000;
1245
1249
  var IDLE_TIMEOUT_MS = 5 * 60000;
1250
+ var MAX_RESIDENT_CLIENTS = 6;
1246
1251
  var REAPER_INTERVAL_MS = 60000;
1247
1252
  var STOP_HARD_KILL_TIMEOUT_MS = 5000;
1248
1253
  var STOP_SIGKILL_GRACE_MS = 1000;
@@ -1768,6 +1773,7 @@ class LspClientTransport {
1768
1773
  this.diagnosticsStore = new Map;
1769
1774
  this.workspaceApplyEditHandler = null;
1770
1775
  this.diagnosticPullSupported = false;
1776
+ this.documentFormattingSupported = false;
1771
1777
  this.requestTimeoutMs = timeouts.requestTimeoutMs ?? REQUEST_TIMEOUT_MS;
1772
1778
  this.initializeTimeoutMs = timeouts.initializeTimeoutMs ?? INIT_TIMEOUT_MS;
1773
1779
  }
@@ -1789,6 +1795,12 @@ class LspClientTransport {
1789
1795
  isDiagnosticPullSupported() {
1790
1796
  return this.diagnosticPullSupported;
1791
1797
  }
1798
+ setDocumentFormattingSupported(supported) {
1799
+ this.documentFormattingSupported = supported;
1800
+ }
1801
+ isDocumentFormattingSupported() {
1802
+ return this.documentFormattingSupported;
1803
+ }
1792
1804
  handlePublishDiagnostics(params) {
1793
1805
  this.diagnosticsStore.set(params.uri, [...params.diagnostics]);
1794
1806
  }
@@ -2002,6 +2014,14 @@ function supportsDiagnosticPull(capabilities) {
2002
2014
  return false;
2003
2015
  return Object.hasOwn(capabilities, "diagnosticProvider");
2004
2016
  }
2017
+ function supportsDocumentFormatting(capabilities) {
2018
+ if (capabilities === undefined)
2019
+ return false;
2020
+ const provider = capabilities.documentFormattingProvider;
2021
+ if (provider === undefined || provider === null || provider === false)
2022
+ return false;
2023
+ return provider === true || typeof provider === "object";
2024
+ }
2005
2025
 
2006
2026
  class LspClientConnection extends LspClientTransport {
2007
2027
  async initialize() {
@@ -2018,6 +2038,7 @@ class LspClientConnection extends LspClientTransport {
2018
2038
  references: {},
2019
2039
  documentSymbol: { hierarchicalDocumentSymbolSupport: true },
2020
2040
  publishDiagnostics: {},
2041
+ formatting: { dynamicRegistration: false },
2021
2042
  rename: {
2022
2043
  prepareSupport: true,
2023
2044
  prepareSupportDefaultBehavior: 1
@@ -2059,6 +2080,7 @@ class LspClientConnection extends LspClientTransport {
2059
2080
  initializationOptions: this.server.initialization
2060
2081
  }, { timeoutMs: this.initializeTimeoutMs });
2061
2082
  this.setDiagnosticPullSupported(supportsDiagnosticPull(result?.capabilities));
2083
+ this.setDocumentFormattingSupported(supportsDocumentFormatting(result?.capabilities));
2062
2084
  await this.sendNotification("initialized", {});
2063
2085
  await this.sendNotification("workspace/didChangeConfiguration", {
2064
2086
  settings: { json: { validate: { enable: true } } }
@@ -3643,6 +3665,18 @@ class LspClient extends LspClientConnection {
3643
3665
  textDocument: { uri: pathToFileURL3(absPath).href }
3644
3666
  }, options);
3645
3667
  }
3668
+ async formatDocument(filePath, options, signal) {
3669
+ if (!this.isDocumentFormattingSupported())
3670
+ return null;
3671
+ const absPath = this.resolveWorkspacePath(filePath);
3672
+ await this.openFile(absPath);
3673
+ const requestOptions = signal === undefined ? {} : { signal };
3674
+ const edits = await this.sendRequest("textDocument/formatting", {
3675
+ textDocument: { uri: pathToFileURL3(absPath).href },
3676
+ options
3677
+ }, requestOptions);
3678
+ return edits ?? [];
3679
+ }
3646
3680
  async workspaceSymbols(query, signal) {
3647
3681
  const options = signal === undefined ? {} : { signal };
3648
3682
  return this.sendRequest("workspace/symbol", { query }, options);
@@ -3895,6 +3929,7 @@ class LspManager {
3895
3929
  this.disposed = false;
3896
3930
  this.idleTimeoutMs = options.idleTimeoutMs ?? IDLE_TIMEOUT_MS;
3897
3931
  this.initTimeoutMs = options.initTimeoutMs ?? INIT_TIMEOUT_MS;
3932
+ this.maxResidentClients = options.maxResidentClients ?? MAX_RESIDENT_CLIENTS;
3898
3933
  this.reaperIntervalMs = options.reaperIntervalMs ?? REAPER_INTERVAL_MS;
3899
3934
  this.clientFactory = options.clientFactory ?? ((root, server2) => new LspClient(root, server2));
3900
3935
  this.now = options.now ?? (() => Date.now());
@@ -3928,6 +3963,26 @@ class LspManager {
3928
3963
  }
3929
3964
  }
3930
3965
  }
3966
+ evictForAdmission() {
3967
+ while (this.clients.size >= this.maxResidentClients) {
3968
+ const victim = this.leastRecentlyUsedIdleClient();
3969
+ if (!victim)
3970
+ return;
3971
+ this.clients.delete(victim.key);
3972
+ stopClientBestEffort(victim.managed.client);
3973
+ }
3974
+ }
3975
+ leastRecentlyUsedIdleClient() {
3976
+ let candidate = null;
3977
+ for (const [key, managed] of this.clients) {
3978
+ if (managed.refCount > 0 || managed.pendingWaiters > 0 || managed.isInitializing)
3979
+ continue;
3980
+ if (candidate === null || managed.lastUsedAt < candidate.managed.lastUsedAt) {
3981
+ candidate = { key, managed };
3982
+ }
3983
+ }
3984
+ return candidate;
3985
+ }
3931
3986
  async tryDeleteIfOrphaned(key, managed) {
3932
3987
  if (managed.refCount === 0 && managed.pendingWaiters === 0 && !managed.isInitializing && this.clients.get(key) === managed) {
3933
3988
  this.clients.delete(key);
@@ -3974,6 +4029,7 @@ class LspManager {
3974
4029
  managed.lastUsedAt = this.now();
3975
4030
  return managed.client;
3976
4031
  }
4032
+ this.evictForAdmission();
3977
4033
  const client = this.clientFactory(root, server2);
3978
4034
  const initStartedAt = this.now();
3979
4035
  const initPromise = (async () => {
@@ -4036,6 +4092,7 @@ class LspManager {
4036
4092
  const key = this.getKey(root, server2.id);
4037
4093
  if (this.clients.has(key))
4038
4094
  return;
4095
+ this.evictForAdmission();
4039
4096
  const client = this.clientFactory(root, server2);
4040
4097
  const initStartedAt = this.now();
4041
4098
  const initPromise = (async () => {
@@ -4161,57 +4218,6 @@ function nearestExistingAncestor(directory) {
4161
4218
  return current;
4162
4219
  }
4163
4220
 
4164
- // ../lsp-core/src/lsp/server-install-state.ts
4165
- import { existsSync as existsSync8, mkdirSync as mkdirSync3, readFileSync as readFileSync4, renameSync as renameSync2, writeFileSync as writeFileSync2 } from "node:fs";
4166
- import { dirname as dirname8 } from "node:path";
4167
- function getInstallDecisionsPath() {
4168
- return lspRequestContext().installDecisionsPath;
4169
- }
4170
- function loadInstallDecisions() {
4171
- const path2 = getInstallDecisionsPath();
4172
- if (!existsSync8(path2))
4173
- return {};
4174
- try {
4175
- const parsed = JSON.parse(readFileSync4(path2, "utf8"));
4176
- return isInstallDecisions(parsed) ? parsed : {};
4177
- } catch {
4178
- return {};
4179
- }
4180
- }
4181
- function loadInstallDecision(serverId) {
4182
- return loadInstallDecisions()[serverId];
4183
- }
4184
- function recordInstallDecision(serverId, decision, decidedAt = new Date().toISOString()) {
4185
- const decisions = loadInstallDecisions();
4186
- decisions[serverId] = { decision, decidedAt };
4187
- writeInstallDecisions(decisions);
4188
- }
4189
- function isInstallDecision(value) {
4190
- return value === "declined" || value === "allowed";
4191
- }
4192
- function writeInstallDecisions(decisions) {
4193
- const path2 = getInstallDecisionsPath();
4194
- mkdirSync3(dirname8(path2), { recursive: true });
4195
- const tmpPath = `${path2}.tmp`;
4196
- writeFileSync2(tmpPath, `${JSON.stringify(decisions, null, 2)}
4197
- `, "utf8");
4198
- renameSync2(tmpPath, path2);
4199
- }
4200
- function isInstallDecisions(value) {
4201
- return isRecord5(value) && Object.values(value).every(isInstallDecisionRecord);
4202
- }
4203
- function isInstallDecisionRecord(value) {
4204
- if (!isRecord5(value))
4205
- return false;
4206
- return isInstallDecision(value["decision"]) && typeof value["decidedAt"] === "string";
4207
- }
4208
- function isRecord5(value) {
4209
- return typeof value === "object" && value !== null && !Array.isArray(value);
4210
- }
4211
-
4212
- // ../lsp-core/src/lsp/config-loader.ts
4213
- import { existsSync as existsSync9, readFileSync as readFileSync5 } from "node:fs";
4214
-
4215
4221
  // ../lsp-core/src/lsp/server-definitions.ts
4216
4222
  var LSP_INSTALL_HINTS = {
4217
4223
  typescript: "npm install -g typescript-language-server typescript",
@@ -4257,6 +4263,26 @@ var LSP_INSTALL_HINTS = {
4257
4263
  julials: `julia -e 'using Pkg; Pkg.add("LanguageServer")'`,
4258
4264
  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"
4259
4265
  };
4266
+ var LSP_LOCAL_INSTALL_HINTS = {
4267
+ typescript: "bun add -d typescript-language-server typescript",
4268
+ vue: "bun add -d @vue/language-server",
4269
+ eslint: "bun add -d vscode-langservers-extracted",
4270
+ oxlint: "bun add -d oxlint",
4271
+ biome: "bun add -d @biomejs/biome",
4272
+ svelte: "bun add -d svelte-language-server",
4273
+ astro: "bun add -d @astrojs/language-server",
4274
+ bash: "bun add -d bash-language-server",
4275
+ "bash-ls": "bun add -d bash-language-server",
4276
+ "yaml-ls": "bun add -d yaml-language-server",
4277
+ php: "bun add -d intelephense",
4278
+ prisma: "bun add -d prisma",
4279
+ dockerfile: "bun add -d dockerfile-language-server-nodejs",
4280
+ pyright: "uv add --dev pyright",
4281
+ basedpyright: "uv add --dev basedpyright",
4282
+ ruff: "uv add --dev ruff",
4283
+ ty: "uv add --dev ty",
4284
+ "ruby-lsp": "bundle add ruby-lsp --group development"
4285
+ };
4260
4286
  var BUILTIN_SERVERS = {
4261
4287
  typescript: {
4262
4288
  command: ["typescript-language-server", "--stdio"],
@@ -4359,7 +4385,56 @@ var BUILTIN_SERVERS = {
4359
4385
  }
4360
4386
  };
4361
4387
 
4388
+ // ../lsp-core/src/lsp/server-install-state.ts
4389
+ import { existsSync as existsSync8, mkdirSync as mkdirSync3, readFileSync as readFileSync4, renameSync as renameSync2, writeFileSync as writeFileSync2 } from "node:fs";
4390
+ import { dirname as dirname8 } from "node:path";
4391
+ function getInstallDecisionsPath() {
4392
+ return lspRequestContext().installDecisionsPath;
4393
+ }
4394
+ function loadInstallDecisions() {
4395
+ const path2 = getInstallDecisionsPath();
4396
+ if (!existsSync8(path2))
4397
+ return {};
4398
+ try {
4399
+ const parsed = JSON.parse(readFileSync4(path2, "utf8"));
4400
+ return isInstallDecisions(parsed) ? parsed : {};
4401
+ } catch {
4402
+ return {};
4403
+ }
4404
+ }
4405
+ function loadInstallDecision(serverId) {
4406
+ return loadInstallDecisions()[serverId];
4407
+ }
4408
+ function recordInstallDecision(serverId, decision, decidedAt = new Date().toISOString()) {
4409
+ const decisions = loadInstallDecisions();
4410
+ decisions[serverId] = { decision, decidedAt };
4411
+ writeInstallDecisions(decisions);
4412
+ }
4413
+ function isInstallDecision(value) {
4414
+ return value === "declined" || value === "allowed";
4415
+ }
4416
+ function writeInstallDecisions(decisions) {
4417
+ const path2 = getInstallDecisionsPath();
4418
+ mkdirSync3(dirname8(path2), { recursive: true });
4419
+ const tmpPath = `${path2}.tmp`;
4420
+ writeFileSync2(tmpPath, `${JSON.stringify(decisions, null, 2)}
4421
+ `, "utf8");
4422
+ renameSync2(tmpPath, path2);
4423
+ }
4424
+ function isInstallDecisions(value) {
4425
+ return isRecord5(value) && Object.values(value).every(isInstallDecisionRecord);
4426
+ }
4427
+ function isInstallDecisionRecord(value) {
4428
+ if (!isRecord5(value))
4429
+ return false;
4430
+ return isInstallDecision(value["decision"]) && typeof value["decidedAt"] === "string";
4431
+ }
4432
+ function isRecord5(value) {
4433
+ return typeof value === "object" && value !== null && !Array.isArray(value);
4434
+ }
4435
+
4362
4436
  // ../lsp-core/src/lsp/config-loader.ts
4437
+ import { existsSync as existsSync9, readFileSync as readFileSync5 } from "node:fs";
4363
4438
  function getProjectConfigPaths() {
4364
4439
  return lspRequestContext().projectConfigPaths;
4365
4440
  }
@@ -4556,53 +4631,154 @@ function getDisabledServerIds() {
4556
4631
 
4557
4632
  // ../lsp-core/src/lsp/server-installation.ts
4558
4633
  import { existsSync as existsSync10 } from "node:fs";
4559
- import { delimiter as delimiter3, join as join4 } from "node:path";
4560
- function isServerInstalled(command, _workingDirectory) {
4561
- if (command.length === 0)
4562
- return false;
4563
- const [cmd] = command;
4564
- if (!cmd)
4565
- return false;
4566
- if (cmd.includes("/") || cmd.includes("\\")) {
4567
- if (existsSync10(cmd))
4568
- return true;
4634
+ import { delimiter as delimiter3, dirname as dirname9, isAbsolute as isAbsolute5, join as join4, resolve as resolve7 } from "node:path";
4635
+ var LOCAL_BIN_RULES = [
4636
+ {
4637
+ markers: ["package.json", "bun.lock", "bun.lockb", "package-lock.json", "yarn.lock", "pnpm-lock.yaml"],
4638
+ binDirs: [join4("node_modules", ".bin")]
4639
+ },
4640
+ {
4641
+ markers: [
4642
+ "pyproject.toml",
4643
+ "ty.toml",
4644
+ "requirements.txt",
4645
+ "setup.py",
4646
+ "setup.cfg",
4647
+ "Pipfile",
4648
+ "pyrightconfig.json",
4649
+ "ruff.toml",
4650
+ ".ruff.toml"
4651
+ ],
4652
+ binDirs: [
4653
+ join4(".venv", "bin"),
4654
+ join4(".venv", "Scripts"),
4655
+ join4("venv", "bin"),
4656
+ join4("venv", "Scripts"),
4657
+ join4(".env", "bin"),
4658
+ join4(".env", "Scripts")
4659
+ ]
4660
+ },
4661
+ {
4662
+ markers: ["Gemfile", "Gemfile.lock"],
4663
+ binDirs: [join4("vendor", "bundle", "bin"), "bin"]
4664
+ },
4665
+ {
4666
+ markers: ["go.mod", "go.sum", "go.work"],
4667
+ binDirs: ["bin"]
4569
4668
  }
4570
- const isWindows = process.platform === "win32";
4571
- let exts = [""];
4572
- if (isWindows) {
4573
- const pathExt = process.env["PATHEXT"] ?? "";
4574
- if (pathExt) {
4575
- const systemExts = pathExt.split(";").filter(Boolean);
4576
- exts = [...new Set([...exts, ...systemExts, ".exe", ".cmd", ".bat", ".ps1"])];
4577
- } else {
4578
- exts = ["", ".exe", ".cmd", ".bat", ".ps1"];
4669
+ ];
4670
+ var resolutionCache = new Map;
4671
+ var probeCount = 0;
4672
+ function probe(path2) {
4673
+ probeCount += 1;
4674
+ return existsSync10(path2);
4675
+ }
4676
+ function executableSuffixes(platform, pathExt) {
4677
+ if (platform !== "win32")
4678
+ return [""];
4679
+ const configured = pathExt ?? process.env["PATHEXT"] ?? "";
4680
+ const systemExts = configured.split(";").filter((entry) => entry.length > 0).map((entry) => entry.toLowerCase());
4681
+ return [...new Set(["", ...systemExts, ".exe", ".cmd", ".bat", ".ps1"])];
4682
+ }
4683
+ function probeWithSuffixes(directory, command, suffixes) {
4684
+ for (const suffix of suffixes) {
4685
+ const candidate = join4(directory, command + suffix);
4686
+ if (probe(candidate))
4687
+ return candidate;
4688
+ }
4689
+ return null;
4690
+ }
4691
+ function resolveLocal(command, workingDirectory, suffixes, stopAt) {
4692
+ const boundary = stopAt === undefined ? undefined : resolve7(stopAt);
4693
+ let current = resolve7(workingDirectory);
4694
+ while (true) {
4695
+ for (const rule of LOCAL_BIN_RULES) {
4696
+ if (!rule.markers.some((marker) => probe(join4(current, marker))))
4697
+ continue;
4698
+ for (const binDir of rule.binDirs) {
4699
+ const found = probeWithSuffixes(join4(current, binDir), command, suffixes);
4700
+ if (found !== null)
4701
+ return found;
4702
+ }
4579
4703
  }
4704
+ if (probe(join4(current, ".git")))
4705
+ return null;
4706
+ if (boundary !== undefined && current === boundary)
4707
+ return null;
4708
+ const parent = dirname9(current);
4709
+ if (parent === current)
4710
+ return null;
4711
+ current = parent;
4580
4712
  }
4581
- let pathEnv = process.env["PATH"] ?? "";
4582
- if (isWindows && !pathEnv) {
4713
+ }
4714
+ function resolveFromPath(command, suffixes, platform, pathEnvOverride) {
4715
+ let pathEnv = pathEnvOverride ?? process.env["PATH"] ?? "";
4716
+ if (platform === "win32" && !pathEnv) {
4583
4717
  pathEnv = process.env["Path"] ?? "";
4584
4718
  }
4585
- const paths = pathEnv.split(delimiter3);
4586
- for (const p of paths) {
4587
- for (const suffix of exts) {
4588
- if (existsSync10(join4(p, cmd + suffix))) {
4589
- return true;
4590
- }
4591
- }
4719
+ for (const entry of pathEnv.split(delimiter3)) {
4720
+ if (entry.length === 0)
4721
+ continue;
4722
+ const found = probeWithSuffixes(entry, command, suffixes);
4723
+ if (found !== null)
4724
+ return found;
4592
4725
  }
4593
- if (cmd === "node")
4594
- return true;
4595
- return false;
4726
+ return null;
4727
+ }
4728
+ function resolveServerBinary(command, workingDirectory, options = {}) {
4729
+ if (command.length === 0)
4730
+ return null;
4731
+ const [cmd] = command;
4732
+ if (cmd === undefined || cmd.length === 0)
4733
+ return null;
4734
+ const platform = options.platform ?? process.platform;
4735
+ const suffixes = executableSuffixes(platform, options.pathExt);
4736
+ if (cmd.includes("/") || cmd.includes("\\")) {
4737
+ const explicit = isAbsolute5(cmd) ? cmd : resolve7(workingDirectory ?? process.cwd(), cmd);
4738
+ return probe(explicit) ? explicit : null;
4739
+ }
4740
+ const cacheKey = JSON.stringify([
4741
+ workingDirectory ?? "",
4742
+ cmd,
4743
+ platform,
4744
+ options.stopAt ?? "",
4745
+ options.pathExt ?? "",
4746
+ options.pathEnv ?? process.env["PATH"] ?? ""
4747
+ ]);
4748
+ const cached = resolutionCache.get(cacheKey);
4749
+ if (cached !== undefined)
4750
+ return cached;
4751
+ let resolved = null;
4752
+ if (workingDirectory !== undefined && workingDirectory.length > 0) {
4753
+ resolved = resolveLocal(cmd, workingDirectory, suffixes, options.stopAt);
4754
+ }
4755
+ resolved ??= resolveFromPath(cmd, suffixes, platform, options.pathEnv);
4756
+ if (resolved === null && cmd === "node")
4757
+ resolved = cmd;
4758
+ resolutionCache.set(cacheKey, resolved);
4759
+ return resolved;
4760
+ }
4761
+ function isServerInstalled(command, workingDirectory, options = {}) {
4762
+ if (command.length === 0)
4763
+ return false;
4764
+ return resolveServerBinary(command, workingDirectory, options) !== null;
4596
4765
  }
4597
4766
 
4598
4767
  // ../lsp-core/src/lsp/server-resolution.ts
4768
+ function withResolvedCommand(command, binaryPath) {
4769
+ return [binaryPath, ...command.slice(1)];
4770
+ }
4599
4771
  function findServerForExtension(ext) {
4600
4772
  const servers = getMergedServers();
4773
+ const workingDirectory = contextCwd();
4601
4774
  for (const server2 of servers) {
4602
- if (server2.extensions.includes(ext) && isServerInstalled(server2.command)) {
4775
+ if (!server2.extensions.includes(ext))
4776
+ continue;
4777
+ const binaryPath = resolveServerBinary(server2.command, workingDirectory);
4778
+ if (binaryPath !== null) {
4603
4779
  const resolvedServer = {
4604
4780
  id: server2.id,
4605
- command: server2.command,
4781
+ command: withResolvedCommand(server2.command, binaryPath),
4606
4782
  extensions: server2.extensions,
4607
4783
  priority: server2.priority
4608
4784
  };
@@ -4649,6 +4825,7 @@ function findServerForExtension(ext) {
4649
4825
  function getAllServers() {
4650
4826
  const servers = getMergedServers();
4651
4827
  const disabled = getDisabledServerIds();
4828
+ const workingDirectory = contextCwd();
4652
4829
  const result = [];
4653
4830
  const seen = new Set;
4654
4831
  for (const server2 of servers) {
@@ -4656,7 +4833,7 @@ function getAllServers() {
4656
4833
  continue;
4657
4834
  result.push({
4658
4835
  id: server2.id,
4659
- installed: isServerInstalled(server2.command),
4836
+ installed: isServerInstalled(server2.command, workingDirectory),
4660
4837
  extensions: server2.extensions,
4661
4838
  disabled: false,
4662
4839
  source: server2.source,
@@ -4670,7 +4847,7 @@ function getAllServers() {
4670
4847
  const builtin = BUILTIN_SERVERS[id];
4671
4848
  result.push({
4672
4849
  id,
4673
- installed: builtin ? isServerInstalled(builtin.command) : false,
4850
+ installed: builtin ? isServerInstalled(builtin.command, workingDirectory) : false,
4674
4851
  extensions: builtin?.extensions ?? [],
4675
4852
  disabled: true,
4676
4853
  source: "disabled",
@@ -4693,7 +4870,7 @@ function findWorkspaceRoot(filePath) {
4693
4870
  const abs = resolveReadablePathInsideContext(filePath);
4694
4871
  let dir = abs;
4695
4872
  if (!isDirectoryPath(dir)) {
4696
- dir = dirname9(dir);
4873
+ dir = dirname10(dir);
4697
4874
  }
4698
4875
  if (!isPathInside(cwd, abs))
4699
4876
  return findWorkspaceRootOutsideContext(dir);
@@ -4709,13 +4886,13 @@ function findWorkspaceRoot(filePath) {
4709
4886
  }
4710
4887
  if (dir === cwd)
4711
4888
  break;
4712
- dir = dirname9(dir);
4889
+ dir = dirname10(dir);
4713
4890
  }
4714
4891
  return fallbackRoot;
4715
4892
  }
4716
4893
  function resolveReadablePathInsideContext(filePath) {
4717
4894
  const cwd = contextCwd();
4718
- const abs = resolve7(cwd, filePath);
4895
+ const abs = resolve8(cwd, filePath);
4719
4896
  if (isPathInside(cwd, abs))
4720
4897
  return abs;
4721
4898
  const rebased = rebaseThroughCanonicalAncestor(abs, cwd);
@@ -4741,7 +4918,7 @@ function rebaseThroughCanonicalAncestor(path2, cwd) {
4741
4918
  if (isPathInside(cwd, canonical))
4742
4919
  return suffix.length === 0 ? canonical : join5(canonical, ...suffix);
4743
4920
  }
4744
- const parent = dirname9(current);
4921
+ const parent = dirname10(current);
4745
4922
  if (parent === current)
4746
4923
  return;
4747
4924
  suffix.unshift(basename3(current));
@@ -4764,7 +4941,7 @@ function nearestExistingDirectoryInsideContext(directory, cwd) {
4764
4941
  return canonical;
4765
4942
  if (current === cwd)
4766
4943
  return;
4767
- current = dirname9(current);
4944
+ current = dirname10(current);
4768
4945
  }
4769
4946
  return;
4770
4947
  }
@@ -4791,6 +4968,19 @@ function formatServerLookupError(result) {
4791
4968
  ].join(`
4792
4969
  `);
4793
4970
  }
4971
+ function formatInstallOptions(serverId, installHint) {
4972
+ const localHint = LSP_LOCAL_INSTALL_HINTS[serverId];
4973
+ if (localHint === undefined) {
4974
+ return ["To install, run:", ` ${installHint}`];
4975
+ }
4976
+ return [
4977
+ "To install in THIS repository (preferred — no global install needed):",
4978
+ ` ${localHint}`,
4979
+ "",
4980
+ "Or install it globally:",
4981
+ ` ${installHint}`
4982
+ ];
4983
+ }
4794
4984
  function formatNotInstalled(result) {
4795
4985
  const { server: server2, installHint } = result;
4796
4986
  const extensions = server2.extensions.join(", ");
@@ -4805,19 +4995,19 @@ function formatNotInstalled(result) {
4805
4995
  `Command not found: ${server2.command[0]}`,
4806
4996
  ""
4807
4997
  ];
4998
+ const installOptions = formatInstallOptions(server2.id, installHint);
4808
4999
  if (decision === "allowed") {
4809
5000
  return [
4810
5001
  ...header,
4811
5002
  "The user has pre-authorized LSP installation. Run the install command, then retry this tool:",
4812
- ` ${installHint}`
5003
+ ...installOptions.slice(1)
4813
5004
  ].join(`
4814
5005
  `);
4815
5006
  }
4816
5007
  if (!context.capabilities.installDecisionTool) {
4817
5008
  return [
4818
5009
  ...header,
4819
- "To install, run:",
4820
- ` ${installHint}`,
5010
+ ...installOptions,
4821
5011
  "",
4822
5012
  "ACTION REQUIRED — ASK THE USER whether to install this LSP server.",
4823
5013
  "Install-decision recording is unavailable in this harness; proceed without LSP if the user declines."
@@ -4826,8 +5016,7 @@ function formatNotInstalled(result) {
4826
5016
  }
4827
5017
  return [
4828
5018
  ...header,
4829
- "To install, run:",
4830
- ` ${installHint}`,
5019
+ ...installOptions,
4831
5020
  "",
4832
5021
  "ACTION REQUIRED — ASK THE USER whether to install this LSP server.",
4833
5022
  "- If the user agrees: run the install command above, then retry this tool.",
@@ -4883,7 +5072,7 @@ async function withLspClient(filePath, fn, toolName, options = {}) {
4883
5072
 
4884
5073
  // ../lsp-core/src/lsp/directory-diagnostics.ts
4885
5074
  import { existsSync as existsSync12, lstatSync as lstatSync5, readdirSync as readdirSync3 } from "node:fs";
4886
- import { join as join6, resolve as resolve8 } from "node:path";
5075
+ import { join as join6, resolve as resolve9 } from "node:path";
4887
5076
 
4888
5077
  // ../lsp-core/src/lsp/formatters.ts
4889
5078
  import { fileURLToPath as fileURLToPath3 } from "node:url";
@@ -5038,7 +5227,7 @@ async function aggregateDiagnosticsForDirectory(directory, extension, severity,
5038
5227
  if (!extension.startsWith(".")) {
5039
5228
  throw new LspInvalidPathError(`Extension must start with a dot (e.g., ".ts", not "${extension}"). Use ".${extension}" instead.`);
5040
5229
  }
5041
- const absDir = resolve8(options.workspaceRoot ?? contextCwd(), directory);
5230
+ const absDir = resolve9(options.workspaceRoot ?? contextCwd(), directory);
5042
5231
  if (!existsSync12(absDir)) {
5043
5232
  throw new LspInvalidPathError(`Directory does not exist: ${absDir}`);
5044
5233
  }
@@ -5395,6 +5584,96 @@ async function executeLspDiagnostics(params, signal) {
5395
5584
  throw error;
5396
5585
  }
5397
5586
  }
5587
+ // ../lsp-core/src/lsp/format-document.ts
5588
+ import { readFileSync as readFileSync6, renameSync as renameSync3, unlinkSync as unlinkSync2, writeFileSync as writeFileSync3 } from "node:fs";
5589
+ var DEFAULT_FORMATTING_OPTIONS = {
5590
+ tabSize: 4,
5591
+ insertSpaces: false,
5592
+ trimTrailingWhitespace: true,
5593
+ insertFinalNewline: true,
5594
+ trimFinalNewlines: true
5595
+ };
5596
+ var UNCHANGED = { status: "unchanged", linesAdded: 0, linesRemoved: 0 };
5597
+ async function formatDocumentWithClient(client, filePath, options = {}) {
5598
+ const edits = await client.formatDocument(filePath, options.formattingOptions ?? DEFAULT_FORMATTING_OPTIONS, options.signal);
5599
+ if (edits === null)
5600
+ return { status: "unavailable", reason: "capability_not_advertised" };
5601
+ if (edits.length === 0)
5602
+ return UNCHANGED;
5603
+ const before = readFileSync6(filePath, "utf-8");
5604
+ const normalized = normalizeTextEdits(before, edits, 0);
5605
+ if (normalized.text === before)
5606
+ return UNCHANGED;
5607
+ writeAtomically(filePath, normalized.text);
5608
+ await client.openFile(filePath);
5609
+ return {
5610
+ status: "formatted",
5611
+ ...lineDelta(normalized.edits)
5612
+ };
5613
+ }
5614
+ function lineDelta(edits) {
5615
+ let linesAdded = 0;
5616
+ let linesRemoved = 0;
5617
+ for (const edit of edits) {
5618
+ linesRemoved += edit.range.end.line - edit.range.start.line + 1;
5619
+ linesAdded += edit.newText.split(`
5620
+ `).length;
5621
+ }
5622
+ return { linesAdded, linesRemoved };
5623
+ }
5624
+ function writeAtomically(filePath, content) {
5625
+ const tempPath = `${filePath}.omo-format.tmp`;
5626
+ writeFileSync3(tempPath, content, "utf-8");
5627
+ try {
5628
+ renameSync3(tempPath, filePath);
5629
+ } catch (error) {
5630
+ try {
5631
+ unlinkSync2(tempPath);
5632
+ } catch {}
5633
+ throw error;
5634
+ }
5635
+ }
5636
+
5637
+ // ../lsp-core/src/tools/format.ts
5638
+ async function executeLspFormat(params, signal) {
5639
+ const filePath = requireString(params, "filePath");
5640
+ try {
5641
+ const result = await withLspClient(filePath, async (client, _workspaceRoot, resolvedFilePath) => formatDocumentWithClient(client, resolvedFilePath, signal === undefined ? {} : { signal }), "format", clientOptions(signal));
5642
+ return text(describeResult(filePath, result), formatDetails(filePath, result));
5643
+ } catch (error) {
5644
+ const missingDependency = missingDependencyResult(error, {
5645
+ filePath,
5646
+ status: "unavailable",
5647
+ reason: "server_unavailable",
5648
+ linesAdded: 0,
5649
+ linesRemoved: 0
5650
+ });
5651
+ if (missingDependency)
5652
+ return missingDependency;
5653
+ throw error;
5654
+ }
5655
+ }
5656
+ function formatDetails(filePath, result) {
5657
+ if (result.status === "unavailable") {
5658
+ return { filePath, status: "unavailable", reason: result.reason, linesAdded: 0, linesRemoved: 0 };
5659
+ }
5660
+ return {
5661
+ filePath,
5662
+ status: result.status,
5663
+ linesAdded: result.linesAdded,
5664
+ linesRemoved: result.linesRemoved
5665
+ };
5666
+ }
5667
+ function describeResult(filePath, result) {
5668
+ if (result.status === "unavailable") {
5669
+ return `Formatting unavailable for ${filePath}: the language server does not advertise documentFormattingProvider.`;
5670
+ }
5671
+ if (result.status === "unchanged") {
5672
+ return `Already formatted: ${filePath}`;
5673
+ }
5674
+ return `Formatted ${filePath} (+${result.linesAdded}/-${result.linesRemoved} lines)`;
5675
+ }
5676
+
5398
5677
  // ../lsp-core/src/tools/install-decision.ts
5399
5678
  async function executeLspInstallDecision(params) {
5400
5679
  const serverId = requireString(params, "server_id");
@@ -5727,6 +6006,16 @@ var LSP_MCP_TOOLS = [
5727
6006
  }, ["filePath", "line", "character", "newName"]),
5728
6007
  execute: executeLspRename
5729
6008
  },
6009
+ {
6010
+ name: "format",
6011
+ aliases: ["lsp_format"],
6012
+ title: "LSP Format",
6013
+ description: "Format a source file with its language server and write the returned edits to disk.",
6014
+ inputSchema: objectSchema({
6015
+ filePath: { type: "string", description: "Source file path to format." }
6016
+ }, ["filePath"]),
6017
+ execute: executeLspFormat
6018
+ },
5730
6019
  {
5731
6020
  name: "install_decision",
5732
6021
  aliases: ["lsp_install_decision"],
@@ -5946,6 +6235,9 @@ async function callToolViaDaemon(name, args, options) {
5946
6235
  function callDiagnosticsViaDaemon(filePath, options) {
5947
6236
  return callToolViaDaemon("diagnostics", { filePath, severity: "error" }, options);
5948
6237
  }
6238
+ function callFormatViaDaemon(filePath, options) {
6239
+ return callToolViaDaemon("format", { filePath }, options);
6240
+ }
5949
6241
  function currentRequestContext(env = process.env) {
5950
6242
  const cwd = process.cwd();
5951
6243
  const home = env["HOME"] ?? homedir3();
@@ -5968,7 +6260,7 @@ function withContext(args, context) {
5968
6260
  function ensureDaemonAvailable(paths, ensure, signal) {
5969
6261
  if (!signal)
5970
6262
  return ensure(paths);
5971
- return new Promise((resolve9, reject) => {
6263
+ return new Promise((resolve10, reject) => {
5972
6264
  let settled = false;
5973
6265
  const finish = (run) => {
5974
6266
  if (settled)
@@ -5983,11 +6275,11 @@ function ensureDaemonAvailable(paths, ensure, signal) {
5983
6275
  return;
5984
6276
  }
5985
6277
  signal.addEventListener("abort", onAbort, { once: true });
5986
- Promise.resolve().then(() => ensure(paths, signal)).then(() => finish(() => resolve9()), (error) => finish(() => reject(signal.aborted ? new DaemonRequestCancelledError(false) : error)));
6278
+ Promise.resolve().then(() => ensure(paths, signal)).then(() => finish(() => resolve10()), (error) => finish(() => reject(signal.aborted ? new DaemonRequestCancelledError(false) : error)));
5987
6279
  });
5988
6280
  }
5989
6281
  function sendToolCall(paths, token, name, args, options) {
5990
- return new Promise((resolve9, reject) => {
6282
+ return new Promise((resolve10, reject) => {
5991
6283
  const socket = connect(paths.socket);
5992
6284
  const requestId = allocateProxyRequestId();
5993
6285
  let settled = false;
@@ -6040,7 +6332,7 @@ function sendToolCall(paths, token, name, args, options) {
6040
6332
  }
6041
6333
  const result = toToolResult(message, requestId);
6042
6334
  if (result)
6043
- finish(() => resolve9(result));
6335
+ finish(() => resolve10(result));
6044
6336
  else
6045
6337
  finish(() => reject(new DaemonRequestError("invalid daemon response", requestWritten)));
6046
6338
  });
@@ -6086,8 +6378,6 @@ function isRetryableTool(name) {
6086
6378
  }
6087
6379
 
6088
6380
  // src/client.ts
6089
- import { statSync as statSync5 } from "node:fs";
6090
- import { isAbsolute as isAbsolute5 } from "node:path";
6091
6381
  var OMO_LSP_DAEMON_DIR2 = "OMO_LSP_DAEMON_DIR";
6092
6382
  var OMO_LSP_DAEMON_CLI2 = "OMO_LSP_DAEMON_CLI";
6093
6383
  var OMO_LSP_DAEMON_VERSION2 = "OMO_LSP_DAEMON_VERSION";
@@ -6116,12 +6406,12 @@ function resolveDaemonRuntime2(env, defaults) {
6116
6406
  throw new InvalidRuntimeOverrideError2("paired_values_required", `${OMO_LSP_DAEMON_CLI2} and ${OMO_LSP_DAEMON_VERSION2} must be set together`);
6117
6407
  }
6118
6408
  if (!hasCliOverride || !hasVersionOverride) {
6119
- if (!isAbsolute5(defaults.cliPath)) {
6409
+ if (!isAbsolute6(defaults.cliPath)) {
6120
6410
  throw new InvalidRuntimeOverrideError2("packaged_cli_must_be_absolute", "Packaged LSP daemon CLI path must be absolute");
6121
6411
  }
6122
6412
  return { cliPath: defaults.cliPath, version: validateDaemonVersion2(defaults.version) };
6123
6413
  }
6124
- if (!isAbsolute5(cliOverride)) {
6414
+ if (!isAbsolute6(cliOverride)) {
6125
6415
  throw new InvalidRuntimeOverrideError2("cli_must_be_absolute", `${OMO_LSP_DAEMON_CLI2} must be an absolute path to an existing regular file`);
6126
6416
  }
6127
6417
  const stat = statSync5(cliOverride, { throwIfNoEntry: false });
@@ -6139,6 +6429,9 @@ function callToolViaDaemon2(name, args, options) {
6139
6429
  function callDiagnosticsViaDaemon2(filePath, options) {
6140
6430
  return callDiagnosticsViaDaemon(filePath, options);
6141
6431
  }
6432
+ function callFormatViaDaemon2(filePath, options) {
6433
+ return callFormatViaDaemon(filePath, options);
6434
+ }
6142
6435
  function currentRequestContext2(env = process.env) {
6143
6436
  return currentRequestContext(env);
6144
6437
  }
@@ -6148,6 +6441,7 @@ export {
6148
6441
  OMO_LSP_DAEMON_DIR2 as OMO_LSP_DAEMON_DIR,
6149
6442
  OMO_LSP_DAEMON_VERSION2 as OMO_LSP_DAEMON_VERSION,
6150
6443
  callDiagnosticsViaDaemon2 as callDiagnosticsViaDaemon,
6444
+ callFormatViaDaemon2 as callFormatViaDaemon,
6151
6445
  callToolViaDaemon2 as callToolViaDaemon,
6152
6446
  currentRequestContext2 as currentRequestContext,
6153
6447
  resolveDaemonRuntime2 as resolveDaemonRuntime,