lazycodex-ai 5.0.0-beta.49 → 5.0.0-beta.50
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 +4682 -14969
- package/dist/cli-node/index.js +4727 -15014
- package/package.json +1 -1
- package/packages/lsp-daemon/dist/cli.js +181 -181
- package/packages/lsp-daemon/dist/client.js +232 -232
- package/packages/lsp-daemon/dist/index.js +132 -132
- package/packages/lsp-tools-mcp/dist/cli.js +103 -101
- package/packages/lsp-tools-mcp/dist/lsp/manager.js +14 -14
- package/packages/lsp-tools-mcp/dist/mcp.js +129 -129
- package/packages/lsp-tools-mcp/dist/tools.js +47 -47
- package/packages/omo-codex/plugin/.codex-plugin/plugin.json +1 -1
- package/packages/omo-codex/plugin/README.md +4 -0
- package/packages/omo-codex/plugin/components/bootstrap/dist/cli.js +151 -102
- 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/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/AGENTS.md +2 -2
- package/packages/omo-codex/plugin/components/lazycodex-executor-verify/directive.md +2 -0
- package/packages/omo-codex/plugin/components/lazycodex-executor-verify/dist/cli.js +35 -24
- package/packages/omo-codex/plugin/components/lazycodex-executor-verify/dist/codex-hook.js +31 -21
- package/packages/omo-codex/plugin/components/lazycodex-executor-verify/dist/types.d.ts +3 -0
- 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/lazycodex-executor-verify/src/codex-hook.ts +31 -23
- package/packages/omo-codex/plugin/components/lazycodex-executor-verify/src/types.ts +3 -0
- package/packages/omo-codex/plugin/components/lazycodex-executor-verify/test/cli.test.ts +1 -1
- package/packages/omo-codex/plugin/components/lazycodex-executor-verify/test/codex-hook.test.ts +133 -7
- package/packages/omo-codex/plugin/components/lcx/skills/lcx-doctor/SKILL.md +3 -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 +298 -298
- 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/README.md +2 -0
- package/packages/omo-codex/plugin/components/rules/bundled-rules/hephaestus/gpt-6.md +123 -0
- package/packages/omo-codex/plugin/components/rules/dist/cli.js +38 -30
- 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 +6 -0
- package/packages/omo-codex/plugin/components/rules/test/hephaestus-model-variant.test.ts +38 -2
- package/packages/omo-codex/plugin/components/rules/test/post-compact-budget.test.ts +24 -0
- package/packages/omo-codex/plugin/components/teammode/hooks/hooks.json +1 -1
- package/packages/omo-codex/plugin/components/teammode/package.json +2 -2
- package/packages/omo-codex/plugin/components/telemetry/dist/cli.js +66 -357
- package/packages/omo-codex/plugin/components/telemetry/dist/posthog.js +66 -358
- 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/README.md +2 -0
- package/packages/omo-codex/plugin/components/ultrawork/agents/explorer.toml +1 -1
- package/packages/omo-codex/plugin/components/ultrawork/agents/lazycodex-clone-fidelity-reviewer.toml +1 -1
- package/packages/omo-codex/plugin/components/ultrawork/agents/lazycodex-code-reviewer.toml +1 -1
- package/packages/omo-codex/plugin/components/ultrawork/agents/lazycodex-gate-reviewer.toml +1 -1
- package/packages/omo-codex/plugin/components/ultrawork/agents/lazycodex-qa-executor.toml +1 -1
- package/packages/omo-codex/plugin/components/ultrawork/agents/lazycodex-worker-high.toml +1 -1
- package/packages/omo-codex/plugin/components/ultrawork/agents/lazycodex-worker-low.toml +1 -1
- package/packages/omo-codex/plugin/components/ultrawork/agents/lazycodex-worker-medium.toml +1 -1
- package/packages/omo-codex/plugin/components/ultrawork/agents/librarian.toml +1 -1
- package/packages/omo-codex/plugin/components/ultrawork/agents/metis.toml +1 -1
- package/packages/omo-codex/plugin/components/ultrawork/agents/momus.toml +1 -1
- package/packages/omo-codex/plugin/components/ultrawork/agents/plan.toml +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/dist/cli.js +3 -3
- package/packages/omo-codex/plugin/components/ulw-execute-continuation/hooks/hooks.json +1 -1
- package/packages/omo-codex/plugin/components/ulw-execute-continuation/package.json +1 -1
- package/packages/omo-codex/plugin/components/ulw-loop/dist/cli.js +63 -63
- package/packages/omo-codex/plugin/components/ulw-loop/hooks/hooks.json +5 -5
- package/packages/omo-codex/plugin/components/ulw-loop/package.json +1 -1
- 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-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/post-tool-use-recording-spawn-admission.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-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-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 +16 -7
- package/packages/omo-codex/plugin/package-lock.json +16 -16
- package/packages/omo-codex/plugin/package.json +1 -1
- package/packages/omo-codex/plugin/scripts/migrate-codex-config/catalog.mjs +16 -7
- package/packages/omo-codex/plugin/scripts/migrate-codex-config/multi-agent-v2-guard.mjs +8 -4
- package/packages/omo-codex/plugin/scripts/migrate-codex-config/subagent-limit-guard.mjs +18 -90
- package/packages/omo-codex/plugin/scripts/migrate-codex-config/toml-section-editor.mjs +1 -1
- package/packages/omo-codex/plugin/shared/package.json +1 -1
- package/packages/omo-codex/plugin/skills/lcx-doctor/SKILL.md +3 -1
- package/packages/omo-codex/plugin/test/aggregate-agents.test.mjs +12 -12
- package/packages/omo-codex/plugin/test/aggregate-model-catalog.test.mjs +14 -4
- package/packages/omo-codex/plugin/test/auto-update.test.mjs +4 -4
- package/packages/omo-codex/plugin/test/component-hook-contract-cases.mjs +25 -1
- package/packages/omo-codex/plugin/test/migrate-codex-config.test.mjs +35 -35
- package/packages/omo-codex/plugin/test/multi-agent-v2-regression.test.mjs +1 -1
- package/packages/omo-codex/plugin/test/subagent-limit-migration.test.mjs +107 -15
- package/packages/omo-codex/scripts/install-dist/install-local.mjs +318 -569
|
@@ -684,7 +684,7 @@ async function probeDaemon(paths, timeoutMs = PROBE_TIMEOUT_MS, signal) {
|
|
|
684
684
|
return await pingDaemon(paths, token, timeoutMs, signal) !== null;
|
|
685
685
|
}
|
|
686
686
|
function pingDaemon(paths, token, timeoutMs = PROBE_TIMEOUT_MS, signal) {
|
|
687
|
-
return new Promise((
|
|
687
|
+
return new Promise((resolve) => {
|
|
688
688
|
const socket = new Socket;
|
|
689
689
|
let settled = false;
|
|
690
690
|
let timer;
|
|
@@ -696,7 +696,7 @@ function pingDaemon(paths, token, timeoutMs = PROBE_TIMEOUT_MS, signal) {
|
|
|
696
696
|
clearTimeout(timer);
|
|
697
697
|
signal?.removeEventListener("abort", onAbort);
|
|
698
698
|
socket.destroy();
|
|
699
|
-
|
|
699
|
+
resolve(value);
|
|
700
700
|
};
|
|
701
701
|
const onAbort = () => finish(null);
|
|
702
702
|
const decoder = createLineDecoder((message) => {
|
|
@@ -759,7 +759,7 @@ function defaultEnsureDaemonDeps() {
|
|
|
759
759
|
};
|
|
760
760
|
}
|
|
761
761
|
function sleepWithSignal(ms, signal) {
|
|
762
|
-
return new Promise((
|
|
762
|
+
return new Promise((resolve) => {
|
|
763
763
|
let settled = false;
|
|
764
764
|
const finish = () => {
|
|
765
765
|
if (settled)
|
|
@@ -767,7 +767,7 @@ function sleepWithSignal(ms, signal) {
|
|
|
767
767
|
settled = true;
|
|
768
768
|
clearTimeout(timer);
|
|
769
769
|
signal?.removeEventListener("abort", finish);
|
|
770
|
-
|
|
770
|
+
resolve();
|
|
771
771
|
};
|
|
772
772
|
const timer = setTimeout(finish, ms);
|
|
773
773
|
if (signal?.aborted) {
|
|
@@ -782,7 +782,7 @@ function awaitWithSignal(promise, signal) {
|
|
|
782
782
|
return promise;
|
|
783
783
|
if (signal.aborted)
|
|
784
784
|
return Promise.reject(abortError(signal));
|
|
785
|
-
return new Promise((
|
|
785
|
+
return new Promise((resolve, reject) => {
|
|
786
786
|
let settled = false;
|
|
787
787
|
const finish = (run) => {
|
|
788
788
|
if (settled)
|
|
@@ -793,7 +793,7 @@ function awaitWithSignal(promise, signal) {
|
|
|
793
793
|
};
|
|
794
794
|
const onAbort = () => finish(() => reject(abortError(signal)));
|
|
795
795
|
signal.addEventListener("abort", onAbort, { once: true });
|
|
796
|
-
promise.then((value) => finish(() =>
|
|
796
|
+
promise.then((value) => finish(() => resolve(value)), (error) => finish(() => reject(error)));
|
|
797
797
|
});
|
|
798
798
|
}
|
|
799
799
|
function throwIfAborted(signal) {
|
|
@@ -822,18 +822,18 @@ function parsePingResponse(message) {
|
|
|
822
822
|
return null;
|
|
823
823
|
if (!endpoint || typeof endpoint !== "object" || Array.isArray(endpoint))
|
|
824
824
|
return null;
|
|
825
|
-
const
|
|
825
|
+
const path = Reflect.get(endpoint, "path");
|
|
826
826
|
const kind = Reflect.get(endpoint, "kind");
|
|
827
|
-
if (typeof
|
|
827
|
+
if (typeof path !== "string")
|
|
828
828
|
return null;
|
|
829
829
|
if (kind === "windows")
|
|
830
|
-
return { pid, nonce, startedAt, endpoint: { kind, path
|
|
830
|
+
return { pid, nonce, startedAt, endpoint: { kind, path } };
|
|
831
831
|
if (kind === "missing")
|
|
832
|
-
return { pid, nonce, startedAt, endpoint: { kind, path
|
|
832
|
+
return { pid, nonce, startedAt, endpoint: { kind, path } };
|
|
833
833
|
const dev = Reflect.get(endpoint, "dev");
|
|
834
834
|
const ino = Reflect.get(endpoint, "ino");
|
|
835
835
|
if (kind === "unix" && typeof dev === "number" && typeof ino === "number") {
|
|
836
|
-
return { pid, nonce, startedAt, endpoint: { kind, path
|
|
836
|
+
return { pid, nonce, startedAt, endpoint: { kind, path, dev, ino } };
|
|
837
837
|
}
|
|
838
838
|
return null;
|
|
839
839
|
}
|
|
@@ -881,7 +881,7 @@ ${body}` : `${body}
|
|
|
881
881
|
await writeChunk(output, payload);
|
|
882
882
|
}
|
|
883
883
|
function writeChunk(output, chunk) {
|
|
884
|
-
return new Promise((
|
|
884
|
+
return new Promise((resolve, reject) => {
|
|
885
885
|
let settled = false;
|
|
886
886
|
const onError = (error) => {
|
|
887
887
|
if (settled)
|
|
@@ -901,7 +901,7 @@ function writeChunk(output, chunk) {
|
|
|
901
901
|
return;
|
|
902
902
|
}
|
|
903
903
|
output.removeListener("error", onError);
|
|
904
|
-
|
|
904
|
+
resolve();
|
|
905
905
|
});
|
|
906
906
|
} catch (error) {
|
|
907
907
|
output.removeListener("error", onError);
|
|
@@ -1345,7 +1345,7 @@ class JsonRpcConnection {
|
|
|
1345
1345
|
let settled = false;
|
|
1346
1346
|
const writeCancel = () => this.writeMessage({ jsonrpc: "2.0", method: "$/cancelRequest", params: { id } });
|
|
1347
1347
|
let rejectAfterCancelWrite;
|
|
1348
|
-
const responsePromise = new Promise((
|
|
1348
|
+
const responsePromise = new Promise((resolve, reject) => {
|
|
1349
1349
|
const cleanup = () => {
|
|
1350
1350
|
options.signal?.removeEventListener("abort", onAbort);
|
|
1351
1351
|
};
|
|
@@ -1375,7 +1375,7 @@ class JsonRpcConnection {
|
|
|
1375
1375
|
resolve(result) {
|
|
1376
1376
|
settled = true;
|
|
1377
1377
|
cleanup();
|
|
1378
|
-
|
|
1378
|
+
resolve(result);
|
|
1379
1379
|
},
|
|
1380
1380
|
reject(error) {
|
|
1381
1381
|
settled = true;
|
|
@@ -1534,13 +1534,13 @@ class JsonRpcConnection {
|
|
|
1534
1534
|
const payload = `Content-Length: ${Buffer.byteLength(body, "utf8")}\r
|
|
1535
1535
|
\r
|
|
1536
1536
|
${body}`;
|
|
1537
|
-
return new Promise((
|
|
1537
|
+
return new Promise((resolve, reject) => {
|
|
1538
1538
|
this.writer.write(payload, (error) => {
|
|
1539
1539
|
if (error) {
|
|
1540
1540
|
reject(error);
|
|
1541
1541
|
return;
|
|
1542
1542
|
}
|
|
1543
|
-
|
|
1543
|
+
resolve();
|
|
1544
1544
|
});
|
|
1545
1545
|
});
|
|
1546
1546
|
}
|
|
@@ -1627,9 +1627,9 @@ function validateCwd(cwd) {
|
|
|
1627
1627
|
}
|
|
1628
1628
|
}
|
|
1629
1629
|
function wrap(proc) {
|
|
1630
|
-
const exitedPromise = new Promise((
|
|
1631
|
-
proc.once("close", (code) =>
|
|
1632
|
-
proc.once("error", () =>
|
|
1630
|
+
const exitedPromise = new Promise((resolve) => {
|
|
1631
|
+
proc.once("close", (code) => resolve(code ?? 0));
|
|
1632
|
+
proc.once("error", () => resolve(1));
|
|
1633
1633
|
});
|
|
1634
1634
|
if (!proc.stdin || !proc.stdout || !proc.stderr) {
|
|
1635
1635
|
throw new LspProcessSpawnError("Spawned process is missing one of stdin/stdout/stderr pipes");
|
|
@@ -1791,9 +1791,9 @@ class LspClientNotStartedError extends Error {
|
|
|
1791
1791
|
}
|
|
1792
1792
|
|
|
1793
1793
|
class LspClientTransport {
|
|
1794
|
-
constructor(root,
|
|
1794
|
+
constructor(root, server, timeouts = {}) {
|
|
1795
1795
|
this.root = root;
|
|
1796
|
-
this.server =
|
|
1796
|
+
this.server = server;
|
|
1797
1797
|
this.proc = null;
|
|
1798
1798
|
this.connection = null;
|
|
1799
1799
|
this.stderrBuffer = [];
|
|
@@ -1975,8 +1975,8 @@ class LspClientTransport {
|
|
|
1975
1975
|
try {
|
|
1976
1976
|
proc.kill();
|
|
1977
1977
|
let timeoutId;
|
|
1978
|
-
const timeoutPromise = new Promise((
|
|
1979
|
-
timeoutId = setTimeout(
|
|
1978
|
+
const timeoutPromise = new Promise((resolve) => {
|
|
1979
|
+
timeoutId = setTimeout(resolve, STOP_HARD_KILL_TIMEOUT_MS);
|
|
1980
1980
|
});
|
|
1981
1981
|
await Promise.race([
|
|
1982
1982
|
proc.exited.then(() => {
|
|
@@ -1992,7 +1992,7 @@ class LspClientTransport {
|
|
|
1992
1992
|
proc.kill("SIGKILL");
|
|
1993
1993
|
await Promise.race([
|
|
1994
1994
|
proc.exited,
|
|
1995
|
-
new Promise((
|
|
1995
|
+
new Promise((resolve) => setTimeout(resolve, STOP_SIGKILL_GRACE_MS))
|
|
1996
1996
|
]);
|
|
1997
1997
|
} catch (error) {
|
|
1998
1998
|
reportBestEffortCleanupError("hard process kill", error instanceof Error ? error : String(error));
|
|
@@ -2341,16 +2341,16 @@ class WorkspaceDocumentState {
|
|
|
2341
2341
|
this.versionlessPublishQuiescenceMs = options.versionlessPublishQuiescenceMs ?? DEFAULT_VERSIONLESS_PUBLISH_QUIESCENCE_MS;
|
|
2342
2342
|
}
|
|
2343
2343
|
async openFile(filePath) {
|
|
2344
|
-
const
|
|
2345
|
-
const existingOpen = this.openPromises.get(
|
|
2344
|
+
const path = canonicalPath(filePath);
|
|
2345
|
+
const existingOpen = this.openPromises.get(path);
|
|
2346
2346
|
if (existingOpen) {
|
|
2347
2347
|
await existingOpen;
|
|
2348
|
-
return this.openFile(
|
|
2348
|
+
return this.openFile(path);
|
|
2349
2349
|
}
|
|
2350
|
-
const text = readFileSync2(
|
|
2351
|
-
const existing = this.openDocuments.get(
|
|
2350
|
+
const text = readFileSync2(path, "utf-8");
|
|
2351
|
+
const existing = this.openDocuments.get(path);
|
|
2352
2352
|
if (!existing)
|
|
2353
|
-
return this.openDocumentSingleFlight(
|
|
2353
|
+
return this.openDocumentSingleFlight(path, text);
|
|
2354
2354
|
if (existing.text === text)
|
|
2355
2355
|
return;
|
|
2356
2356
|
await this.changeDocument(existing, text);
|
|
@@ -2445,7 +2445,7 @@ class WorkspaceDocumentState {
|
|
|
2445
2445
|
});
|
|
2446
2446
|
}
|
|
2447
2447
|
validateVersions(operations) {
|
|
2448
|
-
const versions = new Map([...this.openDocuments].map(([
|
|
2448
|
+
const versions = new Map([...this.openDocuments].map(([path, state]) => [path, state.version]));
|
|
2449
2449
|
for (const operation of operations) {
|
|
2450
2450
|
if (operation.kind === "text") {
|
|
2451
2451
|
const current = versions.get(operation.path);
|
|
@@ -2461,17 +2461,17 @@ class WorkspaceDocumentState {
|
|
|
2461
2461
|
continue;
|
|
2462
2462
|
}
|
|
2463
2463
|
if (operation.kind === "rename") {
|
|
2464
|
-
const moved = [...versions].filter(([
|
|
2465
|
-
for (const [
|
|
2466
|
-
versions.delete(
|
|
2467
|
-
for (const [
|
|
2468
|
-
versions.set(movedPath(
|
|
2464
|
+
const moved = [...versions].filter(([path]) => isSameOrDescendant(path, operation.oldPath));
|
|
2465
|
+
for (const [path] of moved)
|
|
2466
|
+
versions.delete(path);
|
|
2467
|
+
for (const [path] of moved)
|
|
2468
|
+
versions.set(movedPath(path, operation.oldPath, operation.newPath), 1);
|
|
2469
2469
|
continue;
|
|
2470
2470
|
}
|
|
2471
2471
|
if (operation.kind === "delete") {
|
|
2472
|
-
for (const
|
|
2473
|
-
if (isSameOrDescendant(
|
|
2474
|
-
versions.delete(
|
|
2472
|
+
for (const path of [...versions.keys()]) {
|
|
2473
|
+
if (isSameOrDescendant(path, operation.path))
|
|
2474
|
+
versions.delete(path);
|
|
2475
2475
|
}
|
|
2476
2476
|
continue;
|
|
2477
2477
|
}
|
|
@@ -2515,8 +2515,8 @@ class WorkspaceDocumentState {
|
|
|
2515
2515
|
for (const state of moved)
|
|
2516
2516
|
await this.closeDocument(state);
|
|
2517
2517
|
for (const state of moved) {
|
|
2518
|
-
const
|
|
2519
|
-
await this.openDocumentSingleFlight(
|
|
2518
|
+
const path = movedPath(state.path, mutation.oldPath, mutation.newPath);
|
|
2519
|
+
await this.openDocumentSingleFlight(path, readFileSync2(path, "utf-8"));
|
|
2520
2520
|
}
|
|
2521
2521
|
if (moved.length === 0) {
|
|
2522
2522
|
watched.push({ uri: pathToFileURL2(mutation.oldPath).href, type: 3 });
|
|
@@ -2530,31 +2530,31 @@ class WorkspaceDocumentState {
|
|
|
2530
2530
|
if (removed.length === 0)
|
|
2531
2531
|
watched.push({ uri: pathToFileURL2(mutation.path).href, type: 3 });
|
|
2532
2532
|
}
|
|
2533
|
-
async openDocumentSingleFlight(
|
|
2534
|
-
const existing = this.openPromises.get(
|
|
2533
|
+
async openDocumentSingleFlight(path, text) {
|
|
2534
|
+
const existing = this.openPromises.get(path);
|
|
2535
2535
|
if (existing)
|
|
2536
2536
|
return existing;
|
|
2537
2537
|
const open = (async () => {
|
|
2538
2538
|
const state = {
|
|
2539
|
-
path
|
|
2540
|
-
uri: pathToFileURL2(
|
|
2541
|
-
languageId: getLanguageId(effectiveExtension(
|
|
2539
|
+
path,
|
|
2540
|
+
uri: pathToFileURL2(path).href,
|
|
2541
|
+
languageId: getLanguageId(effectiveExtension(path)),
|
|
2542
2542
|
text,
|
|
2543
2543
|
version: 1,
|
|
2544
2544
|
generation: 1,
|
|
2545
2545
|
publishGeneration: 0,
|
|
2546
2546
|
waiters: new Set
|
|
2547
2547
|
};
|
|
2548
|
-
this.openDocuments.set(
|
|
2548
|
+
this.openDocuments.set(path, state);
|
|
2549
2549
|
this.openByUri.set(normalizeDocumentUri(state.uri), state);
|
|
2550
2550
|
this.notifyWaiters(state);
|
|
2551
2551
|
await this.sendNotification("textDocument/didOpen", {
|
|
2552
2552
|
textDocument: { uri: state.uri, languageId: state.languageId, version: state.version, text }
|
|
2553
2553
|
});
|
|
2554
2554
|
})().finally(() => {
|
|
2555
|
-
this.openPromises.delete(
|
|
2555
|
+
this.openPromises.delete(path);
|
|
2556
2556
|
});
|
|
2557
|
-
this.openPromises.set(
|
|
2557
|
+
this.openPromises.set(path, open);
|
|
2558
2558
|
return open;
|
|
2559
2559
|
}
|
|
2560
2560
|
async changeDocument(state, text) {
|
|
@@ -2600,9 +2600,9 @@ import { dirname as dirname4, isAbsolute as isAbsolute4, relative as relative3,
|
|
|
2600
2600
|
import { fileURLToPath as fileURLToPath2 } from "node:url";
|
|
2601
2601
|
|
|
2602
2602
|
class WorkspaceEditPathError extends Error {
|
|
2603
|
-
constructor(
|
|
2604
|
-
super(`${detail}: ${
|
|
2605
|
-
this.path =
|
|
2603
|
+
constructor(path, detail) {
|
|
2604
|
+
super(`${detail}: ${path}`);
|
|
2605
|
+
this.path = path;
|
|
2606
2606
|
this.detail = detail;
|
|
2607
2607
|
this.name = "WorkspaceEditPathError";
|
|
2608
2608
|
}
|
|
@@ -2666,28 +2666,28 @@ function uriToCanonicalWorkspacePath(uri, workspaceRoot) {
|
|
|
2666
2666
|
return { success: false, error: `${requestedPath}: ${detail}` };
|
|
2667
2667
|
}
|
|
2668
2668
|
}
|
|
2669
|
-
function snapshotPath(
|
|
2670
|
-
if (!existsSync4(
|
|
2669
|
+
function snapshotPath(path, includeChildren) {
|
|
2670
|
+
if (!existsSync4(path))
|
|
2671
2671
|
return { kind: "missing" };
|
|
2672
|
-
const stats = lstatSync2(
|
|
2672
|
+
const stats = lstatSync2(path);
|
|
2673
2673
|
if (stats.isFile())
|
|
2674
|
-
return { kind: "file", content: readFileSync3(
|
|
2674
|
+
return { kind: "file", content: readFileSync3(path, "utf-8") };
|
|
2675
2675
|
if (stats.isDirectory()) {
|
|
2676
|
-
return includeChildren ? { kind: "directory", children: readdirSync(
|
|
2676
|
+
return includeChildren ? { kind: "directory", children: readdirSync(path).sort() } : { kind: "directory" };
|
|
2677
2677
|
}
|
|
2678
|
-
throw new WorkspaceEditPathError(
|
|
2678
|
+
throw new WorkspaceEditPathError(path, "unsupported filesystem entry");
|
|
2679
2679
|
}
|
|
2680
2680
|
|
|
2681
2681
|
// ../lsp-core/src/lsp/workspace-edit-commit.ts
|
|
2682
2682
|
var DEFAULT_IO = {
|
|
2683
|
-
writeFile(
|
|
2684
|
-
writeFileSync(
|
|
2683
|
+
writeFile(path, content) {
|
|
2684
|
+
writeFileSync(path, content, "utf-8");
|
|
2685
2685
|
},
|
|
2686
2686
|
rename(oldPath, newPath) {
|
|
2687
2687
|
renameSync(oldPath, newPath);
|
|
2688
2688
|
},
|
|
2689
|
-
remove(
|
|
2690
|
-
rmSync(
|
|
2689
|
+
remove(path, recursive) {
|
|
2690
|
+
rmSync(path, { recursive, force: false });
|
|
2691
2691
|
}
|
|
2692
2692
|
};
|
|
2693
2693
|
function snapshotsEqual(expected, actual) {
|
|
@@ -2700,8 +2700,8 @@ function snapshotsEqual(expected, actual) {
|
|
|
2700
2700
|
}
|
|
2701
2701
|
return true;
|
|
2702
2702
|
}
|
|
2703
|
-
function liveSnapshot(
|
|
2704
|
-
return snapshotPath(
|
|
2703
|
+
function liveSnapshot(path, expected) {
|
|
2704
|
+
return snapshotPath(path, expected.kind === "directory" && expected.children !== undefined);
|
|
2705
2705
|
}
|
|
2706
2706
|
function firstOperationIndex(plan) {
|
|
2707
2707
|
return plan.operations[0]?.changeIndex ?? 0;
|
|
@@ -2722,28 +2722,28 @@ function failedCommit(plan, failure) {
|
|
|
2722
2722
|
};
|
|
2723
2723
|
}
|
|
2724
2724
|
function verifySnapshots(plan) {
|
|
2725
|
-
for (const [
|
|
2725
|
+
for (const [path, expected] of plan.snapshots) {
|
|
2726
2726
|
let actual;
|
|
2727
2727
|
try {
|
|
2728
|
-
actual = liveSnapshot(
|
|
2728
|
+
actual = liveSnapshot(path, expected);
|
|
2729
2729
|
} catch (error) {
|
|
2730
|
-
const changeIndex = plan.firstChangeByPath.get(
|
|
2730
|
+
const changeIndex = plan.firstChangeByPath.get(path) ?? firstOperationIndex(plan);
|
|
2731
2731
|
const detail = error instanceof Error ? error.message : String(error);
|
|
2732
|
-
return failedCommit(plan, { message: `cannot verify snapshot for ${
|
|
2732
|
+
return failedCommit(plan, { message: `cannot verify snapshot for ${path}: ${detail}`, changeIndex });
|
|
2733
2733
|
}
|
|
2734
2734
|
if (!snapshotsEqual(expected, actual)) {
|
|
2735
|
-
const changeIndex = plan.firstChangeByPath.get(
|
|
2736
|
-
return failedCommit(plan, { message: `workspace state changed before commit: ${
|
|
2735
|
+
const changeIndex = plan.firstChangeByPath.get(path) ?? firstOperationIndex(plan);
|
|
2736
|
+
return failedCommit(plan, { message: `workspace state changed before commit: ${path}`, changeIndex });
|
|
2737
2737
|
}
|
|
2738
2738
|
}
|
|
2739
2739
|
return null;
|
|
2740
2740
|
}
|
|
2741
|
-
function addModifiedPath(paths,
|
|
2742
|
-
if (!paths.includes(
|
|
2743
|
-
paths.push(
|
|
2741
|
+
function addModifiedPath(paths, path) {
|
|
2742
|
+
if (!paths.includes(path))
|
|
2743
|
+
paths.push(path);
|
|
2744
2744
|
}
|
|
2745
|
-
function reportedPath(plan,
|
|
2746
|
-
return plan.reportedPathByCanonical.get(
|
|
2745
|
+
function reportedPath(plan, path) {
|
|
2746
|
+
return plan.reportedPathByCanonical.get(path) ?? path;
|
|
2747
2747
|
}
|
|
2748
2748
|
function changedPathsForMutation(mutation) {
|
|
2749
2749
|
return mutation.kind === "rename" ? [mutation.oldPath, mutation.newPath] : [mutation.path];
|
|
@@ -2751,8 +2751,8 @@ function changedPathsForMutation(mutation) {
|
|
|
2751
2751
|
function mutationDelta(operations) {
|
|
2752
2752
|
const changedPaths = new Set;
|
|
2753
2753
|
for (const operation of operations) {
|
|
2754
|
-
for (const
|
|
2755
|
-
changedPaths.add(
|
|
2754
|
+
for (const path of changedPathsForMutation(operation))
|
|
2755
|
+
changedPaths.add(path);
|
|
2756
2756
|
}
|
|
2757
2757
|
return { operations, changedPaths: [...changedPaths].sort() };
|
|
2758
2758
|
}
|
|
@@ -2986,14 +2986,14 @@ function parseSinglePathResource(input, kind) {
|
|
|
2986
2986
|
return;
|
|
2987
2987
|
}
|
|
2988
2988
|
if (kind === "create") {
|
|
2989
|
-
const
|
|
2989
|
+
const options = parseOptions(change["options"], ["overwrite", "ignoreIfExists"], changeIndex);
|
|
2990
2990
|
target.operations.push({
|
|
2991
2991
|
kind,
|
|
2992
2992
|
changeIndex,
|
|
2993
2993
|
path: resolvedPath.path,
|
|
2994
2994
|
reportedPath: resolvedPath.requestedPath,
|
|
2995
|
-
overwrite:
|
|
2996
|
-
ignoreIfExists:
|
|
2995
|
+
overwrite: options["overwrite"] ?? false,
|
|
2996
|
+
ignoreIfExists: options["ignoreIfExists"] ?? false,
|
|
2997
2997
|
followedSymbolicLink: resolvedPath.followedSymbolicLink
|
|
2998
2998
|
});
|
|
2999
2999
|
return;
|
|
@@ -3251,12 +3251,12 @@ function isSameOrDescendant2(candidate, parent) {
|
|
|
3251
3251
|
const relativePath = relative4(parent, candidate);
|
|
3252
3252
|
return relativePath === "" || !relativePath.startsWith("..") && relativePath !== "..";
|
|
3253
3253
|
}
|
|
3254
|
-
function removeVirtualSubtree(virtual,
|
|
3254
|
+
function removeVirtualSubtree(virtual, path) {
|
|
3255
3255
|
for (const candidate of [...virtual.keys()]) {
|
|
3256
|
-
if (isSameOrDescendant2(candidate,
|
|
3256
|
+
if (isSameOrDescendant2(candidate, path))
|
|
3257
3257
|
virtual.delete(candidate);
|
|
3258
3258
|
}
|
|
3259
|
-
virtual.set(
|
|
3259
|
+
virtual.set(path, { kind: "missing" });
|
|
3260
3260
|
}
|
|
3261
3261
|
function moveVirtualSubtree(virtual, oldPath, newPath) {
|
|
3262
3262
|
const moved = [...virtual.entries()].filter(([candidate]) => isSameOrDescendant2(candidate, oldPath));
|
|
@@ -3267,16 +3267,16 @@ function moveVirtualSubtree(virtual, oldPath, newPath) {
|
|
|
3267
3267
|
virtual.set(suffix === "" ? newPath : resolve4(newPath, suffix), entry);
|
|
3268
3268
|
}
|
|
3269
3269
|
}
|
|
3270
|
-
function virtualDirectoryHasChildren(virtual,
|
|
3270
|
+
function virtualDirectoryHasChildren(virtual, path) {
|
|
3271
3271
|
for (const [candidate, entry] of virtual) {
|
|
3272
|
-
if (candidate !==
|
|
3272
|
+
if (candidate !== path && entry.kind !== "missing" && isSameOrDescendant2(candidate, path))
|
|
3273
3273
|
return true;
|
|
3274
3274
|
}
|
|
3275
3275
|
return false;
|
|
3276
3276
|
}
|
|
3277
|
-
function requireVirtualParent(virtual,
|
|
3278
|
-
if (virtual.get(dirname5(
|
|
3279
|
-
throw new WorkspaceEditValidationError(changeIndex, `parent directory does not exist for ${
|
|
3277
|
+
function requireVirtualParent(virtual, path, changeIndex) {
|
|
3278
|
+
if (virtual.get(dirname5(path))?.kind !== "directory") {
|
|
3279
|
+
throw new WorkspaceEditValidationError(changeIndex, `parent directory does not exist for ${path}`);
|
|
3280
3280
|
}
|
|
3281
3281
|
}
|
|
3282
3282
|
function simulateOperations(parsed, snapshots) {
|
|
@@ -3421,21 +3421,21 @@ class WorkspaceSnapshotBuilder {
|
|
|
3421
3421
|
}
|
|
3422
3422
|
return this.snapshots;
|
|
3423
3423
|
}
|
|
3424
|
-
add(
|
|
3425
|
-
let candidate =
|
|
3424
|
+
add(path, includeChildren) {
|
|
3425
|
+
let candidate = path;
|
|
3426
3426
|
while (true) {
|
|
3427
3427
|
const existing = this.snapshots.get(candidate);
|
|
3428
3428
|
if (existing === undefined || includeChildren && existing.kind === "directory" && existing.children === undefined) {
|
|
3429
|
-
this.snapshots.set(candidate, snapshotPath(candidate, includeChildren && candidate ===
|
|
3429
|
+
this.snapshots.set(candidate, snapshotPath(candidate, includeChildren && candidate === path));
|
|
3430
3430
|
}
|
|
3431
3431
|
if (candidate === this.workspaceRoot)
|
|
3432
3432
|
break;
|
|
3433
3433
|
candidate = dirname6(candidate);
|
|
3434
3434
|
}
|
|
3435
|
-
if (!includeChildren || !existsSync6(
|
|
3435
|
+
if (!includeChildren || !existsSync6(path) || !lstatSync4(path).isDirectory())
|
|
3436
3436
|
return;
|
|
3437
|
-
for (const child of readdirSync2(
|
|
3438
|
-
this.add(resolve5(
|
|
3437
|
+
for (const child of readdirSync2(path))
|
|
3438
|
+
this.add(resolve5(path, child), true);
|
|
3439
3439
|
}
|
|
3440
3440
|
}
|
|
3441
3441
|
function snapshotOperations(operations, workspaceRoot) {
|
|
@@ -3463,11 +3463,11 @@ class PlanPathIndex {
|
|
|
3463
3463
|
}
|
|
3464
3464
|
}
|
|
3465
3465
|
}
|
|
3466
|
-
add(
|
|
3467
|
-
if (!this.firstChangeByPath.has(
|
|
3468
|
-
this.firstChangeByPath.set(
|
|
3469
|
-
if (!this.reportedPathByCanonical.has(
|
|
3470
|
-
this.reportedPathByCanonical.set(
|
|
3466
|
+
add(path, reportedPath, changeIndex) {
|
|
3467
|
+
if (!this.firstChangeByPath.has(path))
|
|
3468
|
+
this.firstChangeByPath.set(path, changeIndex);
|
|
3469
|
+
if (!this.reportedPathByCanonical.has(path))
|
|
3470
|
+
this.reportedPathByCanonical.set(path, reportedPath);
|
|
3471
3471
|
}
|
|
3472
3472
|
}
|
|
3473
3473
|
function fingerprintWorkspaceEdit(edit, workspaceRoot) {
|
|
@@ -3579,15 +3579,15 @@ class WorkspaceMutationController {
|
|
|
3579
3579
|
};
|
|
3580
3580
|
}
|
|
3581
3581
|
lease.phase = "applying";
|
|
3582
|
-
lease.applyCompletion = new Promise((
|
|
3583
|
-
lease.resolveApply =
|
|
3582
|
+
lease.applyCompletion = new Promise((resolve) => {
|
|
3583
|
+
lease.resolveApply = resolve;
|
|
3584
3584
|
});
|
|
3585
3585
|
const edit = isRecord4(params) ? params["edit"] : undefined;
|
|
3586
|
-
const
|
|
3587
|
-
lease.serverApply =
|
|
3586
|
+
const record = edit === undefined ? { fingerprint: null, result: failure("workspace/applyEdit params.edit is required", 0) } : await this.applyEdit(edit, lease);
|
|
3587
|
+
lease.serverApply = record;
|
|
3588
3588
|
lease.phase = "settled";
|
|
3589
3589
|
lease.resolveApply?.();
|
|
3590
|
-
return responseFor(
|
|
3590
|
+
return responseFor(record.result);
|
|
3591
3591
|
}
|
|
3592
3592
|
async reconcileRename(leaseToken, edit) {
|
|
3593
3593
|
const lease = this.requireActiveLease(leaseToken);
|
|
@@ -3603,16 +3603,16 @@ class WorkspaceMutationController {
|
|
|
3603
3603
|
const applied = await this.applyEdit(edit, lease);
|
|
3604
3604
|
return { edit, apply: applied.result };
|
|
3605
3605
|
}
|
|
3606
|
-
reconcileServerApply(
|
|
3606
|
+
reconcileServerApply(record, edit) {
|
|
3607
3607
|
if (!edit)
|
|
3608
|
-
return { edit, apply:
|
|
3608
|
+
return { edit, apply: record.result };
|
|
3609
3609
|
const fingerprint = fingerprintWorkspaceEdit(edit, this.workspaceRoot);
|
|
3610
|
-
if (fingerprint.success &&
|
|
3611
|
-
return { edit, apply:
|
|
3610
|
+
if (fingerprint.success && record.fingerprint !== null && fingerprint.fingerprint === record.fingerprint) {
|
|
3611
|
+
return { edit, apply: record.result };
|
|
3612
3612
|
}
|
|
3613
3613
|
return {
|
|
3614
3614
|
edit,
|
|
3615
|
-
apply: failure("rename result conflicts with server-applied workspace edit", 0,
|
|
3615
|
+
apply: failure("rename result conflicts with server-applied workspace edit", 0, record.result)
|
|
3616
3616
|
};
|
|
3617
3617
|
}
|
|
3618
3618
|
async applyEdit(edit, lease) {
|
|
@@ -3653,8 +3653,8 @@ var DIAGNOSTICS_FRESHNESS_TIMEOUT_MS = 3000;
|
|
|
3653
3653
|
var VERSIONLESS_PUBLISH_QUIESCENCE_MS = 250;
|
|
3654
3654
|
|
|
3655
3655
|
class LspClient extends LspClientConnection {
|
|
3656
|
-
constructor(root,
|
|
3657
|
-
super(root,
|
|
3656
|
+
constructor(root, server, options = {}) {
|
|
3657
|
+
super(root, server, options);
|
|
3658
3658
|
this.diagnosticPullErrors = [];
|
|
3659
3659
|
this.diagnosticsFreshnessTimeoutMs = options.diagnosticsFreshnessTimeoutMs ?? DIAGNOSTICS_FRESHNESS_TIMEOUT_MS;
|
|
3660
3660
|
this.documents = new WorkspaceDocumentState((method, params) => this.sendNotification(method, params), (uri) => this.diagnosticsStore.delete(uri), {
|
|
@@ -3775,13 +3775,13 @@ class LspClient extends LspClientConnection {
|
|
|
3775
3775
|
if (!pushFallbackOnly) {
|
|
3776
3776
|
const cached = this.documents.getPullCache(snapshot);
|
|
3777
3777
|
try {
|
|
3778
|
-
const
|
|
3779
|
-
if (
|
|
3778
|
+
const remainingMs = deadlineAt - this.timerProvider.now();
|
|
3779
|
+
if (remainingMs <= 0)
|
|
3780
3780
|
return this.freshnessTimeout(absPath);
|
|
3781
3781
|
const result = await this.sendRequest("textDocument/diagnostic", {
|
|
3782
3782
|
textDocument: { uri },
|
|
3783
3783
|
...cached?.resultId === undefined ? {} : { previousResultId: cached.resultId }
|
|
3784
|
-
}, { timeoutMs:
|
|
3784
|
+
}, { timeoutMs: remainingMs, ...signal === undefined ? {} : { signal } });
|
|
3785
3785
|
if (!this.documents.isCurrentSnapshot(snapshot))
|
|
3786
3786
|
continue;
|
|
3787
3787
|
const report = this.parseDiagnosticPullReport(result);
|
|
@@ -3862,7 +3862,7 @@ function waitForDiagnosticsActivity(wait, signal) {
|
|
|
3862
3862
|
return wait;
|
|
3863
3863
|
if (signal.aborted)
|
|
3864
3864
|
return Promise.reject(abortError3(signal));
|
|
3865
|
-
return new Promise((
|
|
3865
|
+
return new Promise((resolve, reject) => {
|
|
3866
3866
|
const onAbort = () => {
|
|
3867
3867
|
signal.removeEventListener("abort", onAbort);
|
|
3868
3868
|
reject(abortError3(signal));
|
|
@@ -3870,7 +3870,7 @@ function waitForDiagnosticsActivity(wait, signal) {
|
|
|
3870
3870
|
signal.addEventListener("abort", onAbort, { once: true });
|
|
3871
3871
|
wait.then(() => {
|
|
3872
3872
|
signal.removeEventListener("abort", onAbort);
|
|
3873
|
-
|
|
3873
|
+
resolve();
|
|
3874
3874
|
}, (error) => {
|
|
3875
3875
|
signal.removeEventListener("abort", onAbort);
|
|
3876
3876
|
reject(error);
|
|
@@ -3938,7 +3938,7 @@ async function stopClientBestEffort(client) {
|
|
|
3938
3938
|
function awaitWithSignal2(promise, signal) {
|
|
3939
3939
|
if (!signal)
|
|
3940
3940
|
return promise;
|
|
3941
|
-
return new Promise((
|
|
3941
|
+
return new Promise((resolve, reject) => {
|
|
3942
3942
|
let settled = false;
|
|
3943
3943
|
const onAbort = () => {
|
|
3944
3944
|
if (settled)
|
|
@@ -3956,7 +3956,7 @@ function awaitWithSignal2(promise, signal) {
|
|
|
3956
3956
|
return;
|
|
3957
3957
|
settled = true;
|
|
3958
3958
|
signal.removeEventListener("abort", onAbort);
|
|
3959
|
-
|
|
3959
|
+
resolve(value);
|
|
3960
3960
|
}, (err) => {
|
|
3961
3961
|
if (settled)
|
|
3962
3962
|
return;
|
|
@@ -3979,7 +3979,7 @@ class LspManager {
|
|
|
3979
3979
|
this.initTimeoutMs = options.initTimeoutMs ?? INIT_TIMEOUT_MS;
|
|
3980
3980
|
this.maxResidentClients = options.maxResidentClients ?? MAX_RESIDENT_CLIENTS;
|
|
3981
3981
|
this.reaperIntervalMs = options.reaperIntervalMs ?? REAPER_INTERVAL_MS;
|
|
3982
|
-
this.clientFactory = options.clientFactory ?? ((root,
|
|
3982
|
+
this.clientFactory = options.clientFactory ?? ((root, server) => new LspClient(root, server));
|
|
3983
3983
|
this.now = options.now ?? (() => Date.now());
|
|
3984
3984
|
this.startReaper();
|
|
3985
3985
|
this.signalDisposer = installProcessSignalCleanup(() => this.stopAll());
|
|
@@ -4072,12 +4072,12 @@ class LspManager {
|
|
|
4072
4072
|
await this.tombstoneStop(key, managed.client);
|
|
4073
4073
|
}
|
|
4074
4074
|
}
|
|
4075
|
-
async getClient(root,
|
|
4075
|
+
async getClient(root, server, signal) {
|
|
4076
4076
|
if (this.disposed) {
|
|
4077
4077
|
throw new Error("LspManager has been disposed");
|
|
4078
4078
|
}
|
|
4079
4079
|
signal?.throwIfAborted();
|
|
4080
|
-
const key = this.getKey(root,
|
|
4080
|
+
const key = this.getKey(root, server.id);
|
|
4081
4081
|
for (;; ) {
|
|
4082
4082
|
const pendingStop = this.pendingStops.get(key);
|
|
4083
4083
|
if (pendingStop === undefined)
|
|
@@ -4119,7 +4119,7 @@ class LspManager {
|
|
|
4119
4119
|
this.clients.delete(key);
|
|
4120
4120
|
}
|
|
4121
4121
|
await this.tombstoneStop(key, managed.client);
|
|
4122
|
-
return this.getClient(root,
|
|
4122
|
+
return this.getClient(root, server, signal);
|
|
4123
4123
|
}
|
|
4124
4124
|
this.markHealthyGeneration(key);
|
|
4125
4125
|
managed.refCount++;
|
|
@@ -4127,8 +4127,8 @@ class LspManager {
|
|
|
4127
4127
|
return managed.client;
|
|
4128
4128
|
}
|
|
4129
4129
|
this.evictForAdmission();
|
|
4130
|
-
this.ensureRespawnAllowed(key, root,
|
|
4131
|
-
const client = this.clientFactory(root,
|
|
4130
|
+
this.ensureRespawnAllowed(key, root, server.id);
|
|
4131
|
+
const client = this.clientFactory(root, server);
|
|
4132
4132
|
const initStartedAt = this.now();
|
|
4133
4133
|
const initPromise = (async () => {
|
|
4134
4134
|
await client.start();
|
|
@@ -4168,7 +4168,7 @@ class LspManager {
|
|
|
4168
4168
|
this.clients.delete(key);
|
|
4169
4169
|
}
|
|
4170
4170
|
await this.tombstoneStop(key, client);
|
|
4171
|
-
return this.getClient(root,
|
|
4171
|
+
return this.getClient(root, server, signal);
|
|
4172
4172
|
}
|
|
4173
4173
|
this.markHealthyGeneration(key);
|
|
4174
4174
|
newManaged.refCount++;
|
|
@@ -4193,19 +4193,19 @@ class LspManager {
|
|
|
4193
4193
|
this.clients.delete(key);
|
|
4194
4194
|
this.tombstoneStop(key, managed.client);
|
|
4195
4195
|
}
|
|
4196
|
-
warmupClient(root,
|
|
4196
|
+
warmupClient(root, server) {
|
|
4197
4197
|
if (this.disposed)
|
|
4198
4198
|
return;
|
|
4199
|
-
const key = this.getKey(root,
|
|
4199
|
+
const key = this.getKey(root, server.id);
|
|
4200
4200
|
if (this.clients.has(key) || this.pendingStops.has(key))
|
|
4201
4201
|
return;
|
|
4202
4202
|
this.evictForAdmission();
|
|
4203
4203
|
try {
|
|
4204
|
-
this.ensureRespawnAllowed(key, root,
|
|
4204
|
+
this.ensureRespawnAllowed(key, root, server.id);
|
|
4205
4205
|
} catch {
|
|
4206
4206
|
return;
|
|
4207
4207
|
}
|
|
4208
|
-
const client = this.clientFactory(root,
|
|
4208
|
+
const client = this.clientFactory(root, server);
|
|
4209
4209
|
const initStartedAt = this.now();
|
|
4210
4210
|
const initPromise = (async () => {
|
|
4211
4211
|
await client.start();
|
|
@@ -4516,11 +4516,11 @@ function getInstallDecisionsPath() {
|
|
|
4516
4516
|
return lspRequestContext().installDecisionsPath;
|
|
4517
4517
|
}
|
|
4518
4518
|
function loadInstallDecisions() {
|
|
4519
|
-
const
|
|
4520
|
-
if (!existsSync8(
|
|
4519
|
+
const path = getInstallDecisionsPath();
|
|
4520
|
+
if (!existsSync8(path))
|
|
4521
4521
|
return {};
|
|
4522
4522
|
try {
|
|
4523
|
-
const parsed = JSON.parse(readFileSync4(
|
|
4523
|
+
const parsed = JSON.parse(readFileSync4(path, "utf8"));
|
|
4524
4524
|
return isInstallDecisions(parsed) ? parsed : {};
|
|
4525
4525
|
} catch {
|
|
4526
4526
|
return {};
|
|
@@ -4538,12 +4538,12 @@ function isInstallDecision(value) {
|
|
|
4538
4538
|
return value === "declined" || value === "allowed";
|
|
4539
4539
|
}
|
|
4540
4540
|
function writeInstallDecisions(decisions) {
|
|
4541
|
-
const
|
|
4542
|
-
mkdirSync3(dirname8(
|
|
4543
|
-
const tmpPath = `${
|
|
4541
|
+
const path = getInstallDecisionsPath();
|
|
4542
|
+
mkdirSync3(dirname8(path), { recursive: true });
|
|
4543
|
+
const tmpPath = `${path}.tmp`;
|
|
4544
4544
|
writeFileSync2(tmpPath, `${JSON.stringify(decisions, null, 2)}
|
|
4545
4545
|
`, "utf8");
|
|
4546
|
-
renameSync2(tmpPath,
|
|
4546
|
+
renameSync2(tmpPath, path);
|
|
4547
4547
|
}
|
|
4548
4548
|
function isInstallDecisions(value) {
|
|
4549
4549
|
return isRecord5(value) && Object.values(value).every(isInstallDecisionRecord);
|
|
@@ -4565,11 +4565,11 @@ function getProjectConfigPaths() {
|
|
|
4565
4565
|
function getUserConfigPath() {
|
|
4566
4566
|
return lspRequestContext().userConfigPath;
|
|
4567
4567
|
}
|
|
4568
|
-
function loadJsonFile(
|
|
4569
|
-
if (!existsSync9(
|
|
4568
|
+
function loadJsonFile(path) {
|
|
4569
|
+
if (!existsSync9(path))
|
|
4570
4570
|
return null;
|
|
4571
4571
|
try {
|
|
4572
|
-
const parsed = JSON.parse(readFileSync5(
|
|
4572
|
+
const parsed = JSON.parse(readFileSync5(path, "utf-8"));
|
|
4573
4573
|
return isConfigJson(parsed) ? parsed : null;
|
|
4574
4574
|
} catch {
|
|
4575
4575
|
return null;
|
|
@@ -4586,8 +4586,8 @@ function loadAllConfigs() {
|
|
|
4586
4586
|
return configs;
|
|
4587
4587
|
}
|
|
4588
4588
|
function loadFirstJsonFile(paths) {
|
|
4589
|
-
for (const
|
|
4590
|
-
const config = loadJsonFile(
|
|
4589
|
+
for (const path of paths) {
|
|
4590
|
+
const config = loadJsonFile(path);
|
|
4591
4591
|
if (config)
|
|
4592
4592
|
return config;
|
|
4593
4593
|
}
|
|
@@ -4613,10 +4613,10 @@ function getMergedServers() {
|
|
|
4613
4613
|
}
|
|
4614
4614
|
if (seen.has(id))
|
|
4615
4615
|
continue;
|
|
4616
|
-
const
|
|
4617
|
-
if (!
|
|
4616
|
+
const server = createServerFromEntry(id, entry, source);
|
|
4617
|
+
if (!server)
|
|
4618
4618
|
continue;
|
|
4619
|
-
servers.push(
|
|
4619
|
+
servers.push(server);
|
|
4620
4620
|
seen.add(id);
|
|
4621
4621
|
}
|
|
4622
4622
|
}
|
|
@@ -4648,7 +4648,7 @@ function createServerFromEntry(id, entry, source) {
|
|
|
4648
4648
|
if (source === "project") {
|
|
4649
4649
|
if (!builtin)
|
|
4650
4650
|
return null;
|
|
4651
|
-
const
|
|
4651
|
+
const server = createServer({
|
|
4652
4652
|
id,
|
|
4653
4653
|
command: builtin.command,
|
|
4654
4654
|
extensions: entry.extensions ?? builtin.extensions,
|
|
@@ -4656,35 +4656,35 @@ function createServerFromEntry(id, entry, source) {
|
|
|
4656
4656
|
source
|
|
4657
4657
|
});
|
|
4658
4658
|
if (entry.initialization !== undefined) {
|
|
4659
|
-
|
|
4659
|
+
server.initialization = entry.initialization;
|
|
4660
4660
|
}
|
|
4661
|
-
return
|
|
4661
|
+
return server;
|
|
4662
4662
|
}
|
|
4663
4663
|
if (entry.command && entry.extensions) {
|
|
4664
|
-
const
|
|
4664
|
+
const server = createServer({
|
|
4665
4665
|
id,
|
|
4666
4666
|
command: entry.command,
|
|
4667
4667
|
extensions: entry.extensions,
|
|
4668
4668
|
priority: entry.priority ?? 0,
|
|
4669
4669
|
source
|
|
4670
4670
|
});
|
|
4671
|
-
applyOptionalServerFields(
|
|
4672
|
-
return
|
|
4671
|
+
applyOptionalServerFields(server, entry);
|
|
4672
|
+
return server;
|
|
4673
4673
|
}
|
|
4674
4674
|
if (!builtin)
|
|
4675
4675
|
return null;
|
|
4676
|
-
const
|
|
4676
|
+
const server = createServer({
|
|
4677
4677
|
id,
|
|
4678
4678
|
command: entry.command ?? builtin.command,
|
|
4679
4679
|
extensions: entry.extensions ?? builtin.extensions,
|
|
4680
4680
|
priority: entry.priority ?? 0,
|
|
4681
4681
|
source
|
|
4682
4682
|
});
|
|
4683
|
-
applyOptionalServerFields(
|
|
4684
|
-
return
|
|
4683
|
+
applyOptionalServerFields(server, entry);
|
|
4684
|
+
return server;
|
|
4685
4685
|
}
|
|
4686
4686
|
function createServer(input) {
|
|
4687
|
-
const
|
|
4687
|
+
const server = {
|
|
4688
4688
|
id: input.id,
|
|
4689
4689
|
command: input.command,
|
|
4690
4690
|
extensions: input.extensions,
|
|
@@ -4692,19 +4692,19 @@ function createServer(input) {
|
|
|
4692
4692
|
source: input.source
|
|
4693
4693
|
};
|
|
4694
4694
|
if (input.env !== undefined) {
|
|
4695
|
-
|
|
4695
|
+
server.env = input.env;
|
|
4696
4696
|
}
|
|
4697
4697
|
if (input.initialization !== undefined) {
|
|
4698
|
-
|
|
4698
|
+
server.initialization = input.initialization;
|
|
4699
4699
|
}
|
|
4700
|
-
return
|
|
4700
|
+
return server;
|
|
4701
4701
|
}
|
|
4702
|
-
function applyOptionalServerFields(
|
|
4702
|
+
function applyOptionalServerFields(server, entry) {
|
|
4703
4703
|
if (entry.env !== undefined) {
|
|
4704
|
-
|
|
4704
|
+
server.env = entry.env;
|
|
4705
4705
|
}
|
|
4706
4706
|
if (entry.initialization !== undefined) {
|
|
4707
|
-
|
|
4707
|
+
server.initialization = entry.initialization;
|
|
4708
4708
|
}
|
|
4709
4709
|
}
|
|
4710
4710
|
function isConfigJson(value) {
|
|
@@ -4793,9 +4793,9 @@ var LOCAL_BIN_RULES = [
|
|
|
4793
4793
|
];
|
|
4794
4794
|
var resolutionCache = new Map;
|
|
4795
4795
|
var probeCount = 0;
|
|
4796
|
-
function probe(
|
|
4796
|
+
function probe(path) {
|
|
4797
4797
|
probeCount += 1;
|
|
4798
|
-
return existsSync10(
|
|
4798
|
+
return existsSync10(path);
|
|
4799
4799
|
}
|
|
4800
4800
|
function executableSuffixes(platform, pathExt) {
|
|
4801
4801
|
if (platform !== "win32")
|
|
@@ -4895,24 +4895,24 @@ function withResolvedCommand(command, binaryPath) {
|
|
|
4895
4895
|
function findServerForExtension(ext) {
|
|
4896
4896
|
const servers = getMergedServers();
|
|
4897
4897
|
const workingDirectory = contextCwd();
|
|
4898
|
-
for (const
|
|
4899
|
-
if (!
|
|
4898
|
+
for (const server of servers) {
|
|
4899
|
+
if (!server.extensions.includes(ext))
|
|
4900
4900
|
continue;
|
|
4901
|
-
const binaryPath = resolveServerBinary(
|
|
4901
|
+
const binaryPath = resolveServerBinary(server.command, workingDirectory);
|
|
4902
4902
|
if (binaryPath !== null) {
|
|
4903
4903
|
const resolvedServer = {
|
|
4904
|
-
id:
|
|
4905
|
-
command: withResolvedCommand(
|
|
4906
|
-
extensions:
|
|
4907
|
-
priority:
|
|
4904
|
+
id: server.id,
|
|
4905
|
+
command: withResolvedCommand(server.command, binaryPath),
|
|
4906
|
+
extensions: server.extensions,
|
|
4907
|
+
priority: server.priority
|
|
4908
4908
|
};
|
|
4909
|
-
if (
|
|
4909
|
+
if (server.env !== undefined) {
|
|
4910
4910
|
return {
|
|
4911
4911
|
status: "found",
|
|
4912
4912
|
server: {
|
|
4913
4913
|
...resolvedServer,
|
|
4914
|
-
env:
|
|
4915
|
-
...
|
|
4914
|
+
env: server.env,
|
|
4915
|
+
...server.initialization === undefined ? {} : { initialization: server.initialization }
|
|
4916
4916
|
}
|
|
4917
4917
|
};
|
|
4918
4918
|
}
|
|
@@ -4920,20 +4920,20 @@ function findServerForExtension(ext) {
|
|
|
4920
4920
|
status: "found",
|
|
4921
4921
|
server: {
|
|
4922
4922
|
...resolvedServer,
|
|
4923
|
-
...
|
|
4923
|
+
...server.initialization === undefined ? {} : { initialization: server.initialization }
|
|
4924
4924
|
}
|
|
4925
4925
|
};
|
|
4926
4926
|
}
|
|
4927
4927
|
}
|
|
4928
|
-
for (const
|
|
4929
|
-
if (
|
|
4930
|
-
const installHint = LSP_INSTALL_HINTS[
|
|
4928
|
+
for (const server of servers) {
|
|
4929
|
+
if (server.extensions.includes(ext)) {
|
|
4930
|
+
const installHint = LSP_INSTALL_HINTS[server.id] ?? `Install '${server.command[0]}' and ensure it's in your PATH`;
|
|
4931
4931
|
return {
|
|
4932
4932
|
status: "not_installed",
|
|
4933
4933
|
server: {
|
|
4934
|
-
id:
|
|
4935
|
-
command:
|
|
4936
|
-
extensions:
|
|
4934
|
+
id: server.id,
|
|
4935
|
+
command: server.command,
|
|
4936
|
+
extensions: server.extensions
|
|
4937
4937
|
},
|
|
4938
4938
|
installHint
|
|
4939
4939
|
};
|
|
@@ -4952,18 +4952,18 @@ function getAllServers() {
|
|
|
4952
4952
|
const workingDirectory = contextCwd();
|
|
4953
4953
|
const result = [];
|
|
4954
4954
|
const seen = new Set;
|
|
4955
|
-
for (const
|
|
4956
|
-
if (seen.has(
|
|
4955
|
+
for (const server of servers) {
|
|
4956
|
+
if (seen.has(server.id))
|
|
4957
4957
|
continue;
|
|
4958
4958
|
result.push({
|
|
4959
|
-
id:
|
|
4960
|
-
installed: isServerInstalled(
|
|
4961
|
-
extensions:
|
|
4959
|
+
id: server.id,
|
|
4960
|
+
installed: isServerInstalled(server.command, workingDirectory),
|
|
4961
|
+
extensions: server.extensions,
|
|
4962
4962
|
disabled: false,
|
|
4963
|
-
source:
|
|
4964
|
-
priority:
|
|
4963
|
+
source: server.source,
|
|
4964
|
+
priority: server.priority
|
|
4965
4965
|
});
|
|
4966
|
-
seen.add(
|
|
4966
|
+
seen.add(server.id);
|
|
4967
4967
|
}
|
|
4968
4968
|
for (const id of disabled) {
|
|
4969
4969
|
if (seen.has(id))
|
|
@@ -5038,8 +5038,8 @@ function resolvePathInsideContext(filePath) {
|
|
|
5038
5038
|
}
|
|
5039
5039
|
return canonical;
|
|
5040
5040
|
}
|
|
5041
|
-
function rebaseThroughCanonicalAncestor(
|
|
5042
|
-
let current =
|
|
5041
|
+
function rebaseThroughCanonicalAncestor(path, cwd) {
|
|
5042
|
+
let current = path;
|
|
5043
5043
|
const suffix = [];
|
|
5044
5044
|
while (true) {
|
|
5045
5045
|
if (existsSync11(current)) {
|
|
@@ -5111,20 +5111,20 @@ function formatInstallOptions(serverId, installHint) {
|
|
|
5111
5111
|
];
|
|
5112
5112
|
}
|
|
5113
5113
|
function formatNotInstalled(result) {
|
|
5114
|
-
const { server
|
|
5115
|
-
const extensions =
|
|
5116
|
-
const decision = loadInstallDecision(
|
|
5114
|
+
const { server, installHint } = result;
|
|
5115
|
+
const extensions = server.extensions.join(", ");
|
|
5116
|
+
const decision = loadInstallDecision(server.id)?.decision;
|
|
5117
5117
|
const context = lspRequestContext();
|
|
5118
5118
|
if (decision === "declined") {
|
|
5119
|
-
return `LSP server '${
|
|
5119
|
+
return `LSP server '${server.id}' (${extensions}) is NOT INSTALLED; user previously declined installation — proceed without LSP.`;
|
|
5120
5120
|
}
|
|
5121
5121
|
const header = [
|
|
5122
|
-
`LSP server '${
|
|
5122
|
+
`LSP server '${server.id}' for ${extensions} is NOT INSTALLED.`,
|
|
5123
5123
|
"",
|
|
5124
|
-
`Command not found: ${
|
|
5124
|
+
`Command not found: ${server.command[0]}`,
|
|
5125
5125
|
""
|
|
5126
5126
|
];
|
|
5127
|
-
const installOptions = formatInstallOptions(
|
|
5127
|
+
const installOptions = formatInstallOptions(server.id, installHint);
|
|
5128
5128
|
if (decision === "allowed") {
|
|
5129
5129
|
return [
|
|
5130
5130
|
...header,
|
|
@@ -5150,7 +5150,7 @@ function formatNotInstalled(result) {
|
|
|
5150
5150
|
"ACTION REQUIRED — ASK THE USER whether to install this LSP server.",
|
|
5151
5151
|
"- If the user agrees: run the install command above, then retry this tool.",
|
|
5152
5152
|
"- If the user declines, OR has NOT explicitly asked for LSP installation:",
|
|
5153
|
-
` call lsp_install_decision { server_id: "${
|
|
5153
|
+
` call lsp_install_decision { server_id: "${server.id}", decision: "declined" },`,
|
|
5154
5154
|
` which writes to ${context.installDecisionsPath},`,
|
|
5155
5155
|
" then ignore this message and proceed WITHOUT LSP."
|
|
5156
5156
|
].join(`
|
|
@@ -5174,26 +5174,26 @@ async function withLspClient(filePath, fn, toolName, options = {}) {
|
|
|
5174
5174
|
if (result.status !== "found") {
|
|
5175
5175
|
throw new LspServerLookupError(formatServerLookupError(result), result);
|
|
5176
5176
|
}
|
|
5177
|
-
const
|
|
5177
|
+
const server = result.server;
|
|
5178
5178
|
const root = findWorkspaceRoot(absPath);
|
|
5179
5179
|
const manager = options.manager ?? getLspManager();
|
|
5180
5180
|
const acquireAndCall = async (allowRetry) => {
|
|
5181
|
-
const client = await manager.getClient(root,
|
|
5181
|
+
const client = await manager.getClient(root, server, options.signal);
|
|
5182
5182
|
try {
|
|
5183
5183
|
return await fn(client, root, absPath);
|
|
5184
5184
|
} catch (err) {
|
|
5185
5185
|
if (allowRetry && READ_ONLY_TOOLS.has(toolName) && isLspDeadConnectionError(err)) {
|
|
5186
|
-
manager.invalidateClient(root,
|
|
5186
|
+
manager.invalidateClient(root, server.id, client);
|
|
5187
5187
|
return acquireAndCall(false);
|
|
5188
5188
|
}
|
|
5189
5189
|
if (err instanceof LspRequestTimeoutError) {
|
|
5190
|
-
if (manager.isServerInitializing(root,
|
|
5190
|
+
if (manager.isServerInitializing(root, server.id)) {
|
|
5191
5191
|
throw new LspServerInitializingError(err);
|
|
5192
5192
|
}
|
|
5193
5193
|
}
|
|
5194
5194
|
throw err;
|
|
5195
5195
|
} finally {
|
|
5196
|
-
manager.releaseClient(root,
|
|
5196
|
+
manager.releaseClient(root, server.id);
|
|
5197
5197
|
}
|
|
5198
5198
|
};
|
|
5199
5199
|
return acquireAndCall(true);
|
|
@@ -5216,10 +5216,10 @@ function uriToPath(uri) {
|
|
|
5216
5216
|
}
|
|
5217
5217
|
function formatLocation(loc) {
|
|
5218
5218
|
if ("targetUri" in loc) {
|
|
5219
|
-
const
|
|
5220
|
-
const
|
|
5221
|
-
const
|
|
5222
|
-
return `${
|
|
5219
|
+
const uri = uriToPath(loc.targetUri);
|
|
5220
|
+
const line = loc.targetRange.start.line + 1;
|
|
5221
|
+
const char = loc.targetRange.start.character;
|
|
5222
|
+
return `${uri}:${line}:${char}`;
|
|
5223
5223
|
}
|
|
5224
5224
|
const uri = uriToPath(loc.uri);
|
|
5225
5225
|
const line = loc.range.start.line + 1;
|
|
@@ -5364,7 +5364,7 @@ async function aggregateDiagnosticsForDirectory(directory, extension, severity,
|
|
|
5364
5364
|
if (serverResult.status !== "found") {
|
|
5365
5365
|
throw new LspServerLookupError(formatServerLookupError(serverResult));
|
|
5366
5366
|
}
|
|
5367
|
-
const
|
|
5367
|
+
const server = serverResult.server;
|
|
5368
5368
|
const allFiles = (options.listFiles ?? collectFilesWithExtension)(absDir, extension, maxFiles + 1);
|
|
5369
5369
|
const wasCapped = allFiles.length > maxFiles;
|
|
5370
5370
|
const filesToProcess = allFiles.slice(0, maxFiles);
|
|
@@ -5384,7 +5384,7 @@ async function aggregateDiagnosticsForDirectory(directory, extension, severity,
|
|
|
5384
5384
|
const fileErrors = [];
|
|
5385
5385
|
const maxConcurrency = Math.max(1, options.maxConcurrency ?? DIRECTORY_DIAGNOSTICS_MAX_CONCURRENCY);
|
|
5386
5386
|
options.signal?.throwIfAborted();
|
|
5387
|
-
const client = await manager.getClient(root,
|
|
5387
|
+
const client = await manager.getClient(root, server, options.signal);
|
|
5388
5388
|
try {
|
|
5389
5389
|
let nextIndex = 0;
|
|
5390
5390
|
const workers = Array.from({ length: Math.min(maxConcurrency, filesToProcess.length) }, async () => {
|
|
@@ -5412,7 +5412,7 @@ async function aggregateDiagnosticsForDirectory(directory, extension, severity,
|
|
|
5412
5412
|
});
|
|
5413
5413
|
await Promise.all(workers);
|
|
5414
5414
|
} finally {
|
|
5415
|
-
manager.releaseClient(root,
|
|
5415
|
+
manager.releaseClient(root, server.id);
|
|
5416
5416
|
}
|
|
5417
5417
|
const displayDiagnostics = allDiagnostics.slice(0, DEFAULT_MAX_DIAGNOSTICS);
|
|
5418
5418
|
const wasDiagCapped = allDiagnostics.length > DEFAULT_MAX_DIAGNOSTICS;
|
|
@@ -5621,8 +5621,8 @@ function clientOptions(signal) {
|
|
|
5621
5621
|
}
|
|
5622
5622
|
|
|
5623
5623
|
// ../lsp-core/src/tools/result.ts
|
|
5624
|
-
function text(
|
|
5625
|
-
return { content: [{ type: "text", text
|
|
5624
|
+
function text(text, details, isError = false) {
|
|
5625
|
+
return { content: [{ type: "text", text }], details, isError };
|
|
5626
5626
|
}
|
|
5627
5627
|
|
|
5628
5628
|
// ../lsp-core/src/tools/diagnostics.ts
|
|
@@ -5642,7 +5642,7 @@ async function executeLspDiagnostics(params, signal) {
|
|
|
5642
5642
|
const extension = inferExtensionFromDirectory(absPath);
|
|
5643
5643
|
if (!extension) {
|
|
5644
5644
|
const message = `No supported source files found in directory: ${absPath}`;
|
|
5645
|
-
const
|
|
5645
|
+
const details = {
|
|
5646
5646
|
filePath,
|
|
5647
5647
|
severity,
|
|
5648
5648
|
mode: "directory",
|
|
@@ -5652,24 +5652,24 @@ async function executeLspDiagnostics(params, signal) {
|
|
|
5652
5652
|
error: message,
|
|
5653
5653
|
errorKind: "no_files"
|
|
5654
5654
|
};
|
|
5655
|
-
return text(message,
|
|
5655
|
+
return text(message, details);
|
|
5656
5656
|
}
|
|
5657
|
-
const
|
|
5658
|
-
const
|
|
5657
|
+
const output = await aggregateDiagnosticsForDirectory(absPath, extension, severity, undefined, signal === undefined ? {} : { signal });
|
|
5658
|
+
const details = {
|
|
5659
5659
|
filePath,
|
|
5660
5660
|
severity,
|
|
5661
5661
|
mode: "directory",
|
|
5662
5662
|
diagnostics: [],
|
|
5663
|
-
totalDiagnostics:
|
|
5663
|
+
totalDiagnostics: output.totalDiagnostics,
|
|
5664
5664
|
truncated: false,
|
|
5665
|
-
fileFailures: [...
|
|
5665
|
+
fileFailures: [...output.fileFailures]
|
|
5666
5666
|
};
|
|
5667
|
-
return text(
|
|
5667
|
+
return text(output.output, details);
|
|
5668
5668
|
}
|
|
5669
5669
|
const result = await withLspClient(filePath, async (client, _workspaceRoot, resolvedFilePath) => client.diagnostics(resolvedFilePath, signal), "diagnostics", clientOptions(signal));
|
|
5670
5670
|
if (result.transientError) {
|
|
5671
5671
|
const message = result.transientError.message;
|
|
5672
|
-
const
|
|
5672
|
+
const details = {
|
|
5673
5673
|
filePath,
|
|
5674
5674
|
severity,
|
|
5675
5675
|
mode: "file",
|
|
@@ -5679,7 +5679,7 @@ async function executeLspDiagnostics(params, signal) {
|
|
|
5679
5679
|
error: message,
|
|
5680
5680
|
errorKind: result.transientError.kind
|
|
5681
5681
|
};
|
|
5682
|
-
return text(message,
|
|
5682
|
+
return text(message, details, true);
|
|
5683
5683
|
}
|
|
5684
5684
|
const diagnostics = filterDiagnosticsBySeverity(asDiagnosticArray(result), severity);
|
|
5685
5685
|
const total = diagnostics.length;
|
|
@@ -5810,7 +5810,7 @@ async function executeLspInstallDecision(params) {
|
|
|
5810
5810
|
if (!isInstallDecision(decision)) {
|
|
5811
5811
|
return text(`Invalid decision '${String(decision)}'. Expected "declined" or "allowed".`, { serverId, errorKind: "invalid_decision" }, true);
|
|
5812
5812
|
}
|
|
5813
|
-
const serverIds = [...new Set(getMergedServers().map((
|
|
5813
|
+
const serverIds = [...new Set(getMergedServers().map((server) => server.id))];
|
|
5814
5814
|
if (!serverIds.includes(serverId)) {
|
|
5815
5815
|
const preview = serverIds.slice(0, 20).join(", ");
|
|
5816
5816
|
return text(`Unknown LSP server '${serverId}'. Known servers: ${preview}${serverIds.length > 20 ? "..." : ""}`, { serverId, errorKind: "unknown_server" }, true);
|
|
@@ -5950,10 +5950,10 @@ function objectSchema(properties, required = []) {
|
|
|
5950
5950
|
async function executeLspStatus() {
|
|
5951
5951
|
const servers = getAllServers();
|
|
5952
5952
|
const snapshots = getLspManager().getSnapshot();
|
|
5953
|
-
const installed = servers.filter((
|
|
5954
|
-
const configuredLines = servers.map((
|
|
5955
|
-
const state =
|
|
5956
|
-
return `- ${
|
|
5953
|
+
const installed = servers.filter((server) => server.installed && !server.disabled);
|
|
5954
|
+
const configuredLines = servers.map((server) => {
|
|
5955
|
+
const state = server.disabled ? "disabled" : server.installed ? "installed" : "missing";
|
|
5956
|
+
return `- ${server.id}: ${state}; source=${server.source}; extensions=${server.extensions.join(", ")}`;
|
|
5957
5957
|
});
|
|
5958
5958
|
const activeLines = snapshots.map((snapshot) => {
|
|
5959
5959
|
const state = snapshot.alive ? snapshot.isInitializing ? "initializing" : "alive" : "dead";
|
|
@@ -5996,8 +5996,8 @@ async function executeLspSymbols(params, signal) {
|
|
|
5996
5996
|
errorKind: "missing_query"
|
|
5997
5997
|
});
|
|
5998
5998
|
}
|
|
5999
|
-
const
|
|
6000
|
-
return formatSymbolsResult(filePath, scope,
|
|
5999
|
+
const symbols = await withLspClient(filePath, async (client) => client.workspaceSymbols(query, signal), "workspaceSymbols", clientOptions(signal));
|
|
6000
|
+
return formatSymbolsResult(filePath, scope, symbols, limit, query);
|
|
6001
6001
|
}
|
|
6002
6002
|
const symbols = await withLspClient(filePath, async (client, _workspaceRoot, resolvedFilePath) => client.documentSymbols(resolvedFilePath, signal), "documentSymbols", clientOptions(signal));
|
|
6003
6003
|
return formatSymbolsResult(filePath, scope, symbols, limit);
|
|
@@ -6389,7 +6389,7 @@ function withContext(args, context) {
|
|
|
6389
6389
|
function ensureDaemonAvailable(paths, ensure, signal) {
|
|
6390
6390
|
if (!signal)
|
|
6391
6391
|
return ensure(paths);
|
|
6392
|
-
return new Promise((
|
|
6392
|
+
return new Promise((resolve, reject) => {
|
|
6393
6393
|
let settled = false;
|
|
6394
6394
|
const finish = (run) => {
|
|
6395
6395
|
if (settled)
|
|
@@ -6404,11 +6404,11 @@ function ensureDaemonAvailable(paths, ensure, signal) {
|
|
|
6404
6404
|
return;
|
|
6405
6405
|
}
|
|
6406
6406
|
signal.addEventListener("abort", onAbort, { once: true });
|
|
6407
|
-
Promise.resolve().then(() => ensure(paths, signal)).then(() => finish(() =>
|
|
6407
|
+
Promise.resolve().then(() => ensure(paths, signal)).then(() => finish(() => resolve()), (error) => finish(() => reject(signal.aborted ? new DaemonRequestCancelledError(false) : error)));
|
|
6408
6408
|
});
|
|
6409
6409
|
}
|
|
6410
6410
|
function sendToolCall(paths, token, name, args, options) {
|
|
6411
|
-
return new Promise((
|
|
6411
|
+
return new Promise((resolve, reject) => {
|
|
6412
6412
|
const socket = connect(paths.socket);
|
|
6413
6413
|
const requestId = allocateProxyRequestId();
|
|
6414
6414
|
let settled = false;
|
|
@@ -6461,7 +6461,7 @@ function sendToolCall(paths, token, name, args, options) {
|
|
|
6461
6461
|
}
|
|
6462
6462
|
const result = toToolResult(message, requestId);
|
|
6463
6463
|
if (result)
|
|
6464
|
-
finish(() =>
|
|
6464
|
+
finish(() => resolve(result));
|
|
6465
6465
|
else
|
|
6466
6466
|
finish(() => reject(new DaemonRequestError("invalid daemon response", requestWritten)));
|
|
6467
6467
|
});
|