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.
- package/dist/cli/index.js +290 -288
- package/dist/cli-node/index.js +290 -288
- package/dist/index.js +1675 -1657
- package/dist/skills/debugging/SKILL.md +2 -0
- package/dist/skills/debugging/references/methodology/00-setup.md +12 -0
- package/dist/skills/debugging/references/methodology/02-investigate.md +21 -0
- package/dist/skills/debugging/references/runtimes/go.md +15 -1
- package/dist/skills/debugging/references/runtimes/native-binary.md +38 -0
- package/dist/skills/debugging/references/runtimes/node.md +25 -0
- package/dist/skills/debugging/references/runtimes/python.md +13 -0
- package/dist/skills/debugging/references/runtimes/rust.md +41 -0
- package/dist/skills/debugging/references/scripts/dap.mjs +267 -0
- package/dist/skills/debugging/references/scripts/dap.test.ts +86 -0
- package/dist/skills/debugging/references/scripts/fixture-adapter.mjs +59 -0
- package/dist/skills/debugging/references/tools/dap.md +103 -0
- package/dist/skills/debugging/references/tools/frida.md +193 -0
- package/dist/tools/delegate-task/types.d.ts +3 -0
- package/dist/tui.js +131 -147
- package/package.json +18 -15
- package/packages/lsp-core/src/index.ts +1 -0
- package/packages/lsp-core/src/lsp/client-wrapper.ts +25 -5
- package/packages/lsp-core/src/lsp/client.ts +26 -0
- package/packages/lsp-core/src/lsp/connection.ts +16 -0
- package/packages/lsp-core/src/lsp/constants.ts +1 -0
- package/packages/lsp-core/src/lsp/format-document.test.ts +143 -0
- package/packages/lsp-core/src/lsp/format-document.ts +90 -0
- package/packages/lsp-core/src/lsp/manager-max-clients.test.ts +151 -0
- package/packages/lsp-core/src/lsp/manager.ts +34 -1
- package/packages/lsp-core/src/lsp/server-definitions.ts +29 -0
- package/packages/lsp-core/src/lsp/server-installation.test.ts +376 -0
- package/packages/lsp-core/src/lsp/server-installation.ts +200 -27
- package/packages/lsp-core/src/lsp/server-resolution-local-binary.test.ts +170 -0
- package/packages/lsp-core/src/lsp/server-resolution.ts +18 -5
- package/packages/lsp-core/src/lsp/transport.ts +9 -0
- package/packages/lsp-core/src/lsp/types.ts +8 -0
- package/packages/lsp-core/src/tool-surface.test.ts +13 -1
- package/packages/lsp-core/src/tools/definitions.ts +14 -0
- package/packages/lsp-core/src/tools/format.test.ts +56 -0
- package/packages/lsp-core/src/tools/format.ts +56 -0
- package/packages/lsp-core/src/tools/index.ts +1 -0
- package/packages/lsp-core/src/tools/types.ts +10 -0
- package/packages/lsp-daemon/dist/cli.js +432 -144
- package/packages/lsp-daemon/dist/client.d.ts +10 -0
- package/packages/lsp-daemon/dist/client.js +401 -107
- package/packages/lsp-daemon/dist/daemon-client.d.ts +1 -0
- package/packages/lsp-daemon/dist/daemon-client.js +3 -0
- package/packages/lsp-daemon/dist/index.js +395 -107
- package/packages/lsp-daemon/package.json +1 -1
- package/packages/lsp-tools-mcp/dist/cli.js +384 -99
- package/packages/lsp-tools-mcp/dist/lsp/manager.js +53 -0
- package/packages/lsp-tools-mcp/dist/mcp.js +384 -99
- package/packages/lsp-tools-mcp/dist/tools.js +385 -99
- package/packages/omo-codex/plugin/.codex-plugin/plugin.json +1 -1
- package/packages/omo-codex/plugin/components/bootstrap/dist/cli.js +2 -2
- package/packages/omo-codex/plugin/components/bootstrap/hooks/hooks.json +1 -1
- package/packages/omo-codex/plugin/components/bootstrap/package.json +1 -1
- package/packages/omo-codex/plugin/components/codegraph/dist/cli.js +69 -35
- package/packages/omo-codex/plugin/components/codegraph/dist/serve.js +21 -2
- package/packages/omo-codex/plugin/components/codegraph/package.json +1 -1
- package/packages/omo-codex/plugin/components/comment-checker/hooks/hooks.json +1 -1
- package/packages/omo-codex/plugin/components/comment-checker/package.json +1 -1
- package/packages/omo-codex/plugin/components/git-bash/hooks/hooks.json +2 -2
- package/packages/omo-codex/plugin/components/git-bash/package.json +1 -1
- package/packages/omo-codex/plugin/components/lazycodex-executor-verify/hooks/hooks.json +1 -1
- package/packages/omo-codex/plugin/components/lazycodex-executor-verify/package.json +1 -1
- package/packages/omo-codex/plugin/components/lsp/dist/.omo-runtime-manifest.json +3 -3
- package/packages/omo-codex/plugin/components/lsp/dist/cli.js +404 -121
- package/packages/omo-codex/plugin/components/lsp/hooks/hooks.json +2 -2
- package/packages/omo-codex/plugin/components/lsp/package.json +1 -1
- package/packages/omo-codex/plugin/components/rules/dist/cli.js +3 -3
- package/packages/omo-codex/plugin/components/rules/hooks/hooks.json +4 -4
- package/packages/omo-codex/plugin/components/rules/package.json +1 -1
- package/packages/omo-codex/plugin/components/rules/src/post-compact-budget.ts +3 -3
- package/packages/omo-codex/plugin/components/rules/test/post-compact-budget.test.ts +4 -4
- package/packages/omo-codex/plugin/components/teammode/hooks/hooks.json +1 -1
- package/packages/omo-codex/plugin/components/teammode/package.json +1 -1
- package/packages/omo-codex/plugin/components/telemetry/dist/cli.js +30 -15
- package/packages/omo-codex/plugin/components/telemetry/dist/posthog.js +30 -15
- package/packages/omo-codex/plugin/components/telemetry/hooks/hooks.json +1 -1
- package/packages/omo-codex/plugin/components/telemetry/package.json +1 -1
- package/packages/omo-codex/plugin/components/ultrawork/hooks/hooks.json +1 -1
- package/packages/omo-codex/plugin/components/ultrawork/package.json +1 -1
- package/packages/omo-codex/plugin/components/ulw-execute-continuation/hooks/hooks.json +2 -2
- package/packages/omo-codex/plugin/components/ulw-execute-continuation/package.json +1 -1
- package/packages/omo-codex/plugin/components/ulw-loop/dist/cli-commands.js +5 -1
- package/packages/omo-codex/plugin/components/ulw-loop/dist/cli-output.d.ts +2 -1
- package/packages/omo-codex/plugin/components/ulw-loop/dist/cli-output.js +11 -1
- package/packages/omo-codex/plugin/components/ulw-loop/dist/cli.js +22 -10
- package/packages/omo-codex/plugin/components/ulw-loop/hooks/hooks.json +4 -4
- package/packages/omo-codex/plugin/components/ulw-loop/package.json +1 -1
- package/packages/omo-codex/plugin/components/ulw-loop/src/cli-commands.ts +5 -1
- package/packages/omo-codex/plugin/components/ulw-loop/src/cli-output.ts +13 -1
- package/packages/omo-codex/plugin/components/ulw-loop/src/cli.ts +3 -5
- package/packages/omo-codex/plugin/components/ulw-loop/test/cli-entrypoint.test.ts +26 -2
- package/packages/omo-codex/plugin/hooks/post-compact-resetting-git-bash-mcp-reminder.json +1 -1
- package/packages/omo-codex/plugin/hooks/post-compact-resetting-lsp-diagnostics-cache.json +1 -1
- package/packages/omo-codex/plugin/hooks/post-compact-resetting-project-rule-cache.json +1 -1
- package/packages/omo-codex/plugin/hooks/post-tool-use-checking-codegraph-init-guidance.json +1 -1
- package/packages/omo-codex/plugin/hooks/post-tool-use-checking-comments.json +1 -1
- package/packages/omo-codex/plugin/hooks/post-tool-use-checking-lsp-diagnostics.json +1 -1
- package/packages/omo-codex/plugin/hooks/post-tool-use-checking-thread-title-hygiene.json +1 -1
- package/packages/omo-codex/plugin/hooks/post-tool-use-matching-project-rules.json +1 -1
- package/packages/omo-codex/plugin/hooks/pre-tool-use-enforcing-unlimited-goal-budget.json +1 -1
- package/packages/omo-codex/plugin/hooks/pre-tool-use-guarding-ulw-loop-spawns.json +1 -1
- package/packages/omo-codex/plugin/hooks/pre-tool-use-recommending-git-bash-mcp.json +1 -1
- package/packages/omo-codex/plugin/hooks/session-start-checking-auto-update.json +1 -1
- package/packages/omo-codex/plugin/hooks/session-start-checking-bootstrap-provisioning.json +1 -1
- package/packages/omo-codex/plugin/hooks/session-start-checking-codegraph-bootstrap.json +1 -1
- package/packages/omo-codex/plugin/hooks/session-start-loading-project-rules.json +1 -1
- package/packages/omo-codex/plugin/hooks/session-start-recording-session-telemetry.json +1 -1
- package/packages/omo-codex/plugin/hooks/stop-checking-ulw-execute-continuation.json +1 -1
- package/packages/omo-codex/plugin/hooks/stop-checking-ulw-loop-resume.json +1 -1
- package/packages/omo-codex/plugin/hooks/subagent-stop-checking-ulw-execute-continuation.json +1 -1
- package/packages/omo-codex/plugin/hooks/subagent-stop-verifying-lazycodex-executor-evidence.json +1 -1
- package/packages/omo-codex/plugin/hooks/user-prompt-submit-checking-ultrawork-trigger.json +1 -1
- package/packages/omo-codex/plugin/hooks/user-prompt-submit-checking-ulw-loop-steering.json +1 -1
- package/packages/omo-codex/plugin/hooks/user-prompt-submit-loading-project-rules.json +1 -1
- package/packages/omo-codex/plugin/model-catalog.json +3 -3
- package/packages/omo-codex/plugin/package-lock.json +13 -13
- package/packages/omo-codex/plugin/package.json +1 -1
- package/packages/omo-codex/plugin/scripts/migrate-codex-config/catalog.mjs +3 -3
- package/packages/omo-codex/plugin/skills/debugging/SKILL.md +2 -0
- package/packages/omo-codex/plugin/skills/debugging/references/methodology/00-setup.md +12 -0
- package/packages/omo-codex/plugin/skills/debugging/references/methodology/02-investigate.md +21 -0
- package/packages/omo-codex/plugin/skills/debugging/references/runtimes/go.md +15 -1
- package/packages/omo-codex/plugin/skills/debugging/references/runtimes/native-binary.md +38 -0
- package/packages/omo-codex/plugin/skills/debugging/references/runtimes/node.md +25 -0
- package/packages/omo-codex/plugin/skills/debugging/references/runtimes/python.md +13 -0
- package/packages/omo-codex/plugin/skills/debugging/references/runtimes/rust.md +41 -0
- package/packages/omo-codex/plugin/skills/debugging/references/scripts/dap.mjs +267 -0
- package/packages/omo-codex/plugin/skills/debugging/references/scripts/fixture-adapter.mjs +59 -0
- package/packages/omo-codex/plugin/skills/debugging/references/tools/dap.md +103 -0
- package/packages/omo-codex/plugin/skills/debugging/references/tools/frida.md +193 -0
- package/packages/omo-codex/plugin/test/aggregate-model-catalog.test.mjs +1 -1
- package/packages/omo-codex/plugin/test/auto-update.test.mjs +2 -2
- package/packages/omo-codex/plugin/test/migrate-codex-config.test.mjs +8 -8
- package/packages/omo-codex/scripts/install-config-reasoning.test.mjs +2 -2
- package/packages/omo-codex/scripts/install-dist/install-local.mjs +38 -23
- package/packages/shared-skills/skills/debugging/SKILL.md +2 -0
- package/packages/shared-skills/skills/debugging/references/methodology/00-setup.md +12 -0
- package/packages/shared-skills/skills/debugging/references/methodology/02-investigate.md +21 -0
- package/packages/shared-skills/skills/debugging/references/runtimes/go.md +15 -1
- package/packages/shared-skills/skills/debugging/references/runtimes/native-binary.md +38 -0
- package/packages/shared-skills/skills/debugging/references/runtimes/node.md +25 -0
- package/packages/shared-skills/skills/debugging/references/runtimes/python.md +13 -0
- package/packages/shared-skills/skills/debugging/references/runtimes/rust.md +41 -0
- package/packages/shared-skills/skills/debugging/references/scripts/dap.mjs +267 -0
- package/packages/shared-skills/skills/debugging/references/scripts/dap.test.ts +86 -0
- package/packages/shared-skills/skills/debugging/references/scripts/fixture-adapter.mjs +59 -0
- package/packages/shared-skills/skills/debugging/references/tools/dap.md +103 -0
- 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
|
|
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
|
-
|
|
4561
|
-
|
|
4562
|
-
|
|
4563
|
-
|
|
4564
|
-
|
|
4565
|
-
|
|
4566
|
-
|
|
4567
|
-
|
|
4568
|
-
|
|
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
|
-
|
|
4571
|
-
|
|
4572
|
-
|
|
4573
|
-
|
|
4574
|
-
|
|
4575
|
-
|
|
4576
|
-
|
|
4577
|
-
|
|
4578
|
-
|
|
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
|
-
|
|
4582
|
-
|
|
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
|
|
4586
|
-
|
|
4587
|
-
|
|
4588
|
-
|
|
4589
|
-
|
|
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
|
-
|
|
4594
|
-
|
|
4595
|
-
|
|
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)
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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
|
-
|
|
5003
|
+
...installOptions.slice(1)
|
|
4813
5004
|
].join(`
|
|
4814
5005
|
`);
|
|
4815
5006
|
}
|
|
4816
5007
|
if (!context.capabilities.installDecisionTool) {
|
|
4817
5008
|
return [
|
|
4818
5009
|
...header,
|
|
4819
|
-
|
|
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
|
-
|
|
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
|
|
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 =
|
|
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((
|
|
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(() =>
|
|
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((
|
|
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(() =>
|
|
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 (!
|
|
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 (!
|
|
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,
|