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,6 +1,6 @@
|
|
|
1
1
|
// ../lsp-core/src/lsp/client-wrapper.ts
|
|
2
2
|
import { existsSync as existsSync10, realpathSync as realpathSync5, statSync as statSync3 } from "node:fs";
|
|
3
|
-
import { basename as basename3, dirname as
|
|
3
|
+
import { basename as basename3, dirname as dirname8, join as join5, resolve as resolve8 } from "node:path";
|
|
4
4
|
|
|
5
5
|
// ../lsp-core/src/request-context.ts
|
|
6
6
|
import { AsyncLocalStorage } from "node:async_hooks";
|
|
@@ -282,6 +282,7 @@ var DEFAULT_MAX_DIRECTORY_FILES = 50;
|
|
|
282
282
|
var REQUEST_TIMEOUT_MS = 15000;
|
|
283
283
|
var INIT_TIMEOUT_MS = 60000;
|
|
284
284
|
var IDLE_TIMEOUT_MS = 5 * 60000;
|
|
285
|
+
var MAX_RESIDENT_CLIENTS = 6;
|
|
285
286
|
var REAPER_INTERVAL_MS = 60000;
|
|
286
287
|
var STOP_HARD_KILL_TIMEOUT_MS = 5000;
|
|
287
288
|
var STOP_SIGKILL_GRACE_MS = 1000;
|
|
@@ -807,6 +808,7 @@ class LspClientTransport {
|
|
|
807
808
|
this.diagnosticsStore = new Map;
|
|
808
809
|
this.workspaceApplyEditHandler = null;
|
|
809
810
|
this.diagnosticPullSupported = false;
|
|
811
|
+
this.documentFormattingSupported = false;
|
|
810
812
|
this.requestTimeoutMs = timeouts.requestTimeoutMs ?? REQUEST_TIMEOUT_MS;
|
|
811
813
|
this.initializeTimeoutMs = timeouts.initializeTimeoutMs ?? INIT_TIMEOUT_MS;
|
|
812
814
|
}
|
|
@@ -828,6 +830,12 @@ class LspClientTransport {
|
|
|
828
830
|
isDiagnosticPullSupported() {
|
|
829
831
|
return this.diagnosticPullSupported;
|
|
830
832
|
}
|
|
833
|
+
setDocumentFormattingSupported(supported) {
|
|
834
|
+
this.documentFormattingSupported = supported;
|
|
835
|
+
}
|
|
836
|
+
isDocumentFormattingSupported() {
|
|
837
|
+
return this.documentFormattingSupported;
|
|
838
|
+
}
|
|
831
839
|
handlePublishDiagnostics(params) {
|
|
832
840
|
this.diagnosticsStore.set(params.uri, [...params.diagnostics]);
|
|
833
841
|
}
|
|
@@ -1041,6 +1049,14 @@ function supportsDiagnosticPull(capabilities) {
|
|
|
1041
1049
|
return false;
|
|
1042
1050
|
return Object.hasOwn(capabilities, "diagnosticProvider");
|
|
1043
1051
|
}
|
|
1052
|
+
function supportsDocumentFormatting(capabilities) {
|
|
1053
|
+
if (capabilities === undefined)
|
|
1054
|
+
return false;
|
|
1055
|
+
const provider = capabilities.documentFormattingProvider;
|
|
1056
|
+
if (provider === undefined || provider === null || provider === false)
|
|
1057
|
+
return false;
|
|
1058
|
+
return provider === true || typeof provider === "object";
|
|
1059
|
+
}
|
|
1044
1060
|
|
|
1045
1061
|
class LspClientConnection extends LspClientTransport {
|
|
1046
1062
|
async initialize() {
|
|
@@ -1057,6 +1073,7 @@ class LspClientConnection extends LspClientTransport {
|
|
|
1057
1073
|
references: {},
|
|
1058
1074
|
documentSymbol: { hierarchicalDocumentSymbolSupport: true },
|
|
1059
1075
|
publishDiagnostics: {},
|
|
1076
|
+
formatting: { dynamicRegistration: false },
|
|
1060
1077
|
rename: {
|
|
1061
1078
|
prepareSupport: true,
|
|
1062
1079
|
prepareSupportDefaultBehavior: 1
|
|
@@ -1098,6 +1115,7 @@ class LspClientConnection extends LspClientTransport {
|
|
|
1098
1115
|
initializationOptions: this.server.initialization
|
|
1099
1116
|
}, { timeoutMs: this.initializeTimeoutMs });
|
|
1100
1117
|
this.setDiagnosticPullSupported(supportsDiagnosticPull(result?.capabilities));
|
|
1118
|
+
this.setDocumentFormattingSupported(supportsDocumentFormatting(result?.capabilities));
|
|
1101
1119
|
await this.sendNotification("initialized", {});
|
|
1102
1120
|
await this.sendNotification("workspace/didChangeConfiguration", {
|
|
1103
1121
|
settings: { json: { validate: { enable: true } } }
|
|
@@ -2682,6 +2700,18 @@ class LspClient extends LspClientConnection {
|
|
|
2682
2700
|
textDocument: { uri: pathToFileURL3(absPath).href }
|
|
2683
2701
|
}, options);
|
|
2684
2702
|
}
|
|
2703
|
+
async formatDocument(filePath, options, signal) {
|
|
2704
|
+
if (!this.isDocumentFormattingSupported())
|
|
2705
|
+
return null;
|
|
2706
|
+
const absPath = this.resolveWorkspacePath(filePath);
|
|
2707
|
+
await this.openFile(absPath);
|
|
2708
|
+
const requestOptions = signal === undefined ? {} : { signal };
|
|
2709
|
+
const edits = await this.sendRequest("textDocument/formatting", {
|
|
2710
|
+
textDocument: { uri: pathToFileURL3(absPath).href },
|
|
2711
|
+
options
|
|
2712
|
+
}, requestOptions);
|
|
2713
|
+
return edits ?? [];
|
|
2714
|
+
}
|
|
2685
2715
|
async workspaceSymbols(query, signal) {
|
|
2686
2716
|
const options = signal === undefined ? {} : { signal };
|
|
2687
2717
|
return this.sendRequest("workspace/symbol", { query }, options);
|
|
@@ -2934,6 +2964,7 @@ class LspManager {
|
|
|
2934
2964
|
this.disposed = false;
|
|
2935
2965
|
this.idleTimeoutMs = options.idleTimeoutMs ?? IDLE_TIMEOUT_MS;
|
|
2936
2966
|
this.initTimeoutMs = options.initTimeoutMs ?? INIT_TIMEOUT_MS;
|
|
2967
|
+
this.maxResidentClients = options.maxResidentClients ?? MAX_RESIDENT_CLIENTS;
|
|
2937
2968
|
this.reaperIntervalMs = options.reaperIntervalMs ?? REAPER_INTERVAL_MS;
|
|
2938
2969
|
this.clientFactory = options.clientFactory ?? ((root, server) => new LspClient(root, server));
|
|
2939
2970
|
this.now = options.now ?? (() => Date.now());
|
|
@@ -2967,6 +2998,26 @@ class LspManager {
|
|
|
2967
2998
|
}
|
|
2968
2999
|
}
|
|
2969
3000
|
}
|
|
3001
|
+
evictForAdmission() {
|
|
3002
|
+
while (this.clients.size >= this.maxResidentClients) {
|
|
3003
|
+
const victim = this.leastRecentlyUsedIdleClient();
|
|
3004
|
+
if (!victim)
|
|
3005
|
+
return;
|
|
3006
|
+
this.clients.delete(victim.key);
|
|
3007
|
+
stopClientBestEffort(victim.managed.client);
|
|
3008
|
+
}
|
|
3009
|
+
}
|
|
3010
|
+
leastRecentlyUsedIdleClient() {
|
|
3011
|
+
let candidate = null;
|
|
3012
|
+
for (const [key, managed] of this.clients) {
|
|
3013
|
+
if (managed.refCount > 0 || managed.pendingWaiters > 0 || managed.isInitializing)
|
|
3014
|
+
continue;
|
|
3015
|
+
if (candidate === null || managed.lastUsedAt < candidate.managed.lastUsedAt) {
|
|
3016
|
+
candidate = { key, managed };
|
|
3017
|
+
}
|
|
3018
|
+
}
|
|
3019
|
+
return candidate;
|
|
3020
|
+
}
|
|
2970
3021
|
async tryDeleteIfOrphaned(key, managed) {
|
|
2971
3022
|
if (managed.refCount === 0 && managed.pendingWaiters === 0 && !managed.isInitializing && this.clients.get(key) === managed) {
|
|
2972
3023
|
this.clients.delete(key);
|
|
@@ -3013,6 +3064,7 @@ class LspManager {
|
|
|
3013
3064
|
managed.lastUsedAt = this.now();
|
|
3014
3065
|
return managed.client;
|
|
3015
3066
|
}
|
|
3067
|
+
this.evictForAdmission();
|
|
3016
3068
|
const client = this.clientFactory(root, server);
|
|
3017
3069
|
const initStartedAt = this.now();
|
|
3018
3070
|
const initPromise = (async () => {
|
|
@@ -3075,6 +3127,7 @@ class LspManager {
|
|
|
3075
3127
|
const key = this.getKey(root, server.id);
|
|
3076
3128
|
if (this.clients.has(key))
|
|
3077
3129
|
return;
|
|
3130
|
+
this.evictForAdmission();
|
|
3078
3131
|
const client = this.clientFactory(root, server);
|
|
3079
3132
|
const initStartedAt = this.now();
|
|
3080
3133
|
const initPromise = (async () => {
|
|
@@ -3200,57 +3253,6 @@ function nearestExistingAncestor(directory) {
|
|
|
3200
3253
|
return current;
|
|
3201
3254
|
}
|
|
3202
3255
|
|
|
3203
|
-
// ../lsp-core/src/lsp/server-install-state.ts
|
|
3204
|
-
import { existsSync as existsSync7, mkdirSync, readFileSync as readFileSync3, renameSync as renameSync2, writeFileSync as writeFileSync2 } from "node:fs";
|
|
3205
|
-
import { dirname as dirname6 } from "node:path";
|
|
3206
|
-
function getInstallDecisionsPath() {
|
|
3207
|
-
return lspRequestContext().installDecisionsPath;
|
|
3208
|
-
}
|
|
3209
|
-
function loadInstallDecisions() {
|
|
3210
|
-
const path = getInstallDecisionsPath();
|
|
3211
|
-
if (!existsSync7(path))
|
|
3212
|
-
return {};
|
|
3213
|
-
try {
|
|
3214
|
-
const parsed = JSON.parse(readFileSync3(path, "utf8"));
|
|
3215
|
-
return isInstallDecisions(parsed) ? parsed : {};
|
|
3216
|
-
} catch {
|
|
3217
|
-
return {};
|
|
3218
|
-
}
|
|
3219
|
-
}
|
|
3220
|
-
function loadInstallDecision(serverId) {
|
|
3221
|
-
return loadInstallDecisions()[serverId];
|
|
3222
|
-
}
|
|
3223
|
-
function recordInstallDecision(serverId, decision, decidedAt = new Date().toISOString()) {
|
|
3224
|
-
const decisions = loadInstallDecisions();
|
|
3225
|
-
decisions[serverId] = { decision, decidedAt };
|
|
3226
|
-
writeInstallDecisions(decisions);
|
|
3227
|
-
}
|
|
3228
|
-
function isInstallDecision(value) {
|
|
3229
|
-
return value === "declined" || value === "allowed";
|
|
3230
|
-
}
|
|
3231
|
-
function writeInstallDecisions(decisions) {
|
|
3232
|
-
const path = getInstallDecisionsPath();
|
|
3233
|
-
mkdirSync(dirname6(path), { recursive: true });
|
|
3234
|
-
const tmpPath = `${path}.tmp`;
|
|
3235
|
-
writeFileSync2(tmpPath, `${JSON.stringify(decisions, null, 2)}
|
|
3236
|
-
`, "utf8");
|
|
3237
|
-
renameSync2(tmpPath, path);
|
|
3238
|
-
}
|
|
3239
|
-
function isInstallDecisions(value) {
|
|
3240
|
-
return isRecord5(value) && Object.values(value).every(isInstallDecisionRecord);
|
|
3241
|
-
}
|
|
3242
|
-
function isInstallDecisionRecord(value) {
|
|
3243
|
-
if (!isRecord5(value))
|
|
3244
|
-
return false;
|
|
3245
|
-
return isInstallDecision(value["decision"]) && typeof value["decidedAt"] === "string";
|
|
3246
|
-
}
|
|
3247
|
-
function isRecord5(value) {
|
|
3248
|
-
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
3249
|
-
}
|
|
3250
|
-
|
|
3251
|
-
// ../lsp-core/src/lsp/config-loader.ts
|
|
3252
|
-
import { existsSync as existsSync8, readFileSync as readFileSync4 } from "node:fs";
|
|
3253
|
-
|
|
3254
3256
|
// ../lsp-core/src/lsp/server-definitions.ts
|
|
3255
3257
|
var LSP_INSTALL_HINTS = {
|
|
3256
3258
|
typescript: "npm install -g typescript-language-server typescript",
|
|
@@ -3296,6 +3298,26 @@ var LSP_INSTALL_HINTS = {
|
|
|
3296
3298
|
julials: `julia -e 'using Pkg; Pkg.add("LanguageServer")'`,
|
|
3297
3299
|
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"
|
|
3298
3300
|
};
|
|
3301
|
+
var LSP_LOCAL_INSTALL_HINTS = {
|
|
3302
|
+
typescript: "bun add -d typescript-language-server typescript",
|
|
3303
|
+
vue: "bun add -d @vue/language-server",
|
|
3304
|
+
eslint: "bun add -d vscode-langservers-extracted",
|
|
3305
|
+
oxlint: "bun add -d oxlint",
|
|
3306
|
+
biome: "bun add -d @biomejs/biome",
|
|
3307
|
+
svelte: "bun add -d svelte-language-server",
|
|
3308
|
+
astro: "bun add -d @astrojs/language-server",
|
|
3309
|
+
bash: "bun add -d bash-language-server",
|
|
3310
|
+
"bash-ls": "bun add -d bash-language-server",
|
|
3311
|
+
"yaml-ls": "bun add -d yaml-language-server",
|
|
3312
|
+
php: "bun add -d intelephense",
|
|
3313
|
+
prisma: "bun add -d prisma",
|
|
3314
|
+
dockerfile: "bun add -d dockerfile-language-server-nodejs",
|
|
3315
|
+
pyright: "uv add --dev pyright",
|
|
3316
|
+
basedpyright: "uv add --dev basedpyright",
|
|
3317
|
+
ruff: "uv add --dev ruff",
|
|
3318
|
+
ty: "uv add --dev ty",
|
|
3319
|
+
"ruby-lsp": "bundle add ruby-lsp --group development"
|
|
3320
|
+
};
|
|
3299
3321
|
var BUILTIN_SERVERS = {
|
|
3300
3322
|
typescript: {
|
|
3301
3323
|
command: ["typescript-language-server", "--stdio"],
|
|
@@ -3398,7 +3420,56 @@ var BUILTIN_SERVERS = {
|
|
|
3398
3420
|
}
|
|
3399
3421
|
};
|
|
3400
3422
|
|
|
3423
|
+
// ../lsp-core/src/lsp/server-install-state.ts
|
|
3424
|
+
import { existsSync as existsSync7, mkdirSync, readFileSync as readFileSync3, renameSync as renameSync2, writeFileSync as writeFileSync2 } from "node:fs";
|
|
3425
|
+
import { dirname as dirname6 } from "node:path";
|
|
3426
|
+
function getInstallDecisionsPath() {
|
|
3427
|
+
return lspRequestContext().installDecisionsPath;
|
|
3428
|
+
}
|
|
3429
|
+
function loadInstallDecisions() {
|
|
3430
|
+
const path = getInstallDecisionsPath();
|
|
3431
|
+
if (!existsSync7(path))
|
|
3432
|
+
return {};
|
|
3433
|
+
try {
|
|
3434
|
+
const parsed = JSON.parse(readFileSync3(path, "utf8"));
|
|
3435
|
+
return isInstallDecisions(parsed) ? parsed : {};
|
|
3436
|
+
} catch {
|
|
3437
|
+
return {};
|
|
3438
|
+
}
|
|
3439
|
+
}
|
|
3440
|
+
function loadInstallDecision(serverId) {
|
|
3441
|
+
return loadInstallDecisions()[serverId];
|
|
3442
|
+
}
|
|
3443
|
+
function recordInstallDecision(serverId, decision, decidedAt = new Date().toISOString()) {
|
|
3444
|
+
const decisions = loadInstallDecisions();
|
|
3445
|
+
decisions[serverId] = { decision, decidedAt };
|
|
3446
|
+
writeInstallDecisions(decisions);
|
|
3447
|
+
}
|
|
3448
|
+
function isInstallDecision(value) {
|
|
3449
|
+
return value === "declined" || value === "allowed";
|
|
3450
|
+
}
|
|
3451
|
+
function writeInstallDecisions(decisions) {
|
|
3452
|
+
const path = getInstallDecisionsPath();
|
|
3453
|
+
mkdirSync(dirname6(path), { recursive: true });
|
|
3454
|
+
const tmpPath = `${path}.tmp`;
|
|
3455
|
+
writeFileSync2(tmpPath, `${JSON.stringify(decisions, null, 2)}
|
|
3456
|
+
`, "utf8");
|
|
3457
|
+
renameSync2(tmpPath, path);
|
|
3458
|
+
}
|
|
3459
|
+
function isInstallDecisions(value) {
|
|
3460
|
+
return isRecord5(value) && Object.values(value).every(isInstallDecisionRecord);
|
|
3461
|
+
}
|
|
3462
|
+
function isInstallDecisionRecord(value) {
|
|
3463
|
+
if (!isRecord5(value))
|
|
3464
|
+
return false;
|
|
3465
|
+
return isInstallDecision(value["decision"]) && typeof value["decidedAt"] === "string";
|
|
3466
|
+
}
|
|
3467
|
+
function isRecord5(value) {
|
|
3468
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
3469
|
+
}
|
|
3470
|
+
|
|
3401
3471
|
// ../lsp-core/src/lsp/config-loader.ts
|
|
3472
|
+
import { existsSync as existsSync8, readFileSync as readFileSync4 } from "node:fs";
|
|
3402
3473
|
function getProjectConfigPaths() {
|
|
3403
3474
|
return lspRequestContext().projectConfigPaths;
|
|
3404
3475
|
}
|
|
@@ -3595,53 +3666,154 @@ function getDisabledServerIds() {
|
|
|
3595
3666
|
|
|
3596
3667
|
// ../lsp-core/src/lsp/server-installation.ts
|
|
3597
3668
|
import { existsSync as existsSync9 } from "node:fs";
|
|
3598
|
-
import { delimiter as delimiter3, join as join4 } from "node:path";
|
|
3599
|
-
|
|
3600
|
-
|
|
3601
|
-
|
|
3602
|
-
|
|
3603
|
-
|
|
3604
|
-
|
|
3605
|
-
|
|
3606
|
-
|
|
3607
|
-
|
|
3669
|
+
import { delimiter as delimiter3, dirname as dirname7, isAbsolute as isAbsolute3, join as join4, resolve as resolve7 } from "node:path";
|
|
3670
|
+
var LOCAL_BIN_RULES = [
|
|
3671
|
+
{
|
|
3672
|
+
markers: ["package.json", "bun.lock", "bun.lockb", "package-lock.json", "yarn.lock", "pnpm-lock.yaml"],
|
|
3673
|
+
binDirs: [join4("node_modules", ".bin")]
|
|
3674
|
+
},
|
|
3675
|
+
{
|
|
3676
|
+
markers: [
|
|
3677
|
+
"pyproject.toml",
|
|
3678
|
+
"ty.toml",
|
|
3679
|
+
"requirements.txt",
|
|
3680
|
+
"setup.py",
|
|
3681
|
+
"setup.cfg",
|
|
3682
|
+
"Pipfile",
|
|
3683
|
+
"pyrightconfig.json",
|
|
3684
|
+
"ruff.toml",
|
|
3685
|
+
".ruff.toml"
|
|
3686
|
+
],
|
|
3687
|
+
binDirs: [
|
|
3688
|
+
join4(".venv", "bin"),
|
|
3689
|
+
join4(".venv", "Scripts"),
|
|
3690
|
+
join4("venv", "bin"),
|
|
3691
|
+
join4("venv", "Scripts"),
|
|
3692
|
+
join4(".env", "bin"),
|
|
3693
|
+
join4(".env", "Scripts")
|
|
3694
|
+
]
|
|
3695
|
+
},
|
|
3696
|
+
{
|
|
3697
|
+
markers: ["Gemfile", "Gemfile.lock"],
|
|
3698
|
+
binDirs: [join4("vendor", "bundle", "bin"), "bin"]
|
|
3699
|
+
},
|
|
3700
|
+
{
|
|
3701
|
+
markers: ["go.mod", "go.sum", "go.work"],
|
|
3702
|
+
binDirs: ["bin"]
|
|
3608
3703
|
}
|
|
3609
|
-
|
|
3610
|
-
|
|
3611
|
-
|
|
3612
|
-
|
|
3613
|
-
|
|
3614
|
-
|
|
3615
|
-
|
|
3616
|
-
|
|
3617
|
-
|
|
3704
|
+
];
|
|
3705
|
+
var resolutionCache = new Map;
|
|
3706
|
+
var probeCount = 0;
|
|
3707
|
+
function probe(path) {
|
|
3708
|
+
probeCount += 1;
|
|
3709
|
+
return existsSync9(path);
|
|
3710
|
+
}
|
|
3711
|
+
function executableSuffixes(platform, pathExt) {
|
|
3712
|
+
if (platform !== "win32")
|
|
3713
|
+
return [""];
|
|
3714
|
+
const configured = pathExt ?? process.env["PATHEXT"] ?? "";
|
|
3715
|
+
const systemExts = configured.split(";").filter((entry) => entry.length > 0).map((entry) => entry.toLowerCase());
|
|
3716
|
+
return [...new Set(["", ...systemExts, ".exe", ".cmd", ".bat", ".ps1"])];
|
|
3717
|
+
}
|
|
3718
|
+
function probeWithSuffixes(directory, command, suffixes) {
|
|
3719
|
+
for (const suffix of suffixes) {
|
|
3720
|
+
const candidate = join4(directory, command + suffix);
|
|
3721
|
+
if (probe(candidate))
|
|
3722
|
+
return candidate;
|
|
3723
|
+
}
|
|
3724
|
+
return null;
|
|
3725
|
+
}
|
|
3726
|
+
function resolveLocal(command, workingDirectory, suffixes, stopAt) {
|
|
3727
|
+
const boundary = stopAt === undefined ? undefined : resolve7(stopAt);
|
|
3728
|
+
let current = resolve7(workingDirectory);
|
|
3729
|
+
while (true) {
|
|
3730
|
+
for (const rule of LOCAL_BIN_RULES) {
|
|
3731
|
+
if (!rule.markers.some((marker) => probe(join4(current, marker))))
|
|
3732
|
+
continue;
|
|
3733
|
+
for (const binDir of rule.binDirs) {
|
|
3734
|
+
const found = probeWithSuffixes(join4(current, binDir), command, suffixes);
|
|
3735
|
+
if (found !== null)
|
|
3736
|
+
return found;
|
|
3737
|
+
}
|
|
3618
3738
|
}
|
|
3739
|
+
if (probe(join4(current, ".git")))
|
|
3740
|
+
return null;
|
|
3741
|
+
if (boundary !== undefined && current === boundary)
|
|
3742
|
+
return null;
|
|
3743
|
+
const parent = dirname7(current);
|
|
3744
|
+
if (parent === current)
|
|
3745
|
+
return null;
|
|
3746
|
+
current = parent;
|
|
3619
3747
|
}
|
|
3620
|
-
|
|
3621
|
-
|
|
3748
|
+
}
|
|
3749
|
+
function resolveFromPath(command, suffixes, platform, pathEnvOverride) {
|
|
3750
|
+
let pathEnv = pathEnvOverride ?? process.env["PATH"] ?? "";
|
|
3751
|
+
if (platform === "win32" && !pathEnv) {
|
|
3622
3752
|
pathEnv = process.env["Path"] ?? "";
|
|
3623
3753
|
}
|
|
3624
|
-
const
|
|
3625
|
-
|
|
3626
|
-
|
|
3627
|
-
|
|
3628
|
-
|
|
3629
|
-
|
|
3630
|
-
}
|
|
3754
|
+
for (const entry of pathEnv.split(delimiter3)) {
|
|
3755
|
+
if (entry.length === 0)
|
|
3756
|
+
continue;
|
|
3757
|
+
const found = probeWithSuffixes(entry, command, suffixes);
|
|
3758
|
+
if (found !== null)
|
|
3759
|
+
return found;
|
|
3631
3760
|
}
|
|
3632
|
-
|
|
3633
|
-
|
|
3634
|
-
|
|
3761
|
+
return null;
|
|
3762
|
+
}
|
|
3763
|
+
function resolveServerBinary(command, workingDirectory, options = {}) {
|
|
3764
|
+
if (command.length === 0)
|
|
3765
|
+
return null;
|
|
3766
|
+
const [cmd] = command;
|
|
3767
|
+
if (cmd === undefined || cmd.length === 0)
|
|
3768
|
+
return null;
|
|
3769
|
+
const platform = options.platform ?? process.platform;
|
|
3770
|
+
const suffixes = executableSuffixes(platform, options.pathExt);
|
|
3771
|
+
if (cmd.includes("/") || cmd.includes("\\")) {
|
|
3772
|
+
const explicit = isAbsolute3(cmd) ? cmd : resolve7(workingDirectory ?? process.cwd(), cmd);
|
|
3773
|
+
return probe(explicit) ? explicit : null;
|
|
3774
|
+
}
|
|
3775
|
+
const cacheKey = JSON.stringify([
|
|
3776
|
+
workingDirectory ?? "",
|
|
3777
|
+
cmd,
|
|
3778
|
+
platform,
|
|
3779
|
+
options.stopAt ?? "",
|
|
3780
|
+
options.pathExt ?? "",
|
|
3781
|
+
options.pathEnv ?? process.env["PATH"] ?? ""
|
|
3782
|
+
]);
|
|
3783
|
+
const cached = resolutionCache.get(cacheKey);
|
|
3784
|
+
if (cached !== undefined)
|
|
3785
|
+
return cached;
|
|
3786
|
+
let resolved = null;
|
|
3787
|
+
if (workingDirectory !== undefined && workingDirectory.length > 0) {
|
|
3788
|
+
resolved = resolveLocal(cmd, workingDirectory, suffixes, options.stopAt);
|
|
3789
|
+
}
|
|
3790
|
+
resolved ??= resolveFromPath(cmd, suffixes, platform, options.pathEnv);
|
|
3791
|
+
if (resolved === null && cmd === "node")
|
|
3792
|
+
resolved = cmd;
|
|
3793
|
+
resolutionCache.set(cacheKey, resolved);
|
|
3794
|
+
return resolved;
|
|
3795
|
+
}
|
|
3796
|
+
function isServerInstalled(command, workingDirectory, options = {}) {
|
|
3797
|
+
if (command.length === 0)
|
|
3798
|
+
return false;
|
|
3799
|
+
return resolveServerBinary(command, workingDirectory, options) !== null;
|
|
3635
3800
|
}
|
|
3636
3801
|
|
|
3637
3802
|
// ../lsp-core/src/lsp/server-resolution.ts
|
|
3803
|
+
function withResolvedCommand(command, binaryPath) {
|
|
3804
|
+
return [binaryPath, ...command.slice(1)];
|
|
3805
|
+
}
|
|
3638
3806
|
function findServerForExtension(ext) {
|
|
3639
3807
|
const servers = getMergedServers();
|
|
3808
|
+
const workingDirectory = contextCwd();
|
|
3640
3809
|
for (const server of servers) {
|
|
3641
|
-
if (server.extensions.includes(ext)
|
|
3810
|
+
if (!server.extensions.includes(ext))
|
|
3811
|
+
continue;
|
|
3812
|
+
const binaryPath = resolveServerBinary(server.command, workingDirectory);
|
|
3813
|
+
if (binaryPath !== null) {
|
|
3642
3814
|
const resolvedServer = {
|
|
3643
3815
|
id: server.id,
|
|
3644
|
-
command: server.command,
|
|
3816
|
+
command: withResolvedCommand(server.command, binaryPath),
|
|
3645
3817
|
extensions: server.extensions,
|
|
3646
3818
|
priority: server.priority
|
|
3647
3819
|
};
|
|
@@ -3688,6 +3860,7 @@ function findServerForExtension(ext) {
|
|
|
3688
3860
|
function getAllServers() {
|
|
3689
3861
|
const servers = getMergedServers();
|
|
3690
3862
|
const disabled = getDisabledServerIds();
|
|
3863
|
+
const workingDirectory = contextCwd();
|
|
3691
3864
|
const result = [];
|
|
3692
3865
|
const seen = new Set;
|
|
3693
3866
|
for (const server of servers) {
|
|
@@ -3695,7 +3868,7 @@ function getAllServers() {
|
|
|
3695
3868
|
continue;
|
|
3696
3869
|
result.push({
|
|
3697
3870
|
id: server.id,
|
|
3698
|
-
installed: isServerInstalled(server.command),
|
|
3871
|
+
installed: isServerInstalled(server.command, workingDirectory),
|
|
3699
3872
|
extensions: server.extensions,
|
|
3700
3873
|
disabled: false,
|
|
3701
3874
|
source: server.source,
|
|
@@ -3709,7 +3882,7 @@ function getAllServers() {
|
|
|
3709
3882
|
const builtin = BUILTIN_SERVERS[id];
|
|
3710
3883
|
result.push({
|
|
3711
3884
|
id,
|
|
3712
|
-
installed: builtin ? isServerInstalled(builtin.command) : false,
|
|
3885
|
+
installed: builtin ? isServerInstalled(builtin.command, workingDirectory) : false,
|
|
3713
3886
|
extensions: builtin?.extensions ?? [],
|
|
3714
3887
|
disabled: true,
|
|
3715
3888
|
source: "disabled",
|
|
@@ -3732,7 +3905,7 @@ function findWorkspaceRoot(filePath) {
|
|
|
3732
3905
|
const abs = resolveReadablePathInsideContext(filePath);
|
|
3733
3906
|
let dir = abs;
|
|
3734
3907
|
if (!isDirectoryPath(dir)) {
|
|
3735
|
-
dir =
|
|
3908
|
+
dir = dirname8(dir);
|
|
3736
3909
|
}
|
|
3737
3910
|
if (!isPathInside(cwd, abs))
|
|
3738
3911
|
return findWorkspaceRootOutsideContext(dir);
|
|
@@ -3748,13 +3921,13 @@ function findWorkspaceRoot(filePath) {
|
|
|
3748
3921
|
}
|
|
3749
3922
|
if (dir === cwd)
|
|
3750
3923
|
break;
|
|
3751
|
-
dir =
|
|
3924
|
+
dir = dirname8(dir);
|
|
3752
3925
|
}
|
|
3753
3926
|
return fallbackRoot;
|
|
3754
3927
|
}
|
|
3755
3928
|
function resolveReadablePathInsideContext(filePath) {
|
|
3756
3929
|
const cwd = contextCwd();
|
|
3757
|
-
const abs =
|
|
3930
|
+
const abs = resolve8(cwd, filePath);
|
|
3758
3931
|
if (isPathInside(cwd, abs))
|
|
3759
3932
|
return abs;
|
|
3760
3933
|
const rebased = rebaseThroughCanonicalAncestor(abs, cwd);
|
|
@@ -3780,7 +3953,7 @@ function rebaseThroughCanonicalAncestor(path, cwd) {
|
|
|
3780
3953
|
if (isPathInside(cwd, canonical))
|
|
3781
3954
|
return suffix.length === 0 ? canonical : join5(canonical, ...suffix);
|
|
3782
3955
|
}
|
|
3783
|
-
const parent =
|
|
3956
|
+
const parent = dirname8(current);
|
|
3784
3957
|
if (parent === current)
|
|
3785
3958
|
return;
|
|
3786
3959
|
suffix.unshift(basename3(current));
|
|
@@ -3803,7 +3976,7 @@ function nearestExistingDirectoryInsideContext(directory, cwd) {
|
|
|
3803
3976
|
return canonical;
|
|
3804
3977
|
if (current === cwd)
|
|
3805
3978
|
return;
|
|
3806
|
-
current =
|
|
3979
|
+
current = dirname8(current);
|
|
3807
3980
|
}
|
|
3808
3981
|
return;
|
|
3809
3982
|
}
|
|
@@ -3830,6 +4003,19 @@ function formatServerLookupError(result) {
|
|
|
3830
4003
|
].join(`
|
|
3831
4004
|
`);
|
|
3832
4005
|
}
|
|
4006
|
+
function formatInstallOptions(serverId, installHint) {
|
|
4007
|
+
const localHint = LSP_LOCAL_INSTALL_HINTS[serverId];
|
|
4008
|
+
if (localHint === undefined) {
|
|
4009
|
+
return ["To install, run:", ` ${installHint}`];
|
|
4010
|
+
}
|
|
4011
|
+
return [
|
|
4012
|
+
"To install in THIS repository (preferred — no global install needed):",
|
|
4013
|
+
` ${localHint}`,
|
|
4014
|
+
"",
|
|
4015
|
+
"Or install it globally:",
|
|
4016
|
+
` ${installHint}`
|
|
4017
|
+
];
|
|
4018
|
+
}
|
|
3833
4019
|
function formatNotInstalled(result) {
|
|
3834
4020
|
const { server, installHint } = result;
|
|
3835
4021
|
const extensions = server.extensions.join(", ");
|
|
@@ -3844,19 +4030,19 @@ function formatNotInstalled(result) {
|
|
|
3844
4030
|
`Command not found: ${server.command[0]}`,
|
|
3845
4031
|
""
|
|
3846
4032
|
];
|
|
4033
|
+
const installOptions = formatInstallOptions(server.id, installHint);
|
|
3847
4034
|
if (decision === "allowed") {
|
|
3848
4035
|
return [
|
|
3849
4036
|
...header,
|
|
3850
4037
|
"The user has pre-authorized LSP installation. Run the install command, then retry this tool:",
|
|
3851
|
-
|
|
4038
|
+
...installOptions.slice(1)
|
|
3852
4039
|
].join(`
|
|
3853
4040
|
`);
|
|
3854
4041
|
}
|
|
3855
4042
|
if (!context.capabilities.installDecisionTool) {
|
|
3856
4043
|
return [
|
|
3857
4044
|
...header,
|
|
3858
|
-
|
|
3859
|
-
` ${installHint}`,
|
|
4045
|
+
...installOptions,
|
|
3860
4046
|
"",
|
|
3861
4047
|
"ACTION REQUIRED — ASK THE USER whether to install this LSP server.",
|
|
3862
4048
|
"Install-decision recording is unavailable in this harness; proceed without LSP if the user declines."
|
|
@@ -3865,8 +4051,7 @@ function formatNotInstalled(result) {
|
|
|
3865
4051
|
}
|
|
3866
4052
|
return [
|
|
3867
4053
|
...header,
|
|
3868
|
-
|
|
3869
|
-
` ${installHint}`,
|
|
4054
|
+
...installOptions,
|
|
3870
4055
|
"",
|
|
3871
4056
|
"ACTION REQUIRED — ASK THE USER whether to install this LSP server.",
|
|
3872
4057
|
"- If the user agrees: run the install command above, then retry this tool.",
|
|
@@ -3922,7 +4107,7 @@ async function withLspClient(filePath, fn, toolName, options = {}) {
|
|
|
3922
4107
|
|
|
3923
4108
|
// ../lsp-core/src/lsp/directory-diagnostics.ts
|
|
3924
4109
|
import { existsSync as existsSync11, lstatSync as lstatSync4, readdirSync as readdirSync3 } from "node:fs";
|
|
3925
|
-
import { join as join6, resolve as
|
|
4110
|
+
import { join as join6, resolve as resolve9 } from "node:path";
|
|
3926
4111
|
|
|
3927
4112
|
// ../lsp-core/src/lsp/formatters.ts
|
|
3928
4113
|
import { fileURLToPath as fileURLToPath2 } from "node:url";
|
|
@@ -4077,7 +4262,7 @@ async function aggregateDiagnosticsForDirectory(directory, extension, severity,
|
|
|
4077
4262
|
if (!extension.startsWith(".")) {
|
|
4078
4263
|
throw new LspInvalidPathError(`Extension must start with a dot (e.g., ".ts", not "${extension}"). Use ".${extension}" instead.`);
|
|
4079
4264
|
}
|
|
4080
|
-
const absDir =
|
|
4265
|
+
const absDir = resolve9(options.workspaceRoot ?? contextCwd(), directory);
|
|
4081
4266
|
if (!existsSync11(absDir)) {
|
|
4082
4267
|
throw new LspInvalidPathError(`Directory does not exist: ${absDir}`);
|
|
4083
4268
|
}
|
|
@@ -4434,6 +4619,96 @@ async function executeLspDiagnostics(params, signal) {
|
|
|
4434
4619
|
throw error;
|
|
4435
4620
|
}
|
|
4436
4621
|
}
|
|
4622
|
+
// ../lsp-core/src/lsp/format-document.ts
|
|
4623
|
+
import { readFileSync as readFileSync5, renameSync as renameSync3, unlinkSync, writeFileSync as writeFileSync3 } from "node:fs";
|
|
4624
|
+
var DEFAULT_FORMATTING_OPTIONS = {
|
|
4625
|
+
tabSize: 4,
|
|
4626
|
+
insertSpaces: false,
|
|
4627
|
+
trimTrailingWhitespace: true,
|
|
4628
|
+
insertFinalNewline: true,
|
|
4629
|
+
trimFinalNewlines: true
|
|
4630
|
+
};
|
|
4631
|
+
var UNCHANGED = { status: "unchanged", linesAdded: 0, linesRemoved: 0 };
|
|
4632
|
+
async function formatDocumentWithClient(client, filePath, options = {}) {
|
|
4633
|
+
const edits = await client.formatDocument(filePath, options.formattingOptions ?? DEFAULT_FORMATTING_OPTIONS, options.signal);
|
|
4634
|
+
if (edits === null)
|
|
4635
|
+
return { status: "unavailable", reason: "capability_not_advertised" };
|
|
4636
|
+
if (edits.length === 0)
|
|
4637
|
+
return UNCHANGED;
|
|
4638
|
+
const before = readFileSync5(filePath, "utf-8");
|
|
4639
|
+
const normalized = normalizeTextEdits(before, edits, 0);
|
|
4640
|
+
if (normalized.text === before)
|
|
4641
|
+
return UNCHANGED;
|
|
4642
|
+
writeAtomically(filePath, normalized.text);
|
|
4643
|
+
await client.openFile(filePath);
|
|
4644
|
+
return {
|
|
4645
|
+
status: "formatted",
|
|
4646
|
+
...lineDelta(normalized.edits)
|
|
4647
|
+
};
|
|
4648
|
+
}
|
|
4649
|
+
function lineDelta(edits) {
|
|
4650
|
+
let linesAdded = 0;
|
|
4651
|
+
let linesRemoved = 0;
|
|
4652
|
+
for (const edit of edits) {
|
|
4653
|
+
linesRemoved += edit.range.end.line - edit.range.start.line + 1;
|
|
4654
|
+
linesAdded += edit.newText.split(`
|
|
4655
|
+
`).length;
|
|
4656
|
+
}
|
|
4657
|
+
return { linesAdded, linesRemoved };
|
|
4658
|
+
}
|
|
4659
|
+
function writeAtomically(filePath, content) {
|
|
4660
|
+
const tempPath = `${filePath}.omo-format.tmp`;
|
|
4661
|
+
writeFileSync3(tempPath, content, "utf-8");
|
|
4662
|
+
try {
|
|
4663
|
+
renameSync3(tempPath, filePath);
|
|
4664
|
+
} catch (error) {
|
|
4665
|
+
try {
|
|
4666
|
+
unlinkSync(tempPath);
|
|
4667
|
+
} catch {}
|
|
4668
|
+
throw error;
|
|
4669
|
+
}
|
|
4670
|
+
}
|
|
4671
|
+
|
|
4672
|
+
// ../lsp-core/src/tools/format.ts
|
|
4673
|
+
async function executeLspFormat(params, signal) {
|
|
4674
|
+
const filePath = requireString(params, "filePath");
|
|
4675
|
+
try {
|
|
4676
|
+
const result = await withLspClient(filePath, async (client, _workspaceRoot, resolvedFilePath) => formatDocumentWithClient(client, resolvedFilePath, signal === undefined ? {} : { signal }), "format", clientOptions(signal));
|
|
4677
|
+
return text(describeResult(filePath, result), formatDetails(filePath, result));
|
|
4678
|
+
} catch (error) {
|
|
4679
|
+
const missingDependency = missingDependencyResult(error, {
|
|
4680
|
+
filePath,
|
|
4681
|
+
status: "unavailable",
|
|
4682
|
+
reason: "server_unavailable",
|
|
4683
|
+
linesAdded: 0,
|
|
4684
|
+
linesRemoved: 0
|
|
4685
|
+
});
|
|
4686
|
+
if (missingDependency)
|
|
4687
|
+
return missingDependency;
|
|
4688
|
+
throw error;
|
|
4689
|
+
}
|
|
4690
|
+
}
|
|
4691
|
+
function formatDetails(filePath, result) {
|
|
4692
|
+
if (result.status === "unavailable") {
|
|
4693
|
+
return { filePath, status: "unavailable", reason: result.reason, linesAdded: 0, linesRemoved: 0 };
|
|
4694
|
+
}
|
|
4695
|
+
return {
|
|
4696
|
+
filePath,
|
|
4697
|
+
status: result.status,
|
|
4698
|
+
linesAdded: result.linesAdded,
|
|
4699
|
+
linesRemoved: result.linesRemoved
|
|
4700
|
+
};
|
|
4701
|
+
}
|
|
4702
|
+
function describeResult(filePath, result) {
|
|
4703
|
+
if (result.status === "unavailable") {
|
|
4704
|
+
return `Formatting unavailable for ${filePath}: the language server does not advertise documentFormattingProvider.`;
|
|
4705
|
+
}
|
|
4706
|
+
if (result.status === "unchanged") {
|
|
4707
|
+
return `Already formatted: ${filePath}`;
|
|
4708
|
+
}
|
|
4709
|
+
return `Formatted ${filePath} (+${result.linesAdded}/-${result.linesRemoved} lines)`;
|
|
4710
|
+
}
|
|
4711
|
+
|
|
4437
4712
|
// ../lsp-core/src/tools/install-decision.ts
|
|
4438
4713
|
async function executeLspInstallDecision(params) {
|
|
4439
4714
|
const serverId = requireString(params, "server_id");
|
|
@@ -4766,6 +5041,16 @@ var LSP_MCP_TOOLS = [
|
|
|
4766
5041
|
}, ["filePath", "line", "character", "newName"]),
|
|
4767
5042
|
execute: executeLspRename
|
|
4768
5043
|
},
|
|
5044
|
+
{
|
|
5045
|
+
name: "format",
|
|
5046
|
+
aliases: ["lsp_format"],
|
|
5047
|
+
title: "LSP Format",
|
|
5048
|
+
description: "Format a source file with its language server and write the returned edits to disk.",
|
|
5049
|
+
inputSchema: objectSchema({
|
|
5050
|
+
filePath: { type: "string", description: "Source file path to format." }
|
|
5051
|
+
}, ["filePath"]),
|
|
5052
|
+
execute: executeLspFormat
|
|
5053
|
+
},
|
|
4769
5054
|
{
|
|
4770
5055
|
name: "install_decision",
|
|
4771
5056
|
aliases: ["lsp_install_decision"],
|
|
@@ -4803,6 +5088,7 @@ export {
|
|
|
4803
5088
|
coerceToolArguments,
|
|
4804
5089
|
executeLspDiagnostics,
|
|
4805
5090
|
executeLspFindReferences,
|
|
5091
|
+
executeLspFormat,
|
|
4806
5092
|
executeLspGotoDefinition,
|
|
4807
5093
|
executeLspInstallDecision,
|
|
4808
5094
|
executeLspPrepareRename,
|