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
|
@@ -23,6 +23,7 @@ var DEFAULT_MAX_DIRECTORY_FILES = 50;
|
|
|
23
23
|
var REQUEST_TIMEOUT_MS = 15000;
|
|
24
24
|
var INIT_TIMEOUT_MS = 60000;
|
|
25
25
|
var IDLE_TIMEOUT_MS = 5 * 60000;
|
|
26
|
+
var MAX_RESIDENT_CLIENTS = 6;
|
|
26
27
|
var REAPER_INTERVAL_MS = 60000;
|
|
27
28
|
var STOP_HARD_KILL_TIMEOUT_MS = 5000;
|
|
28
29
|
var STOP_SIGKILL_GRACE_MS = 1000;
|
|
@@ -615,6 +616,7 @@ class LspClientTransport {
|
|
|
615
616
|
this.diagnosticsStore = new Map;
|
|
616
617
|
this.workspaceApplyEditHandler = null;
|
|
617
618
|
this.diagnosticPullSupported = false;
|
|
619
|
+
this.documentFormattingSupported = false;
|
|
618
620
|
this.requestTimeoutMs = timeouts.requestTimeoutMs ?? REQUEST_TIMEOUT_MS;
|
|
619
621
|
this.initializeTimeoutMs = timeouts.initializeTimeoutMs ?? INIT_TIMEOUT_MS;
|
|
620
622
|
}
|
|
@@ -636,6 +638,12 @@ class LspClientTransport {
|
|
|
636
638
|
isDiagnosticPullSupported() {
|
|
637
639
|
return this.diagnosticPullSupported;
|
|
638
640
|
}
|
|
641
|
+
setDocumentFormattingSupported(supported) {
|
|
642
|
+
this.documentFormattingSupported = supported;
|
|
643
|
+
}
|
|
644
|
+
isDocumentFormattingSupported() {
|
|
645
|
+
return this.documentFormattingSupported;
|
|
646
|
+
}
|
|
639
647
|
handlePublishDiagnostics(params) {
|
|
640
648
|
this.diagnosticsStore.set(params.uri, [...params.diagnostics]);
|
|
641
649
|
}
|
|
@@ -849,6 +857,14 @@ function supportsDiagnosticPull(capabilities) {
|
|
|
849
857
|
return false;
|
|
850
858
|
return Object.hasOwn(capabilities, "diagnosticProvider");
|
|
851
859
|
}
|
|
860
|
+
function supportsDocumentFormatting(capabilities) {
|
|
861
|
+
if (capabilities === undefined)
|
|
862
|
+
return false;
|
|
863
|
+
const provider = capabilities.documentFormattingProvider;
|
|
864
|
+
if (provider === undefined || provider === null || provider === false)
|
|
865
|
+
return false;
|
|
866
|
+
return provider === true || typeof provider === "object";
|
|
867
|
+
}
|
|
852
868
|
|
|
853
869
|
class LspClientConnection extends LspClientTransport {
|
|
854
870
|
async initialize() {
|
|
@@ -865,6 +881,7 @@ class LspClientConnection extends LspClientTransport {
|
|
|
865
881
|
references: {},
|
|
866
882
|
documentSymbol: { hierarchicalDocumentSymbolSupport: true },
|
|
867
883
|
publishDiagnostics: {},
|
|
884
|
+
formatting: { dynamicRegistration: false },
|
|
868
885
|
rename: {
|
|
869
886
|
prepareSupport: true,
|
|
870
887
|
prepareSupportDefaultBehavior: 1
|
|
@@ -906,6 +923,7 @@ class LspClientConnection extends LspClientTransport {
|
|
|
906
923
|
initializationOptions: this.server.initialization
|
|
907
924
|
}, { timeoutMs: this.initializeTimeoutMs });
|
|
908
925
|
this.setDiagnosticPullSupported(supportsDiagnosticPull(result?.capabilities));
|
|
926
|
+
this.setDocumentFormattingSupported(supportsDocumentFormatting(result?.capabilities));
|
|
909
927
|
await this.sendNotification("initialized", {});
|
|
910
928
|
await this.sendNotification("workspace/didChangeConfiguration", {
|
|
911
929
|
settings: { json: { validate: { enable: true } } }
|
|
@@ -2500,6 +2518,18 @@ class LspClient extends LspClientConnection {
|
|
|
2500
2518
|
textDocument: { uri: pathToFileURL3(absPath).href }
|
|
2501
2519
|
}, options);
|
|
2502
2520
|
}
|
|
2521
|
+
async formatDocument(filePath, options, signal) {
|
|
2522
|
+
if (!this.isDocumentFormattingSupported())
|
|
2523
|
+
return null;
|
|
2524
|
+
const absPath = this.resolveWorkspacePath(filePath);
|
|
2525
|
+
await this.openFile(absPath);
|
|
2526
|
+
const requestOptions = signal === undefined ? {} : { signal };
|
|
2527
|
+
const edits = await this.sendRequest("textDocument/formatting", {
|
|
2528
|
+
textDocument: { uri: pathToFileURL3(absPath).href },
|
|
2529
|
+
options
|
|
2530
|
+
}, requestOptions);
|
|
2531
|
+
return edits ?? [];
|
|
2532
|
+
}
|
|
2503
2533
|
async workspaceSymbols(query, signal) {
|
|
2504
2534
|
const options = signal === undefined ? {} : { signal };
|
|
2505
2535
|
return this.sendRequest("workspace/symbol", { query }, options);
|
|
@@ -2752,6 +2782,7 @@ class LspManager {
|
|
|
2752
2782
|
this.disposed = false;
|
|
2753
2783
|
this.idleTimeoutMs = options.idleTimeoutMs ?? IDLE_TIMEOUT_MS;
|
|
2754
2784
|
this.initTimeoutMs = options.initTimeoutMs ?? INIT_TIMEOUT_MS;
|
|
2785
|
+
this.maxResidentClients = options.maxResidentClients ?? MAX_RESIDENT_CLIENTS;
|
|
2755
2786
|
this.reaperIntervalMs = options.reaperIntervalMs ?? REAPER_INTERVAL_MS;
|
|
2756
2787
|
this.clientFactory = options.clientFactory ?? ((root, server) => new LspClient(root, server));
|
|
2757
2788
|
this.now = options.now ?? (() => Date.now());
|
|
@@ -2785,6 +2816,26 @@ class LspManager {
|
|
|
2785
2816
|
}
|
|
2786
2817
|
}
|
|
2787
2818
|
}
|
|
2819
|
+
evictForAdmission() {
|
|
2820
|
+
while (this.clients.size >= this.maxResidentClients) {
|
|
2821
|
+
const victim = this.leastRecentlyUsedIdleClient();
|
|
2822
|
+
if (!victim)
|
|
2823
|
+
return;
|
|
2824
|
+
this.clients.delete(victim.key);
|
|
2825
|
+
stopClientBestEffort(victim.managed.client);
|
|
2826
|
+
}
|
|
2827
|
+
}
|
|
2828
|
+
leastRecentlyUsedIdleClient() {
|
|
2829
|
+
let candidate = null;
|
|
2830
|
+
for (const [key, managed] of this.clients) {
|
|
2831
|
+
if (managed.refCount > 0 || managed.pendingWaiters > 0 || managed.isInitializing)
|
|
2832
|
+
continue;
|
|
2833
|
+
if (candidate === null || managed.lastUsedAt < candidate.managed.lastUsedAt) {
|
|
2834
|
+
candidate = { key, managed };
|
|
2835
|
+
}
|
|
2836
|
+
}
|
|
2837
|
+
return candidate;
|
|
2838
|
+
}
|
|
2788
2839
|
async tryDeleteIfOrphaned(key, managed) {
|
|
2789
2840
|
if (managed.refCount === 0 && managed.pendingWaiters === 0 && !managed.isInitializing && this.clients.get(key) === managed) {
|
|
2790
2841
|
this.clients.delete(key);
|
|
@@ -2831,6 +2882,7 @@ class LspManager {
|
|
|
2831
2882
|
managed.lastUsedAt = this.now();
|
|
2832
2883
|
return managed.client;
|
|
2833
2884
|
}
|
|
2885
|
+
this.evictForAdmission();
|
|
2834
2886
|
const client = this.clientFactory(root, server);
|
|
2835
2887
|
const initStartedAt = this.now();
|
|
2836
2888
|
const initPromise = (async () => {
|
|
@@ -2893,6 +2945,7 @@ class LspManager {
|
|
|
2893
2945
|
const key = this.getKey(root, server.id);
|
|
2894
2946
|
if (this.clients.has(key))
|
|
2895
2947
|
return;
|
|
2948
|
+
this.evictForAdmission();
|
|
2896
2949
|
const client = this.clientFactory(root, server);
|
|
2897
2950
|
const initStartedAt = this.now();
|
|
2898
2951
|
const initPromise = (async () => {
|
|
@@ -4121,7 +4174,7 @@ function createIdleTimer(idleTimeoutMs, log, onTimeout) {
|
|
|
4121
4174
|
}
|
|
4122
4175
|
// ../lsp-core/src/lsp/client-wrapper.ts
|
|
4123
4176
|
import { existsSync as existsSync11, realpathSync as realpathSync5, statSync as statSync4 } from "node:fs";
|
|
4124
|
-
import { basename as basename3, dirname as
|
|
4177
|
+
import { basename as basename3, dirname as dirname10, join as join5, resolve as resolve8 } from "node:path";
|
|
4125
4178
|
|
|
4126
4179
|
// ../lsp-core/src/lsp/outside-context-workspace.ts
|
|
4127
4180
|
import { existsSync as existsSync7, realpathSync as realpathSync4 } from "node:fs";
|
|
@@ -4160,57 +4213,6 @@ function nearestExistingAncestor(directory) {
|
|
|
4160
4213
|
return current;
|
|
4161
4214
|
}
|
|
4162
4215
|
|
|
4163
|
-
// ../lsp-core/src/lsp/server-install-state.ts
|
|
4164
|
-
import { existsSync as existsSync8, mkdirSync as mkdirSync3, readFileSync as readFileSync4, renameSync as renameSync2, writeFileSync as writeFileSync2 } from "node:fs";
|
|
4165
|
-
import { dirname as dirname8 } from "node:path";
|
|
4166
|
-
function getInstallDecisionsPath() {
|
|
4167
|
-
return lspRequestContext().installDecisionsPath;
|
|
4168
|
-
}
|
|
4169
|
-
function loadInstallDecisions() {
|
|
4170
|
-
const path2 = getInstallDecisionsPath();
|
|
4171
|
-
if (!existsSync8(path2))
|
|
4172
|
-
return {};
|
|
4173
|
-
try {
|
|
4174
|
-
const parsed = JSON.parse(readFileSync4(path2, "utf8"));
|
|
4175
|
-
return isInstallDecisions(parsed) ? parsed : {};
|
|
4176
|
-
} catch {
|
|
4177
|
-
return {};
|
|
4178
|
-
}
|
|
4179
|
-
}
|
|
4180
|
-
function loadInstallDecision(serverId) {
|
|
4181
|
-
return loadInstallDecisions()[serverId];
|
|
4182
|
-
}
|
|
4183
|
-
function recordInstallDecision(serverId, decision, decidedAt = new Date().toISOString()) {
|
|
4184
|
-
const decisions = loadInstallDecisions();
|
|
4185
|
-
decisions[serverId] = { decision, decidedAt };
|
|
4186
|
-
writeInstallDecisions(decisions);
|
|
4187
|
-
}
|
|
4188
|
-
function isInstallDecision(value) {
|
|
4189
|
-
return value === "declined" || value === "allowed";
|
|
4190
|
-
}
|
|
4191
|
-
function writeInstallDecisions(decisions) {
|
|
4192
|
-
const path2 = getInstallDecisionsPath();
|
|
4193
|
-
mkdirSync3(dirname8(path2), { recursive: true });
|
|
4194
|
-
const tmpPath = `${path2}.tmp`;
|
|
4195
|
-
writeFileSync2(tmpPath, `${JSON.stringify(decisions, null, 2)}
|
|
4196
|
-
`, "utf8");
|
|
4197
|
-
renameSync2(tmpPath, path2);
|
|
4198
|
-
}
|
|
4199
|
-
function isInstallDecisions(value) {
|
|
4200
|
-
return isRecord5(value) && Object.values(value).every(isInstallDecisionRecord);
|
|
4201
|
-
}
|
|
4202
|
-
function isInstallDecisionRecord(value) {
|
|
4203
|
-
if (!isRecord5(value))
|
|
4204
|
-
return false;
|
|
4205
|
-
return isInstallDecision(value["decision"]) && typeof value["decidedAt"] === "string";
|
|
4206
|
-
}
|
|
4207
|
-
function isRecord5(value) {
|
|
4208
|
-
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
4209
|
-
}
|
|
4210
|
-
|
|
4211
|
-
// ../lsp-core/src/lsp/config-loader.ts
|
|
4212
|
-
import { existsSync as existsSync9, readFileSync as readFileSync5 } from "node:fs";
|
|
4213
|
-
|
|
4214
4216
|
// ../lsp-core/src/lsp/server-definitions.ts
|
|
4215
4217
|
var LSP_INSTALL_HINTS = {
|
|
4216
4218
|
typescript: "npm install -g typescript-language-server typescript",
|
|
@@ -4256,6 +4258,26 @@ var LSP_INSTALL_HINTS = {
|
|
|
4256
4258
|
julials: `julia -e 'using Pkg; Pkg.add("LanguageServer")'`,
|
|
4257
4259
|
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"
|
|
4258
4260
|
};
|
|
4261
|
+
var LSP_LOCAL_INSTALL_HINTS = {
|
|
4262
|
+
typescript: "bun add -d typescript-language-server typescript",
|
|
4263
|
+
vue: "bun add -d @vue/language-server",
|
|
4264
|
+
eslint: "bun add -d vscode-langservers-extracted",
|
|
4265
|
+
oxlint: "bun add -d oxlint",
|
|
4266
|
+
biome: "bun add -d @biomejs/biome",
|
|
4267
|
+
svelte: "bun add -d svelte-language-server",
|
|
4268
|
+
astro: "bun add -d @astrojs/language-server",
|
|
4269
|
+
bash: "bun add -d bash-language-server",
|
|
4270
|
+
"bash-ls": "bun add -d bash-language-server",
|
|
4271
|
+
"yaml-ls": "bun add -d yaml-language-server",
|
|
4272
|
+
php: "bun add -d intelephense",
|
|
4273
|
+
prisma: "bun add -d prisma",
|
|
4274
|
+
dockerfile: "bun add -d dockerfile-language-server-nodejs",
|
|
4275
|
+
pyright: "uv add --dev pyright",
|
|
4276
|
+
basedpyright: "uv add --dev basedpyright",
|
|
4277
|
+
ruff: "uv add --dev ruff",
|
|
4278
|
+
ty: "uv add --dev ty",
|
|
4279
|
+
"ruby-lsp": "bundle add ruby-lsp --group development"
|
|
4280
|
+
};
|
|
4259
4281
|
var BUILTIN_SERVERS = {
|
|
4260
4282
|
typescript: {
|
|
4261
4283
|
command: ["typescript-language-server", "--stdio"],
|
|
@@ -4358,7 +4380,56 @@ var BUILTIN_SERVERS = {
|
|
|
4358
4380
|
}
|
|
4359
4381
|
};
|
|
4360
4382
|
|
|
4383
|
+
// ../lsp-core/src/lsp/server-install-state.ts
|
|
4384
|
+
import { existsSync as existsSync8, mkdirSync as mkdirSync3, readFileSync as readFileSync4, renameSync as renameSync2, writeFileSync as writeFileSync2 } from "node:fs";
|
|
4385
|
+
import { dirname as dirname8 } from "node:path";
|
|
4386
|
+
function getInstallDecisionsPath() {
|
|
4387
|
+
return lspRequestContext().installDecisionsPath;
|
|
4388
|
+
}
|
|
4389
|
+
function loadInstallDecisions() {
|
|
4390
|
+
const path2 = getInstallDecisionsPath();
|
|
4391
|
+
if (!existsSync8(path2))
|
|
4392
|
+
return {};
|
|
4393
|
+
try {
|
|
4394
|
+
const parsed = JSON.parse(readFileSync4(path2, "utf8"));
|
|
4395
|
+
return isInstallDecisions(parsed) ? parsed : {};
|
|
4396
|
+
} catch {
|
|
4397
|
+
return {};
|
|
4398
|
+
}
|
|
4399
|
+
}
|
|
4400
|
+
function loadInstallDecision(serverId) {
|
|
4401
|
+
return loadInstallDecisions()[serverId];
|
|
4402
|
+
}
|
|
4403
|
+
function recordInstallDecision(serverId, decision, decidedAt = new Date().toISOString()) {
|
|
4404
|
+
const decisions = loadInstallDecisions();
|
|
4405
|
+
decisions[serverId] = { decision, decidedAt };
|
|
4406
|
+
writeInstallDecisions(decisions);
|
|
4407
|
+
}
|
|
4408
|
+
function isInstallDecision(value) {
|
|
4409
|
+
return value === "declined" || value === "allowed";
|
|
4410
|
+
}
|
|
4411
|
+
function writeInstallDecisions(decisions) {
|
|
4412
|
+
const path2 = getInstallDecisionsPath();
|
|
4413
|
+
mkdirSync3(dirname8(path2), { recursive: true });
|
|
4414
|
+
const tmpPath = `${path2}.tmp`;
|
|
4415
|
+
writeFileSync2(tmpPath, `${JSON.stringify(decisions, null, 2)}
|
|
4416
|
+
`, "utf8");
|
|
4417
|
+
renameSync2(tmpPath, path2);
|
|
4418
|
+
}
|
|
4419
|
+
function isInstallDecisions(value) {
|
|
4420
|
+
return isRecord5(value) && Object.values(value).every(isInstallDecisionRecord);
|
|
4421
|
+
}
|
|
4422
|
+
function isInstallDecisionRecord(value) {
|
|
4423
|
+
if (!isRecord5(value))
|
|
4424
|
+
return false;
|
|
4425
|
+
return isInstallDecision(value["decision"]) && typeof value["decidedAt"] === "string";
|
|
4426
|
+
}
|
|
4427
|
+
function isRecord5(value) {
|
|
4428
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
4429
|
+
}
|
|
4430
|
+
|
|
4361
4431
|
// ../lsp-core/src/lsp/config-loader.ts
|
|
4432
|
+
import { existsSync as existsSync9, readFileSync as readFileSync5 } from "node:fs";
|
|
4362
4433
|
function getProjectConfigPaths() {
|
|
4363
4434
|
return lspRequestContext().projectConfigPaths;
|
|
4364
4435
|
}
|
|
@@ -4555,53 +4626,154 @@ function getDisabledServerIds() {
|
|
|
4555
4626
|
|
|
4556
4627
|
// ../lsp-core/src/lsp/server-installation.ts
|
|
4557
4628
|
import { existsSync as existsSync10 } from "node:fs";
|
|
4558
|
-
import { delimiter as delimiter3, join as join4 } from "node:path";
|
|
4559
|
-
|
|
4560
|
-
|
|
4561
|
-
|
|
4562
|
-
|
|
4563
|
-
|
|
4564
|
-
|
|
4565
|
-
|
|
4566
|
-
|
|
4567
|
-
|
|
4629
|
+
import { delimiter as delimiter3, dirname as dirname9, isAbsolute as isAbsolute5, join as join4, resolve as resolve7 } from "node:path";
|
|
4630
|
+
var LOCAL_BIN_RULES = [
|
|
4631
|
+
{
|
|
4632
|
+
markers: ["package.json", "bun.lock", "bun.lockb", "package-lock.json", "yarn.lock", "pnpm-lock.yaml"],
|
|
4633
|
+
binDirs: [join4("node_modules", ".bin")]
|
|
4634
|
+
},
|
|
4635
|
+
{
|
|
4636
|
+
markers: [
|
|
4637
|
+
"pyproject.toml",
|
|
4638
|
+
"ty.toml",
|
|
4639
|
+
"requirements.txt",
|
|
4640
|
+
"setup.py",
|
|
4641
|
+
"setup.cfg",
|
|
4642
|
+
"Pipfile",
|
|
4643
|
+
"pyrightconfig.json",
|
|
4644
|
+
"ruff.toml",
|
|
4645
|
+
".ruff.toml"
|
|
4646
|
+
],
|
|
4647
|
+
binDirs: [
|
|
4648
|
+
join4(".venv", "bin"),
|
|
4649
|
+
join4(".venv", "Scripts"),
|
|
4650
|
+
join4("venv", "bin"),
|
|
4651
|
+
join4("venv", "Scripts"),
|
|
4652
|
+
join4(".env", "bin"),
|
|
4653
|
+
join4(".env", "Scripts")
|
|
4654
|
+
]
|
|
4655
|
+
},
|
|
4656
|
+
{
|
|
4657
|
+
markers: ["Gemfile", "Gemfile.lock"],
|
|
4658
|
+
binDirs: [join4("vendor", "bundle", "bin"), "bin"]
|
|
4659
|
+
},
|
|
4660
|
+
{
|
|
4661
|
+
markers: ["go.mod", "go.sum", "go.work"],
|
|
4662
|
+
binDirs: ["bin"]
|
|
4568
4663
|
}
|
|
4569
|
-
|
|
4570
|
-
|
|
4571
|
-
|
|
4572
|
-
|
|
4573
|
-
|
|
4574
|
-
|
|
4575
|
-
|
|
4576
|
-
|
|
4577
|
-
|
|
4664
|
+
];
|
|
4665
|
+
var resolutionCache = new Map;
|
|
4666
|
+
var probeCount = 0;
|
|
4667
|
+
function probe(path2) {
|
|
4668
|
+
probeCount += 1;
|
|
4669
|
+
return existsSync10(path2);
|
|
4670
|
+
}
|
|
4671
|
+
function executableSuffixes(platform, pathExt) {
|
|
4672
|
+
if (platform !== "win32")
|
|
4673
|
+
return [""];
|
|
4674
|
+
const configured = pathExt ?? process.env["PATHEXT"] ?? "";
|
|
4675
|
+
const systemExts = configured.split(";").filter((entry) => entry.length > 0).map((entry) => entry.toLowerCase());
|
|
4676
|
+
return [...new Set(["", ...systemExts, ".exe", ".cmd", ".bat", ".ps1"])];
|
|
4677
|
+
}
|
|
4678
|
+
function probeWithSuffixes(directory, command, suffixes) {
|
|
4679
|
+
for (const suffix of suffixes) {
|
|
4680
|
+
const candidate = join4(directory, command + suffix);
|
|
4681
|
+
if (probe(candidate))
|
|
4682
|
+
return candidate;
|
|
4683
|
+
}
|
|
4684
|
+
return null;
|
|
4685
|
+
}
|
|
4686
|
+
function resolveLocal(command, workingDirectory, suffixes, stopAt) {
|
|
4687
|
+
const boundary = stopAt === undefined ? undefined : resolve7(stopAt);
|
|
4688
|
+
let current = resolve7(workingDirectory);
|
|
4689
|
+
while (true) {
|
|
4690
|
+
for (const rule of LOCAL_BIN_RULES) {
|
|
4691
|
+
if (!rule.markers.some((marker) => probe(join4(current, marker))))
|
|
4692
|
+
continue;
|
|
4693
|
+
for (const binDir of rule.binDirs) {
|
|
4694
|
+
const found = probeWithSuffixes(join4(current, binDir), command, suffixes);
|
|
4695
|
+
if (found !== null)
|
|
4696
|
+
return found;
|
|
4697
|
+
}
|
|
4578
4698
|
}
|
|
4699
|
+
if (probe(join4(current, ".git")))
|
|
4700
|
+
return null;
|
|
4701
|
+
if (boundary !== undefined && current === boundary)
|
|
4702
|
+
return null;
|
|
4703
|
+
const parent = dirname9(current);
|
|
4704
|
+
if (parent === current)
|
|
4705
|
+
return null;
|
|
4706
|
+
current = parent;
|
|
4579
4707
|
}
|
|
4580
|
-
|
|
4581
|
-
|
|
4708
|
+
}
|
|
4709
|
+
function resolveFromPath(command, suffixes, platform, pathEnvOverride) {
|
|
4710
|
+
let pathEnv = pathEnvOverride ?? process.env["PATH"] ?? "";
|
|
4711
|
+
if (platform === "win32" && !pathEnv) {
|
|
4582
4712
|
pathEnv = process.env["Path"] ?? "";
|
|
4583
4713
|
}
|
|
4584
|
-
const
|
|
4585
|
-
|
|
4586
|
-
|
|
4587
|
-
|
|
4588
|
-
|
|
4589
|
-
|
|
4590
|
-
}
|
|
4714
|
+
for (const entry of pathEnv.split(delimiter3)) {
|
|
4715
|
+
if (entry.length === 0)
|
|
4716
|
+
continue;
|
|
4717
|
+
const found = probeWithSuffixes(entry, command, suffixes);
|
|
4718
|
+
if (found !== null)
|
|
4719
|
+
return found;
|
|
4591
4720
|
}
|
|
4592
|
-
|
|
4593
|
-
|
|
4594
|
-
|
|
4721
|
+
return null;
|
|
4722
|
+
}
|
|
4723
|
+
function resolveServerBinary(command, workingDirectory, options = {}) {
|
|
4724
|
+
if (command.length === 0)
|
|
4725
|
+
return null;
|
|
4726
|
+
const [cmd] = command;
|
|
4727
|
+
if (cmd === undefined || cmd.length === 0)
|
|
4728
|
+
return null;
|
|
4729
|
+
const platform = options.platform ?? process.platform;
|
|
4730
|
+
const suffixes = executableSuffixes(platform, options.pathExt);
|
|
4731
|
+
if (cmd.includes("/") || cmd.includes("\\")) {
|
|
4732
|
+
const explicit = isAbsolute5(cmd) ? cmd : resolve7(workingDirectory ?? process.cwd(), cmd);
|
|
4733
|
+
return probe(explicit) ? explicit : null;
|
|
4734
|
+
}
|
|
4735
|
+
const cacheKey = JSON.stringify([
|
|
4736
|
+
workingDirectory ?? "",
|
|
4737
|
+
cmd,
|
|
4738
|
+
platform,
|
|
4739
|
+
options.stopAt ?? "",
|
|
4740
|
+
options.pathExt ?? "",
|
|
4741
|
+
options.pathEnv ?? process.env["PATH"] ?? ""
|
|
4742
|
+
]);
|
|
4743
|
+
const cached = resolutionCache.get(cacheKey);
|
|
4744
|
+
if (cached !== undefined)
|
|
4745
|
+
return cached;
|
|
4746
|
+
let resolved = null;
|
|
4747
|
+
if (workingDirectory !== undefined && workingDirectory.length > 0) {
|
|
4748
|
+
resolved = resolveLocal(cmd, workingDirectory, suffixes, options.stopAt);
|
|
4749
|
+
}
|
|
4750
|
+
resolved ??= resolveFromPath(cmd, suffixes, platform, options.pathEnv);
|
|
4751
|
+
if (resolved === null && cmd === "node")
|
|
4752
|
+
resolved = cmd;
|
|
4753
|
+
resolutionCache.set(cacheKey, resolved);
|
|
4754
|
+
return resolved;
|
|
4755
|
+
}
|
|
4756
|
+
function isServerInstalled(command, workingDirectory, options = {}) {
|
|
4757
|
+
if (command.length === 0)
|
|
4758
|
+
return false;
|
|
4759
|
+
return resolveServerBinary(command, workingDirectory, options) !== null;
|
|
4595
4760
|
}
|
|
4596
4761
|
|
|
4597
4762
|
// ../lsp-core/src/lsp/server-resolution.ts
|
|
4763
|
+
function withResolvedCommand(command, binaryPath) {
|
|
4764
|
+
return [binaryPath, ...command.slice(1)];
|
|
4765
|
+
}
|
|
4598
4766
|
function findServerForExtension(ext) {
|
|
4599
4767
|
const servers = getMergedServers();
|
|
4768
|
+
const workingDirectory = contextCwd();
|
|
4600
4769
|
for (const server2 of servers) {
|
|
4601
|
-
if (server2.extensions.includes(ext)
|
|
4770
|
+
if (!server2.extensions.includes(ext))
|
|
4771
|
+
continue;
|
|
4772
|
+
const binaryPath = resolveServerBinary(server2.command, workingDirectory);
|
|
4773
|
+
if (binaryPath !== null) {
|
|
4602
4774
|
const resolvedServer = {
|
|
4603
4775
|
id: server2.id,
|
|
4604
|
-
command: server2.command,
|
|
4776
|
+
command: withResolvedCommand(server2.command, binaryPath),
|
|
4605
4777
|
extensions: server2.extensions,
|
|
4606
4778
|
priority: server2.priority
|
|
4607
4779
|
};
|
|
@@ -4648,6 +4820,7 @@ function findServerForExtension(ext) {
|
|
|
4648
4820
|
function getAllServers() {
|
|
4649
4821
|
const servers = getMergedServers();
|
|
4650
4822
|
const disabled = getDisabledServerIds();
|
|
4823
|
+
const workingDirectory = contextCwd();
|
|
4651
4824
|
const result = [];
|
|
4652
4825
|
const seen = new Set;
|
|
4653
4826
|
for (const server2 of servers) {
|
|
@@ -4655,7 +4828,7 @@ function getAllServers() {
|
|
|
4655
4828
|
continue;
|
|
4656
4829
|
result.push({
|
|
4657
4830
|
id: server2.id,
|
|
4658
|
-
installed: isServerInstalled(server2.command),
|
|
4831
|
+
installed: isServerInstalled(server2.command, workingDirectory),
|
|
4659
4832
|
extensions: server2.extensions,
|
|
4660
4833
|
disabled: false,
|
|
4661
4834
|
source: server2.source,
|
|
@@ -4669,7 +4842,7 @@ function getAllServers() {
|
|
|
4669
4842
|
const builtin = BUILTIN_SERVERS[id];
|
|
4670
4843
|
result.push({
|
|
4671
4844
|
id,
|
|
4672
|
-
installed: builtin ? isServerInstalled(builtin.command) : false,
|
|
4845
|
+
installed: builtin ? isServerInstalled(builtin.command, workingDirectory) : false,
|
|
4673
4846
|
extensions: builtin?.extensions ?? [],
|
|
4674
4847
|
disabled: true,
|
|
4675
4848
|
source: "disabled",
|
|
@@ -4692,7 +4865,7 @@ function findWorkspaceRoot(filePath) {
|
|
|
4692
4865
|
const abs = resolveReadablePathInsideContext(filePath);
|
|
4693
4866
|
let dir = abs;
|
|
4694
4867
|
if (!isDirectoryPath(dir)) {
|
|
4695
|
-
dir =
|
|
4868
|
+
dir = dirname10(dir);
|
|
4696
4869
|
}
|
|
4697
4870
|
if (!isPathInside(cwd, abs))
|
|
4698
4871
|
return findWorkspaceRootOutsideContext(dir);
|
|
@@ -4708,13 +4881,13 @@ function findWorkspaceRoot(filePath) {
|
|
|
4708
4881
|
}
|
|
4709
4882
|
if (dir === cwd)
|
|
4710
4883
|
break;
|
|
4711
|
-
dir =
|
|
4884
|
+
dir = dirname10(dir);
|
|
4712
4885
|
}
|
|
4713
4886
|
return fallbackRoot;
|
|
4714
4887
|
}
|
|
4715
4888
|
function resolveReadablePathInsideContext(filePath) {
|
|
4716
4889
|
const cwd = contextCwd();
|
|
4717
|
-
const abs =
|
|
4890
|
+
const abs = resolve8(cwd, filePath);
|
|
4718
4891
|
if (isPathInside(cwd, abs))
|
|
4719
4892
|
return abs;
|
|
4720
4893
|
const rebased = rebaseThroughCanonicalAncestor(abs, cwd);
|
|
@@ -4740,7 +4913,7 @@ function rebaseThroughCanonicalAncestor(path2, cwd) {
|
|
|
4740
4913
|
if (isPathInside(cwd, canonical))
|
|
4741
4914
|
return suffix.length === 0 ? canonical : join5(canonical, ...suffix);
|
|
4742
4915
|
}
|
|
4743
|
-
const parent =
|
|
4916
|
+
const parent = dirname10(current);
|
|
4744
4917
|
if (parent === current)
|
|
4745
4918
|
return;
|
|
4746
4919
|
suffix.unshift(basename3(current));
|
|
@@ -4763,7 +4936,7 @@ function nearestExistingDirectoryInsideContext(directory, cwd) {
|
|
|
4763
4936
|
return canonical;
|
|
4764
4937
|
if (current === cwd)
|
|
4765
4938
|
return;
|
|
4766
|
-
current =
|
|
4939
|
+
current = dirname10(current);
|
|
4767
4940
|
}
|
|
4768
4941
|
return;
|
|
4769
4942
|
}
|
|
@@ -4790,6 +4963,19 @@ function formatServerLookupError(result) {
|
|
|
4790
4963
|
].join(`
|
|
4791
4964
|
`);
|
|
4792
4965
|
}
|
|
4966
|
+
function formatInstallOptions(serverId, installHint) {
|
|
4967
|
+
const localHint = LSP_LOCAL_INSTALL_HINTS[serverId];
|
|
4968
|
+
if (localHint === undefined) {
|
|
4969
|
+
return ["To install, run:", ` ${installHint}`];
|
|
4970
|
+
}
|
|
4971
|
+
return [
|
|
4972
|
+
"To install in THIS repository (preferred — no global install needed):",
|
|
4973
|
+
` ${localHint}`,
|
|
4974
|
+
"",
|
|
4975
|
+
"Or install it globally:",
|
|
4976
|
+
` ${installHint}`
|
|
4977
|
+
];
|
|
4978
|
+
}
|
|
4793
4979
|
function formatNotInstalled(result) {
|
|
4794
4980
|
const { server: server2, installHint } = result;
|
|
4795
4981
|
const extensions = server2.extensions.join(", ");
|
|
@@ -4804,19 +4990,19 @@ function formatNotInstalled(result) {
|
|
|
4804
4990
|
`Command not found: ${server2.command[0]}`,
|
|
4805
4991
|
""
|
|
4806
4992
|
];
|
|
4993
|
+
const installOptions = formatInstallOptions(server2.id, installHint);
|
|
4807
4994
|
if (decision === "allowed") {
|
|
4808
4995
|
return [
|
|
4809
4996
|
...header,
|
|
4810
4997
|
"The user has pre-authorized LSP installation. Run the install command, then retry this tool:",
|
|
4811
|
-
|
|
4998
|
+
...installOptions.slice(1)
|
|
4812
4999
|
].join(`
|
|
4813
5000
|
`);
|
|
4814
5001
|
}
|
|
4815
5002
|
if (!context.capabilities.installDecisionTool) {
|
|
4816
5003
|
return [
|
|
4817
5004
|
...header,
|
|
4818
|
-
|
|
4819
|
-
` ${installHint}`,
|
|
5005
|
+
...installOptions,
|
|
4820
5006
|
"",
|
|
4821
5007
|
"ACTION REQUIRED — ASK THE USER whether to install this LSP server.",
|
|
4822
5008
|
"Install-decision recording is unavailable in this harness; proceed without LSP if the user declines."
|
|
@@ -4825,8 +5011,7 @@ function formatNotInstalled(result) {
|
|
|
4825
5011
|
}
|
|
4826
5012
|
return [
|
|
4827
5013
|
...header,
|
|
4828
|
-
|
|
4829
|
-
` ${installHint}`,
|
|
5014
|
+
...installOptions,
|
|
4830
5015
|
"",
|
|
4831
5016
|
"ACTION REQUIRED — ASK THE USER whether to install this LSP server.",
|
|
4832
5017
|
"- If the user agrees: run the install command above, then retry this tool.",
|
|
@@ -4882,7 +5067,7 @@ async function withLspClient(filePath, fn, toolName, options = {}) {
|
|
|
4882
5067
|
|
|
4883
5068
|
// ../lsp-core/src/lsp/directory-diagnostics.ts
|
|
4884
5069
|
import { existsSync as existsSync12, lstatSync as lstatSync5, readdirSync as readdirSync3 } from "node:fs";
|
|
4885
|
-
import { join as join6, resolve as
|
|
5070
|
+
import { join as join6, resolve as resolve9 } from "node:path";
|
|
4886
5071
|
|
|
4887
5072
|
// ../lsp-core/src/lsp/formatters.ts
|
|
4888
5073
|
import { fileURLToPath as fileURLToPath3 } from "node:url";
|
|
@@ -5037,7 +5222,7 @@ async function aggregateDiagnosticsForDirectory(directory, extension, severity,
|
|
|
5037
5222
|
if (!extension.startsWith(".")) {
|
|
5038
5223
|
throw new LspInvalidPathError(`Extension must start with a dot (e.g., ".ts", not "${extension}"). Use ".${extension}" instead.`);
|
|
5039
5224
|
}
|
|
5040
|
-
const absDir =
|
|
5225
|
+
const absDir = resolve9(options.workspaceRoot ?? contextCwd(), directory);
|
|
5041
5226
|
if (!existsSync12(absDir)) {
|
|
5042
5227
|
throw new LspInvalidPathError(`Directory does not exist: ${absDir}`);
|
|
5043
5228
|
}
|
|
@@ -5394,6 +5579,96 @@ async function executeLspDiagnostics(params, signal) {
|
|
|
5394
5579
|
throw error;
|
|
5395
5580
|
}
|
|
5396
5581
|
}
|
|
5582
|
+
// ../lsp-core/src/lsp/format-document.ts
|
|
5583
|
+
import { readFileSync as readFileSync6, renameSync as renameSync3, unlinkSync as unlinkSync2, writeFileSync as writeFileSync3 } from "node:fs";
|
|
5584
|
+
var DEFAULT_FORMATTING_OPTIONS = {
|
|
5585
|
+
tabSize: 4,
|
|
5586
|
+
insertSpaces: false,
|
|
5587
|
+
trimTrailingWhitespace: true,
|
|
5588
|
+
insertFinalNewline: true,
|
|
5589
|
+
trimFinalNewlines: true
|
|
5590
|
+
};
|
|
5591
|
+
var UNCHANGED = { status: "unchanged", linesAdded: 0, linesRemoved: 0 };
|
|
5592
|
+
async function formatDocumentWithClient(client, filePath, options = {}) {
|
|
5593
|
+
const edits = await client.formatDocument(filePath, options.formattingOptions ?? DEFAULT_FORMATTING_OPTIONS, options.signal);
|
|
5594
|
+
if (edits === null)
|
|
5595
|
+
return { status: "unavailable", reason: "capability_not_advertised" };
|
|
5596
|
+
if (edits.length === 0)
|
|
5597
|
+
return UNCHANGED;
|
|
5598
|
+
const before = readFileSync6(filePath, "utf-8");
|
|
5599
|
+
const normalized = normalizeTextEdits(before, edits, 0);
|
|
5600
|
+
if (normalized.text === before)
|
|
5601
|
+
return UNCHANGED;
|
|
5602
|
+
writeAtomically(filePath, normalized.text);
|
|
5603
|
+
await client.openFile(filePath);
|
|
5604
|
+
return {
|
|
5605
|
+
status: "formatted",
|
|
5606
|
+
...lineDelta(normalized.edits)
|
|
5607
|
+
};
|
|
5608
|
+
}
|
|
5609
|
+
function lineDelta(edits) {
|
|
5610
|
+
let linesAdded = 0;
|
|
5611
|
+
let linesRemoved = 0;
|
|
5612
|
+
for (const edit of edits) {
|
|
5613
|
+
linesRemoved += edit.range.end.line - edit.range.start.line + 1;
|
|
5614
|
+
linesAdded += edit.newText.split(`
|
|
5615
|
+
`).length;
|
|
5616
|
+
}
|
|
5617
|
+
return { linesAdded, linesRemoved };
|
|
5618
|
+
}
|
|
5619
|
+
function writeAtomically(filePath, content) {
|
|
5620
|
+
const tempPath = `${filePath}.omo-format.tmp`;
|
|
5621
|
+
writeFileSync3(tempPath, content, "utf-8");
|
|
5622
|
+
try {
|
|
5623
|
+
renameSync3(tempPath, filePath);
|
|
5624
|
+
} catch (error) {
|
|
5625
|
+
try {
|
|
5626
|
+
unlinkSync2(tempPath);
|
|
5627
|
+
} catch {}
|
|
5628
|
+
throw error;
|
|
5629
|
+
}
|
|
5630
|
+
}
|
|
5631
|
+
|
|
5632
|
+
// ../lsp-core/src/tools/format.ts
|
|
5633
|
+
async function executeLspFormat(params, signal) {
|
|
5634
|
+
const filePath = requireString(params, "filePath");
|
|
5635
|
+
try {
|
|
5636
|
+
const result = await withLspClient(filePath, async (client, _workspaceRoot, resolvedFilePath) => formatDocumentWithClient(client, resolvedFilePath, signal === undefined ? {} : { signal }), "format", clientOptions(signal));
|
|
5637
|
+
return text(describeResult(filePath, result), formatDetails(filePath, result));
|
|
5638
|
+
} catch (error) {
|
|
5639
|
+
const missingDependency = missingDependencyResult(error, {
|
|
5640
|
+
filePath,
|
|
5641
|
+
status: "unavailable",
|
|
5642
|
+
reason: "server_unavailable",
|
|
5643
|
+
linesAdded: 0,
|
|
5644
|
+
linesRemoved: 0
|
|
5645
|
+
});
|
|
5646
|
+
if (missingDependency)
|
|
5647
|
+
return missingDependency;
|
|
5648
|
+
throw error;
|
|
5649
|
+
}
|
|
5650
|
+
}
|
|
5651
|
+
function formatDetails(filePath, result) {
|
|
5652
|
+
if (result.status === "unavailable") {
|
|
5653
|
+
return { filePath, status: "unavailable", reason: result.reason, linesAdded: 0, linesRemoved: 0 };
|
|
5654
|
+
}
|
|
5655
|
+
return {
|
|
5656
|
+
filePath,
|
|
5657
|
+
status: result.status,
|
|
5658
|
+
linesAdded: result.linesAdded,
|
|
5659
|
+
linesRemoved: result.linesRemoved
|
|
5660
|
+
};
|
|
5661
|
+
}
|
|
5662
|
+
function describeResult(filePath, result) {
|
|
5663
|
+
if (result.status === "unavailable") {
|
|
5664
|
+
return `Formatting unavailable for ${filePath}: the language server does not advertise documentFormattingProvider.`;
|
|
5665
|
+
}
|
|
5666
|
+
if (result.status === "unchanged") {
|
|
5667
|
+
return `Already formatted: ${filePath}`;
|
|
5668
|
+
}
|
|
5669
|
+
return `Formatted ${filePath} (+${result.linesAdded}/-${result.linesRemoved} lines)`;
|
|
5670
|
+
}
|
|
5671
|
+
|
|
5397
5672
|
// ../lsp-core/src/tools/install-decision.ts
|
|
5398
5673
|
async function executeLspInstallDecision(params) {
|
|
5399
5674
|
const serverId = requireString(params, "server_id");
|
|
@@ -5726,6 +6001,16 @@ var LSP_MCP_TOOLS = [
|
|
|
5726
6001
|
}, ["filePath", "line", "character", "newName"]),
|
|
5727
6002
|
execute: executeLspRename
|
|
5728
6003
|
},
|
|
6004
|
+
{
|
|
6005
|
+
name: "format",
|
|
6006
|
+
aliases: ["lsp_format"],
|
|
6007
|
+
title: "LSP Format",
|
|
6008
|
+
description: "Format a source file with its language server and write the returned edits to disk.",
|
|
6009
|
+
inputSchema: objectSchema({
|
|
6010
|
+
filePath: { type: "string", description: "Source file path to format." }
|
|
6011
|
+
}, ["filePath"]),
|
|
6012
|
+
execute: executeLspFormat
|
|
6013
|
+
},
|
|
5729
6014
|
{
|
|
5730
6015
|
name: "install_decision",
|
|
5731
6016
|
aliases: ["lsp_install_decision"],
|
|
@@ -5945,6 +6230,9 @@ async function callToolViaDaemon(name, args, options) {
|
|
|
5945
6230
|
function callDiagnosticsViaDaemon(filePath, options) {
|
|
5946
6231
|
return callToolViaDaemon("diagnostics", { filePath, severity: "error" }, options);
|
|
5947
6232
|
}
|
|
6233
|
+
function callFormatViaDaemon(filePath, options) {
|
|
6234
|
+
return callToolViaDaemon("format", { filePath }, options);
|
|
6235
|
+
}
|
|
5948
6236
|
function currentRequestContext(env = process.env) {
|
|
5949
6237
|
const cwd = process.cwd();
|
|
5950
6238
|
const home = env["HOME"] ?? homedir3();
|
|
@@ -5967,7 +6255,7 @@ function withContext(args, context) {
|
|
|
5967
6255
|
function ensureDaemonAvailable(paths, ensure, signal) {
|
|
5968
6256
|
if (!signal)
|
|
5969
6257
|
return ensure(paths);
|
|
5970
|
-
return new Promise((
|
|
6258
|
+
return new Promise((resolve10, reject) => {
|
|
5971
6259
|
let settled = false;
|
|
5972
6260
|
const finish = (run) => {
|
|
5973
6261
|
if (settled)
|
|
@@ -5982,11 +6270,11 @@ function ensureDaemonAvailable(paths, ensure, signal) {
|
|
|
5982
6270
|
return;
|
|
5983
6271
|
}
|
|
5984
6272
|
signal.addEventListener("abort", onAbort, { once: true });
|
|
5985
|
-
Promise.resolve().then(() => ensure(paths, signal)).then(() => finish(() =>
|
|
6273
|
+
Promise.resolve().then(() => ensure(paths, signal)).then(() => finish(() => resolve10()), (error) => finish(() => reject(signal.aborted ? new DaemonRequestCancelledError(false) : error)));
|
|
5986
6274
|
});
|
|
5987
6275
|
}
|
|
5988
6276
|
function sendToolCall(paths, token, name, args, options) {
|
|
5989
|
-
return new Promise((
|
|
6277
|
+
return new Promise((resolve10, reject) => {
|
|
5990
6278
|
const socket = connect(paths.socket);
|
|
5991
6279
|
const requestId = allocateProxyRequestId();
|
|
5992
6280
|
let settled = false;
|
|
@@ -6039,7 +6327,7 @@ function sendToolCall(paths, token, name, args, options) {
|
|
|
6039
6327
|
}
|
|
6040
6328
|
const result = toToolResult(message, requestId);
|
|
6041
6329
|
if (result)
|
|
6042
|
-
finish(() =>
|
|
6330
|
+
finish(() => resolve10(result));
|
|
6043
6331
|
else
|
|
6044
6332
|
finish(() => reject(new DaemonRequestError("invalid daemon response", requestWritten)));
|
|
6045
6333
|
});
|
|
@@ -6085,7 +6373,7 @@ function isRetryableTool(name) {
|
|
|
6085
6373
|
}
|
|
6086
6374
|
// src/proxy.ts
|
|
6087
6375
|
import { existsSync as existsSync13, realpathSync as realpathSync6 } from "node:fs";
|
|
6088
|
-
import { basename as basename4, delimiter as delimiter4, dirname as
|
|
6376
|
+
import { basename as basename4, delimiter as delimiter4, dirname as dirname11, isAbsolute as isAbsolute6 } from "node:path";
|
|
6089
6377
|
var DEFAULT_STARTUP_TIMEOUT_MS = 1e4;
|
|
6090
6378
|
async function runMcpStdioProxy(options = {}) {
|
|
6091
6379
|
const input = options.input ?? process.stdin;
|
|
@@ -6208,18 +6496,18 @@ function canonicalizePathList(value) {
|
|
|
6208
6496
|
return value.split(delimiter4).map((entry) => canonicalizePath(entry) ?? entry).join(delimiter4);
|
|
6209
6497
|
}
|
|
6210
6498
|
function canonicalizePath(value) {
|
|
6211
|
-
if (value === undefined || !
|
|
6499
|
+
if (value === undefined || !isAbsolute6(value) || !existsSync13(value))
|
|
6212
6500
|
return value;
|
|
6213
6501
|
return realpathSync6(value);
|
|
6214
6502
|
}
|
|
6215
6503
|
function projectRootFromOpenCodeConfigPath(path2) {
|
|
6216
6504
|
if (basename4(path2) !== "lsp.json" && basename4(path2) !== "lsp-client.json")
|
|
6217
6505
|
return;
|
|
6218
|
-
const configDir =
|
|
6506
|
+
const configDir = dirname11(path2);
|
|
6219
6507
|
const configDirName = basename4(configDir);
|
|
6220
6508
|
if (configDirName !== ".opencode" && configDirName !== ".omo")
|
|
6221
6509
|
return;
|
|
6222
|
-
return
|
|
6510
|
+
return dirname11(configDir);
|
|
6223
6511
|
}
|
|
6224
6512
|
export {
|
|
6225
6513
|
InvalidDaemonDirectoryError,
|