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
|
@@ -8,9 +8,9 @@ import { argv, execPath as execPath2, stderr } from "node:process";
|
|
|
8
8
|
import { stdin as processStdin } from "node:process";
|
|
9
9
|
|
|
10
10
|
// src/codex-hook.ts
|
|
11
|
-
import { readFileSync as
|
|
11
|
+
import { readFileSync as readFileSync9, realpathSync as realpathSync7 } from "node:fs";
|
|
12
12
|
import { homedir as homedir3 } from "node:os";
|
|
13
|
-
import { join as
|
|
13
|
+
import { join as join11, resolve as resolve11 } from "node:path";
|
|
14
14
|
|
|
15
15
|
// ../../../../lsp-daemon/dist/client.js
|
|
16
16
|
import { statSync as statSync5 } from "node:fs";
|
|
@@ -115,18 +115,18 @@ function parseLspRequestContext(value) {
|
|
|
115
115
|
const installDecisionsPath = stringField(value, "installDecisionsPath");
|
|
116
116
|
const capabilities = capabilitiesField(value["capabilities"]);
|
|
117
117
|
const canonical = canonicalCwd(cwd);
|
|
118
|
-
for (const
|
|
119
|
-
requireAbsolutePath(
|
|
120
|
-
const projectPath = canonicalizeExistingOrNearestAncestor(
|
|
118
|
+
for (const path of projectConfigPaths) {
|
|
119
|
+
requireAbsolutePath(path, "projectConfigPaths");
|
|
120
|
+
const projectPath = canonicalizeExistingOrNearestAncestor(path);
|
|
121
121
|
if (!isPathInside(canonical, projectPath)) {
|
|
122
|
-
throw new LspRequestContextParseError("project_config_outside_cwd", `Project LSP config path must be inside cwd: ${
|
|
122
|
+
throw new LspRequestContextParseError("project_config_outside_cwd", `Project LSP config path must be inside cwd: ${path}`);
|
|
123
123
|
}
|
|
124
124
|
}
|
|
125
125
|
requireAbsolutePath(userConfigPath, "userConfigPath");
|
|
126
126
|
requireAbsolutePath(installDecisionsPath, "installDecisionsPath");
|
|
127
127
|
return {
|
|
128
128
|
cwd: canonical,
|
|
129
|
-
projectConfigPaths: projectConfigPaths.map((
|
|
129
|
+
projectConfigPaths: projectConfigPaths.map((path) => canonicalizeExistingOrNearestAncestor(path)),
|
|
130
130
|
userConfigPath,
|
|
131
131
|
installDecisionsPath,
|
|
132
132
|
capabilities
|
|
@@ -139,8 +139,8 @@ function canonicalCwd(cwd) {
|
|
|
139
139
|
}
|
|
140
140
|
return realpathSync(resolved);
|
|
141
141
|
}
|
|
142
|
-
function canonicalizeExistingOrNearestAncestor(
|
|
143
|
-
let current = resolve(
|
|
142
|
+
function canonicalizeExistingOrNearestAncestor(path) {
|
|
143
|
+
let current = resolve(path);
|
|
144
144
|
const suffix = [];
|
|
145
145
|
while (true) {
|
|
146
146
|
try {
|
|
@@ -182,9 +182,9 @@ function stringArrayField(value, field) {
|
|
|
182
182
|
}
|
|
183
183
|
return fieldValue;
|
|
184
184
|
}
|
|
185
|
-
function requireAbsolutePath(
|
|
186
|
-
if (!isAbsolute(
|
|
187
|
-
throw new LspRequestContextParseError("relative_path", `LSP request context.${field} must be absolute: ${
|
|
185
|
+
function requireAbsolutePath(path, field) {
|
|
186
|
+
if (!isAbsolute(path)) {
|
|
187
|
+
throw new LspRequestContextParseError("relative_path", `LSP request context.${field} must be absolute: ${path}`);
|
|
188
188
|
}
|
|
189
189
|
}
|
|
190
190
|
function isPathInside(parent, child) {
|
|
@@ -521,7 +521,7 @@ async function probeDaemon(paths, timeoutMs = PROBE_TIMEOUT_MS, signal) {
|
|
|
521
521
|
return await pingDaemon(paths, token, timeoutMs, signal) !== null;
|
|
522
522
|
}
|
|
523
523
|
function pingDaemon(paths, token, timeoutMs = PROBE_TIMEOUT_MS, signal) {
|
|
524
|
-
return new Promise((
|
|
524
|
+
return new Promise((resolve) => {
|
|
525
525
|
const socket = new Socket;
|
|
526
526
|
let settled = false;
|
|
527
527
|
let timer;
|
|
@@ -533,7 +533,7 @@ function pingDaemon(paths, token, timeoutMs = PROBE_TIMEOUT_MS, signal) {
|
|
|
533
533
|
clearTimeout(timer);
|
|
534
534
|
signal?.removeEventListener("abort", onAbort);
|
|
535
535
|
socket.destroy();
|
|
536
|
-
|
|
536
|
+
resolve(value);
|
|
537
537
|
};
|
|
538
538
|
const onAbort = () => finish(null);
|
|
539
539
|
const decoder = createLineDecoder((message) => {
|
|
@@ -596,7 +596,7 @@ function defaultEnsureDaemonDeps() {
|
|
|
596
596
|
};
|
|
597
597
|
}
|
|
598
598
|
function sleepWithSignal(ms, signal) {
|
|
599
|
-
return new Promise((
|
|
599
|
+
return new Promise((resolve) => {
|
|
600
600
|
let settled = false;
|
|
601
601
|
const finish = () => {
|
|
602
602
|
if (settled)
|
|
@@ -604,7 +604,7 @@ function sleepWithSignal(ms, signal) {
|
|
|
604
604
|
settled = true;
|
|
605
605
|
clearTimeout(timer);
|
|
606
606
|
signal?.removeEventListener("abort", finish);
|
|
607
|
-
|
|
607
|
+
resolve();
|
|
608
608
|
};
|
|
609
609
|
const timer = setTimeout(finish, ms);
|
|
610
610
|
if (signal?.aborted) {
|
|
@@ -619,7 +619,7 @@ function awaitWithSignal(promise, signal) {
|
|
|
619
619
|
return promise;
|
|
620
620
|
if (signal.aborted)
|
|
621
621
|
return Promise.reject(abortError(signal));
|
|
622
|
-
return new Promise((
|
|
622
|
+
return new Promise((resolve, reject) => {
|
|
623
623
|
let settled = false;
|
|
624
624
|
const finish = (run) => {
|
|
625
625
|
if (settled)
|
|
@@ -630,7 +630,7 @@ function awaitWithSignal(promise, signal) {
|
|
|
630
630
|
};
|
|
631
631
|
const onAbort = () => finish(() => reject(abortError(signal)));
|
|
632
632
|
signal.addEventListener("abort", onAbort, { once: true });
|
|
633
|
-
promise.then((value) => finish(() =>
|
|
633
|
+
promise.then((value) => finish(() => resolve(value)), (error) => finish(() => reject(error)));
|
|
634
634
|
});
|
|
635
635
|
}
|
|
636
636
|
function throwIfAborted(signal) {
|
|
@@ -659,18 +659,18 @@ function parsePingResponse(message) {
|
|
|
659
659
|
return null;
|
|
660
660
|
if (!endpoint || typeof endpoint !== "object" || Array.isArray(endpoint))
|
|
661
661
|
return null;
|
|
662
|
-
const
|
|
662
|
+
const path = Reflect.get(endpoint, "path");
|
|
663
663
|
const kind = Reflect.get(endpoint, "kind");
|
|
664
|
-
if (typeof
|
|
664
|
+
if (typeof path !== "string")
|
|
665
665
|
return null;
|
|
666
666
|
if (kind === "windows")
|
|
667
|
-
return { pid, nonce, startedAt, endpoint: { kind, path
|
|
667
|
+
return { pid, nonce, startedAt, endpoint: { kind, path } };
|
|
668
668
|
if (kind === "missing")
|
|
669
|
-
return { pid, nonce, startedAt, endpoint: { kind, path
|
|
669
|
+
return { pid, nonce, startedAt, endpoint: { kind, path } };
|
|
670
670
|
const dev = Reflect.get(endpoint, "dev");
|
|
671
671
|
const ino = Reflect.get(endpoint, "ino");
|
|
672
672
|
if (kind === "unix" && typeof dev === "number" && typeof ino === "number") {
|
|
673
|
-
return { pid, nonce, startedAt, endpoint: { kind, path
|
|
673
|
+
return { pid, nonce, startedAt, endpoint: { kind, path, dev, ino } };
|
|
674
674
|
}
|
|
675
675
|
return null;
|
|
676
676
|
}
|
|
@@ -856,7 +856,7 @@ class JsonRpcConnection {
|
|
|
856
856
|
let settled = false;
|
|
857
857
|
const writeCancel = () => this.writeMessage({ jsonrpc: "2.0", method: "$/cancelRequest", params: { id } });
|
|
858
858
|
let rejectAfterCancelWrite;
|
|
859
|
-
const responsePromise = new Promise((
|
|
859
|
+
const responsePromise = new Promise((resolve, reject) => {
|
|
860
860
|
const cleanup = () => {
|
|
861
861
|
options.signal?.removeEventListener("abort", onAbort);
|
|
862
862
|
};
|
|
@@ -886,7 +886,7 @@ class JsonRpcConnection {
|
|
|
886
886
|
resolve(result) {
|
|
887
887
|
settled = true;
|
|
888
888
|
cleanup();
|
|
889
|
-
|
|
889
|
+
resolve(result);
|
|
890
890
|
},
|
|
891
891
|
reject(error) {
|
|
892
892
|
settled = true;
|
|
@@ -1045,13 +1045,13 @@ class JsonRpcConnection {
|
|
|
1045
1045
|
const payload = `Content-Length: ${Buffer.byteLength(body, "utf8")}\r
|
|
1046
1046
|
\r
|
|
1047
1047
|
${body}`;
|
|
1048
|
-
return new Promise((
|
|
1048
|
+
return new Promise((resolve, reject) => {
|
|
1049
1049
|
this.writer.write(payload, (error) => {
|
|
1050
1050
|
if (error) {
|
|
1051
1051
|
reject(error);
|
|
1052
1052
|
return;
|
|
1053
1053
|
}
|
|
1054
|
-
|
|
1054
|
+
resolve();
|
|
1055
1055
|
});
|
|
1056
1056
|
});
|
|
1057
1057
|
}
|
|
@@ -1133,9 +1133,9 @@ function validateCwd(cwd) {
|
|
|
1133
1133
|
}
|
|
1134
1134
|
}
|
|
1135
1135
|
function wrap(proc) {
|
|
1136
|
-
const exitedPromise = new Promise((
|
|
1137
|
-
proc.once("close", (code) =>
|
|
1138
|
-
proc.once("error", () =>
|
|
1136
|
+
const exitedPromise = new Promise((resolve) => {
|
|
1137
|
+
proc.once("close", (code) => resolve(code ?? 0));
|
|
1138
|
+
proc.once("error", () => resolve(1));
|
|
1139
1139
|
});
|
|
1140
1140
|
if (!proc.stdin || !proc.stdout || !proc.stderr) {
|
|
1141
1141
|
throw new LspProcessSpawnError("Spawned process is missing one of stdin/stdout/stderr pipes");
|
|
@@ -1294,9 +1294,9 @@ class LspClientNotStartedError extends Error {
|
|
|
1294
1294
|
}
|
|
1295
1295
|
|
|
1296
1296
|
class LspClientTransport {
|
|
1297
|
-
constructor(root,
|
|
1297
|
+
constructor(root, server, timeouts = {}) {
|
|
1298
1298
|
this.root = root;
|
|
1299
|
-
this.server =
|
|
1299
|
+
this.server = server;
|
|
1300
1300
|
this.proc = null;
|
|
1301
1301
|
this.connection = null;
|
|
1302
1302
|
this.stderrBuffer = [];
|
|
@@ -1478,8 +1478,8 @@ class LspClientTransport {
|
|
|
1478
1478
|
try {
|
|
1479
1479
|
proc.kill();
|
|
1480
1480
|
let timeoutId;
|
|
1481
|
-
const timeoutPromise = new Promise((
|
|
1482
|
-
timeoutId = setTimeout(
|
|
1481
|
+
const timeoutPromise = new Promise((resolve) => {
|
|
1482
|
+
timeoutId = setTimeout(resolve, STOP_HARD_KILL_TIMEOUT_MS);
|
|
1483
1483
|
});
|
|
1484
1484
|
await Promise.race([
|
|
1485
1485
|
proc.exited.then(() => {
|
|
@@ -1495,7 +1495,7 @@ class LspClientTransport {
|
|
|
1495
1495
|
proc.kill("SIGKILL");
|
|
1496
1496
|
await Promise.race([
|
|
1497
1497
|
proc.exited,
|
|
1498
|
-
new Promise((
|
|
1498
|
+
new Promise((resolve) => setTimeout(resolve, STOP_SIGKILL_GRACE_MS))
|
|
1499
1499
|
]);
|
|
1500
1500
|
} catch (error) {
|
|
1501
1501
|
reportBestEffortCleanupError("hard process kill", error instanceof Error ? error : String(error));
|
|
@@ -1833,16 +1833,16 @@ class WorkspaceDocumentState {
|
|
|
1833
1833
|
this.versionlessPublishQuiescenceMs = options.versionlessPublishQuiescenceMs ?? DEFAULT_VERSIONLESS_PUBLISH_QUIESCENCE_MS;
|
|
1834
1834
|
}
|
|
1835
1835
|
async openFile(filePath) {
|
|
1836
|
-
const
|
|
1837
|
-
const existingOpen = this.openPromises.get(
|
|
1836
|
+
const path = canonicalPath(filePath);
|
|
1837
|
+
const existingOpen = this.openPromises.get(path);
|
|
1838
1838
|
if (existingOpen) {
|
|
1839
1839
|
await existingOpen;
|
|
1840
|
-
return this.openFile(
|
|
1840
|
+
return this.openFile(path);
|
|
1841
1841
|
}
|
|
1842
|
-
const text = readFileSync2(
|
|
1843
|
-
const existing = this.openDocuments.get(
|
|
1842
|
+
const text = readFileSync2(path, "utf-8");
|
|
1843
|
+
const existing = this.openDocuments.get(path);
|
|
1844
1844
|
if (!existing)
|
|
1845
|
-
return this.openDocumentSingleFlight(
|
|
1845
|
+
return this.openDocumentSingleFlight(path, text);
|
|
1846
1846
|
if (existing.text === text)
|
|
1847
1847
|
return;
|
|
1848
1848
|
await this.changeDocument(existing, text);
|
|
@@ -1937,7 +1937,7 @@ class WorkspaceDocumentState {
|
|
|
1937
1937
|
});
|
|
1938
1938
|
}
|
|
1939
1939
|
validateVersions(operations) {
|
|
1940
|
-
const versions = new Map([...this.openDocuments].map(([
|
|
1940
|
+
const versions = new Map([...this.openDocuments].map(([path, state]) => [path, state.version]));
|
|
1941
1941
|
for (const operation of operations) {
|
|
1942
1942
|
if (operation.kind === "text") {
|
|
1943
1943
|
const current = versions.get(operation.path);
|
|
@@ -1953,17 +1953,17 @@ class WorkspaceDocumentState {
|
|
|
1953
1953
|
continue;
|
|
1954
1954
|
}
|
|
1955
1955
|
if (operation.kind === "rename") {
|
|
1956
|
-
const moved = [...versions].filter(([
|
|
1957
|
-
for (const [
|
|
1958
|
-
versions.delete(
|
|
1959
|
-
for (const [
|
|
1960
|
-
versions.set(movedPath(
|
|
1956
|
+
const moved = [...versions].filter(([path]) => isSameOrDescendant(path, operation.oldPath));
|
|
1957
|
+
for (const [path] of moved)
|
|
1958
|
+
versions.delete(path);
|
|
1959
|
+
for (const [path] of moved)
|
|
1960
|
+
versions.set(movedPath(path, operation.oldPath, operation.newPath), 1);
|
|
1961
1961
|
continue;
|
|
1962
1962
|
}
|
|
1963
1963
|
if (operation.kind === "delete") {
|
|
1964
|
-
for (const
|
|
1965
|
-
if (isSameOrDescendant(
|
|
1966
|
-
versions.delete(
|
|
1964
|
+
for (const path of [...versions.keys()]) {
|
|
1965
|
+
if (isSameOrDescendant(path, operation.path))
|
|
1966
|
+
versions.delete(path);
|
|
1967
1967
|
}
|
|
1968
1968
|
continue;
|
|
1969
1969
|
}
|
|
@@ -2007,8 +2007,8 @@ class WorkspaceDocumentState {
|
|
|
2007
2007
|
for (const state of moved)
|
|
2008
2008
|
await this.closeDocument(state);
|
|
2009
2009
|
for (const state of moved) {
|
|
2010
|
-
const
|
|
2011
|
-
await this.openDocumentSingleFlight(
|
|
2010
|
+
const path = movedPath(state.path, mutation.oldPath, mutation.newPath);
|
|
2011
|
+
await this.openDocumentSingleFlight(path, readFileSync2(path, "utf-8"));
|
|
2012
2012
|
}
|
|
2013
2013
|
if (moved.length === 0) {
|
|
2014
2014
|
watched.push({ uri: pathToFileURL2(mutation.oldPath).href, type: 3 });
|
|
@@ -2022,31 +2022,31 @@ class WorkspaceDocumentState {
|
|
|
2022
2022
|
if (removed.length === 0)
|
|
2023
2023
|
watched.push({ uri: pathToFileURL2(mutation.path).href, type: 3 });
|
|
2024
2024
|
}
|
|
2025
|
-
async openDocumentSingleFlight(
|
|
2026
|
-
const existing = this.openPromises.get(
|
|
2025
|
+
async openDocumentSingleFlight(path, text) {
|
|
2026
|
+
const existing = this.openPromises.get(path);
|
|
2027
2027
|
if (existing)
|
|
2028
2028
|
return existing;
|
|
2029
2029
|
const open = (async () => {
|
|
2030
2030
|
const state = {
|
|
2031
|
-
path
|
|
2032
|
-
uri: pathToFileURL2(
|
|
2033
|
-
languageId: getLanguageId(effectiveExtension(
|
|
2031
|
+
path,
|
|
2032
|
+
uri: pathToFileURL2(path).href,
|
|
2033
|
+
languageId: getLanguageId(effectiveExtension(path)),
|
|
2034
2034
|
text,
|
|
2035
2035
|
version: 1,
|
|
2036
2036
|
generation: 1,
|
|
2037
2037
|
publishGeneration: 0,
|
|
2038
2038
|
waiters: new Set
|
|
2039
2039
|
};
|
|
2040
|
-
this.openDocuments.set(
|
|
2040
|
+
this.openDocuments.set(path, state);
|
|
2041
2041
|
this.openByUri.set(normalizeDocumentUri(state.uri), state);
|
|
2042
2042
|
this.notifyWaiters(state);
|
|
2043
2043
|
await this.sendNotification("textDocument/didOpen", {
|
|
2044
2044
|
textDocument: { uri: state.uri, languageId: state.languageId, version: state.version, text }
|
|
2045
2045
|
});
|
|
2046
2046
|
})().finally(() => {
|
|
2047
|
-
this.openPromises.delete(
|
|
2047
|
+
this.openPromises.delete(path);
|
|
2048
2048
|
});
|
|
2049
|
-
this.openPromises.set(
|
|
2049
|
+
this.openPromises.set(path, open);
|
|
2050
2050
|
return open;
|
|
2051
2051
|
}
|
|
2052
2052
|
async changeDocument(state, text) {
|
|
@@ -2082,9 +2082,9 @@ function workspaceApplyEditConcurrentFailureReason(phase) {
|
|
|
2082
2082
|
}
|
|
2083
2083
|
|
|
2084
2084
|
class WorkspaceEditPathError extends Error {
|
|
2085
|
-
constructor(
|
|
2086
|
-
super(`${detail}: ${
|
|
2087
|
-
this.path =
|
|
2085
|
+
constructor(path, detail) {
|
|
2086
|
+
super(`${detail}: ${path}`);
|
|
2087
|
+
this.path = path;
|
|
2088
2088
|
this.detail = detail;
|
|
2089
2089
|
this.name = "WorkspaceEditPathError";
|
|
2090
2090
|
}
|
|
@@ -2148,26 +2148,26 @@ function uriToCanonicalWorkspacePath(uri, workspaceRoot) {
|
|
|
2148
2148
|
return { success: false, error: `${requestedPath}: ${detail}` };
|
|
2149
2149
|
}
|
|
2150
2150
|
}
|
|
2151
|
-
function snapshotPath(
|
|
2152
|
-
if (!existsSync4(
|
|
2151
|
+
function snapshotPath(path, includeChildren) {
|
|
2152
|
+
if (!existsSync4(path))
|
|
2153
2153
|
return { kind: "missing" };
|
|
2154
|
-
const stats = lstatSync2(
|
|
2154
|
+
const stats = lstatSync2(path);
|
|
2155
2155
|
if (stats.isFile())
|
|
2156
|
-
return { kind: "file", content: readFileSync3(
|
|
2156
|
+
return { kind: "file", content: readFileSync3(path, "utf-8") };
|
|
2157
2157
|
if (stats.isDirectory()) {
|
|
2158
|
-
return includeChildren ? { kind: "directory", children: readdirSync(
|
|
2158
|
+
return includeChildren ? { kind: "directory", children: readdirSync(path).sort() } : { kind: "directory" };
|
|
2159
2159
|
}
|
|
2160
|
-
throw new WorkspaceEditPathError(
|
|
2160
|
+
throw new WorkspaceEditPathError(path, "unsupported filesystem entry");
|
|
2161
2161
|
}
|
|
2162
2162
|
var DEFAULT_IO = {
|
|
2163
|
-
writeFile(
|
|
2164
|
-
writeFileSync(
|
|
2163
|
+
writeFile(path, content) {
|
|
2164
|
+
writeFileSync(path, content, "utf-8");
|
|
2165
2165
|
},
|
|
2166
2166
|
rename(oldPath, newPath) {
|
|
2167
2167
|
renameSync(oldPath, newPath);
|
|
2168
2168
|
},
|
|
2169
|
-
remove(
|
|
2170
|
-
rmSync(
|
|
2169
|
+
remove(path, recursive) {
|
|
2170
|
+
rmSync(path, { recursive, force: false });
|
|
2171
2171
|
}
|
|
2172
2172
|
};
|
|
2173
2173
|
function snapshotsEqual(expected, actual) {
|
|
@@ -2180,8 +2180,8 @@ function snapshotsEqual(expected, actual) {
|
|
|
2180
2180
|
}
|
|
2181
2181
|
return true;
|
|
2182
2182
|
}
|
|
2183
|
-
function liveSnapshot(
|
|
2184
|
-
return snapshotPath(
|
|
2183
|
+
function liveSnapshot(path, expected) {
|
|
2184
|
+
return snapshotPath(path, expected.kind === "directory" && expected.children !== undefined);
|
|
2185
2185
|
}
|
|
2186
2186
|
function firstOperationIndex(plan) {
|
|
2187
2187
|
return plan.operations[0]?.changeIndex ?? 0;
|
|
@@ -2202,28 +2202,28 @@ function failedCommit(plan, failure) {
|
|
|
2202
2202
|
};
|
|
2203
2203
|
}
|
|
2204
2204
|
function verifySnapshots(plan) {
|
|
2205
|
-
for (const [
|
|
2205
|
+
for (const [path, expected] of plan.snapshots) {
|
|
2206
2206
|
let actual;
|
|
2207
2207
|
try {
|
|
2208
|
-
actual = liveSnapshot(
|
|
2208
|
+
actual = liveSnapshot(path, expected);
|
|
2209
2209
|
} catch (error) {
|
|
2210
|
-
const changeIndex = plan.firstChangeByPath.get(
|
|
2210
|
+
const changeIndex = plan.firstChangeByPath.get(path) ?? firstOperationIndex(plan);
|
|
2211
2211
|
const detail = error instanceof Error ? error.message : String(error);
|
|
2212
|
-
return failedCommit(plan, { message: `cannot verify snapshot for ${
|
|
2212
|
+
return failedCommit(plan, { message: `cannot verify snapshot for ${path}: ${detail}`, changeIndex });
|
|
2213
2213
|
}
|
|
2214
2214
|
if (!snapshotsEqual(expected, actual)) {
|
|
2215
|
-
const changeIndex = plan.firstChangeByPath.get(
|
|
2216
|
-
return failedCommit(plan, { message: `workspace state changed before commit: ${
|
|
2215
|
+
const changeIndex = plan.firstChangeByPath.get(path) ?? firstOperationIndex(plan);
|
|
2216
|
+
return failedCommit(plan, { message: `workspace state changed before commit: ${path}`, changeIndex });
|
|
2217
2217
|
}
|
|
2218
2218
|
}
|
|
2219
2219
|
return null;
|
|
2220
2220
|
}
|
|
2221
|
-
function addModifiedPath(paths,
|
|
2222
|
-
if (!paths.includes(
|
|
2223
|
-
paths.push(
|
|
2221
|
+
function addModifiedPath(paths, path) {
|
|
2222
|
+
if (!paths.includes(path))
|
|
2223
|
+
paths.push(path);
|
|
2224
2224
|
}
|
|
2225
|
-
function reportedPath(plan,
|
|
2226
|
-
return plan.reportedPathByCanonical.get(
|
|
2225
|
+
function reportedPath(plan, path) {
|
|
2226
|
+
return plan.reportedPathByCanonical.get(path) ?? path;
|
|
2227
2227
|
}
|
|
2228
2228
|
function changedPathsForMutation(mutation) {
|
|
2229
2229
|
return mutation.kind === "rename" ? [mutation.oldPath, mutation.newPath] : [mutation.path];
|
|
@@ -2231,8 +2231,8 @@ function changedPathsForMutation(mutation) {
|
|
|
2231
2231
|
function mutationDelta(operations) {
|
|
2232
2232
|
const changedPaths = new Set;
|
|
2233
2233
|
for (const operation of operations) {
|
|
2234
|
-
for (const
|
|
2235
|
-
changedPaths.add(
|
|
2234
|
+
for (const path of changedPathsForMutation(operation))
|
|
2235
|
+
changedPaths.add(path);
|
|
2236
2236
|
}
|
|
2237
2237
|
return { operations, changedPaths: [...changedPaths].sort() };
|
|
2238
2238
|
}
|
|
@@ -2458,14 +2458,14 @@ function parseSinglePathResource(input, kind) {
|
|
|
2458
2458
|
return;
|
|
2459
2459
|
}
|
|
2460
2460
|
if (kind === "create") {
|
|
2461
|
-
const
|
|
2461
|
+
const options = parseOptions(change["options"], ["overwrite", "ignoreIfExists"], changeIndex);
|
|
2462
2462
|
target.operations.push({
|
|
2463
2463
|
kind,
|
|
2464
2464
|
changeIndex,
|
|
2465
2465
|
path: resolvedPath.path,
|
|
2466
2466
|
reportedPath: resolvedPath.requestedPath,
|
|
2467
|
-
overwrite:
|
|
2468
|
-
ignoreIfExists:
|
|
2467
|
+
overwrite: options["overwrite"] ?? false,
|
|
2468
|
+
ignoreIfExists: options["ignoreIfExists"] ?? false,
|
|
2469
2469
|
followedSymbolicLink: resolvedPath.followedSymbolicLink
|
|
2470
2470
|
});
|
|
2471
2471
|
return;
|
|
@@ -2714,12 +2714,12 @@ function isSameOrDescendant2(candidate, parent) {
|
|
|
2714
2714
|
const relativePath = relative4(parent, candidate);
|
|
2715
2715
|
return relativePath === "" || !relativePath.startsWith("..") && relativePath !== "..";
|
|
2716
2716
|
}
|
|
2717
|
-
function removeVirtualSubtree(virtual,
|
|
2717
|
+
function removeVirtualSubtree(virtual, path) {
|
|
2718
2718
|
for (const candidate of [...virtual.keys()]) {
|
|
2719
|
-
if (isSameOrDescendant2(candidate,
|
|
2719
|
+
if (isSameOrDescendant2(candidate, path))
|
|
2720
2720
|
virtual.delete(candidate);
|
|
2721
2721
|
}
|
|
2722
|
-
virtual.set(
|
|
2722
|
+
virtual.set(path, { kind: "missing" });
|
|
2723
2723
|
}
|
|
2724
2724
|
function moveVirtualSubtree(virtual, oldPath, newPath) {
|
|
2725
2725
|
const moved = [...virtual.entries()].filter(([candidate]) => isSameOrDescendant2(candidate, oldPath));
|
|
@@ -2730,16 +2730,16 @@ function moveVirtualSubtree(virtual, oldPath, newPath) {
|
|
|
2730
2730
|
virtual.set(suffix === "" ? newPath : resolve4(newPath, suffix), entry);
|
|
2731
2731
|
}
|
|
2732
2732
|
}
|
|
2733
|
-
function virtualDirectoryHasChildren(virtual,
|
|
2733
|
+
function virtualDirectoryHasChildren(virtual, path) {
|
|
2734
2734
|
for (const [candidate, entry] of virtual) {
|
|
2735
|
-
if (candidate !==
|
|
2735
|
+
if (candidate !== path && entry.kind !== "missing" && isSameOrDescendant2(candidate, path))
|
|
2736
2736
|
return true;
|
|
2737
2737
|
}
|
|
2738
2738
|
return false;
|
|
2739
2739
|
}
|
|
2740
|
-
function requireVirtualParent(virtual,
|
|
2741
|
-
if (virtual.get(dirname5(
|
|
2742
|
-
throw new WorkspaceEditValidationError(changeIndex, `parent directory does not exist for ${
|
|
2740
|
+
function requireVirtualParent(virtual, path, changeIndex) {
|
|
2741
|
+
if (virtual.get(dirname5(path))?.kind !== "directory") {
|
|
2742
|
+
throw new WorkspaceEditValidationError(changeIndex, `parent directory does not exist for ${path}`);
|
|
2743
2743
|
}
|
|
2744
2744
|
}
|
|
2745
2745
|
function simulateOperations(parsed, snapshots) {
|
|
@@ -2881,21 +2881,21 @@ class WorkspaceSnapshotBuilder {
|
|
|
2881
2881
|
}
|
|
2882
2882
|
return this.snapshots;
|
|
2883
2883
|
}
|
|
2884
|
-
add(
|
|
2885
|
-
let candidate =
|
|
2884
|
+
add(path, includeChildren) {
|
|
2885
|
+
let candidate = path;
|
|
2886
2886
|
while (true) {
|
|
2887
2887
|
const existing = this.snapshots.get(candidate);
|
|
2888
2888
|
if (existing === undefined || includeChildren && existing.kind === "directory" && existing.children === undefined) {
|
|
2889
|
-
this.snapshots.set(candidate, snapshotPath(candidate, includeChildren && candidate ===
|
|
2889
|
+
this.snapshots.set(candidate, snapshotPath(candidate, includeChildren && candidate === path));
|
|
2890
2890
|
}
|
|
2891
2891
|
if (candidate === this.workspaceRoot)
|
|
2892
2892
|
break;
|
|
2893
2893
|
candidate = dirname6(candidate);
|
|
2894
2894
|
}
|
|
2895
|
-
if (!includeChildren || !existsSync6(
|
|
2895
|
+
if (!includeChildren || !existsSync6(path) || !lstatSync4(path).isDirectory())
|
|
2896
2896
|
return;
|
|
2897
|
-
for (const child of readdirSync2(
|
|
2898
|
-
this.add(resolve5(
|
|
2897
|
+
for (const child of readdirSync2(path))
|
|
2898
|
+
this.add(resolve5(path, child), true);
|
|
2899
2899
|
}
|
|
2900
2900
|
}
|
|
2901
2901
|
function snapshotOperations(operations, workspaceRoot) {
|
|
@@ -2922,11 +2922,11 @@ class PlanPathIndex {
|
|
|
2922
2922
|
}
|
|
2923
2923
|
}
|
|
2924
2924
|
}
|
|
2925
|
-
add(
|
|
2926
|
-
if (!this.firstChangeByPath.has(
|
|
2927
|
-
this.firstChangeByPath.set(
|
|
2928
|
-
if (!this.reportedPathByCanonical.has(
|
|
2929
|
-
this.reportedPathByCanonical.set(
|
|
2925
|
+
add(path, reportedPath, changeIndex) {
|
|
2926
|
+
if (!this.firstChangeByPath.has(path))
|
|
2927
|
+
this.firstChangeByPath.set(path, changeIndex);
|
|
2928
|
+
if (!this.reportedPathByCanonical.has(path))
|
|
2929
|
+
this.reportedPathByCanonical.set(path, reportedPath);
|
|
2930
2930
|
}
|
|
2931
2931
|
}
|
|
2932
2932
|
function fingerprintWorkspaceEdit(edit, workspaceRoot) {
|
|
@@ -3036,15 +3036,15 @@ class WorkspaceMutationController {
|
|
|
3036
3036
|
};
|
|
3037
3037
|
}
|
|
3038
3038
|
lease.phase = "applying";
|
|
3039
|
-
lease.applyCompletion = new Promise((
|
|
3040
|
-
lease.resolveApply =
|
|
3039
|
+
lease.applyCompletion = new Promise((resolve) => {
|
|
3040
|
+
lease.resolveApply = resolve;
|
|
3041
3041
|
});
|
|
3042
3042
|
const edit = isRecord4(params) ? params["edit"] : undefined;
|
|
3043
|
-
const
|
|
3044
|
-
lease.serverApply =
|
|
3043
|
+
const record = edit === undefined ? { fingerprint: null, result: failure("workspace/applyEdit params.edit is required", 0) } : await this.applyEdit(edit, lease);
|
|
3044
|
+
lease.serverApply = record;
|
|
3045
3045
|
lease.phase = "settled";
|
|
3046
3046
|
lease.resolveApply?.();
|
|
3047
|
-
return responseFor(
|
|
3047
|
+
return responseFor(record.result);
|
|
3048
3048
|
}
|
|
3049
3049
|
async reconcileRename(leaseToken, edit) {
|
|
3050
3050
|
const lease = this.requireActiveLease(leaseToken);
|
|
@@ -3060,16 +3060,16 @@ class WorkspaceMutationController {
|
|
|
3060
3060
|
const applied = await this.applyEdit(edit, lease);
|
|
3061
3061
|
return { edit, apply: applied.result };
|
|
3062
3062
|
}
|
|
3063
|
-
reconcileServerApply(
|
|
3063
|
+
reconcileServerApply(record, edit) {
|
|
3064
3064
|
if (!edit)
|
|
3065
|
-
return { edit, apply:
|
|
3065
|
+
return { edit, apply: record.result };
|
|
3066
3066
|
const fingerprint = fingerprintWorkspaceEdit(edit, this.workspaceRoot);
|
|
3067
|
-
if (fingerprint.success &&
|
|
3068
|
-
return { edit, apply:
|
|
3067
|
+
if (fingerprint.success && record.fingerprint !== null && fingerprint.fingerprint === record.fingerprint) {
|
|
3068
|
+
return { edit, apply: record.result };
|
|
3069
3069
|
}
|
|
3070
3070
|
return {
|
|
3071
3071
|
edit,
|
|
3072
|
-
apply: failure("rename result conflicts with server-applied workspace edit", 0,
|
|
3072
|
+
apply: failure("rename result conflicts with server-applied workspace edit", 0, record.result)
|
|
3073
3073
|
};
|
|
3074
3074
|
}
|
|
3075
3075
|
async applyEdit(edit, lease) {
|
|
@@ -3108,8 +3108,8 @@ var DIAGNOSTICS_FRESHNESS_TIMEOUT_MS = 3000;
|
|
|
3108
3108
|
var VERSIONLESS_PUBLISH_QUIESCENCE_MS = 250;
|
|
3109
3109
|
|
|
3110
3110
|
class LspClient extends LspClientConnection {
|
|
3111
|
-
constructor(root,
|
|
3112
|
-
super(root,
|
|
3111
|
+
constructor(root, server, options = {}) {
|
|
3112
|
+
super(root, server, options);
|
|
3113
3113
|
this.diagnosticPullErrors = [];
|
|
3114
3114
|
this.diagnosticsFreshnessTimeoutMs = options.diagnosticsFreshnessTimeoutMs ?? DIAGNOSTICS_FRESHNESS_TIMEOUT_MS;
|
|
3115
3115
|
this.documents = new WorkspaceDocumentState((method, params) => this.sendNotification(method, params), (uri) => this.diagnosticsStore.delete(uri), {
|
|
@@ -3230,13 +3230,13 @@ class LspClient extends LspClientConnection {
|
|
|
3230
3230
|
if (!pushFallbackOnly) {
|
|
3231
3231
|
const cached = this.documents.getPullCache(snapshot);
|
|
3232
3232
|
try {
|
|
3233
|
-
const
|
|
3234
|
-
if (
|
|
3233
|
+
const remainingMs = deadlineAt - this.timerProvider.now();
|
|
3234
|
+
if (remainingMs <= 0)
|
|
3235
3235
|
return this.freshnessTimeout(absPath);
|
|
3236
3236
|
const result = await this.sendRequest("textDocument/diagnostic", {
|
|
3237
3237
|
textDocument: { uri },
|
|
3238
3238
|
...cached?.resultId === undefined ? {} : { previousResultId: cached.resultId }
|
|
3239
|
-
}, { timeoutMs:
|
|
3239
|
+
}, { timeoutMs: remainingMs, ...signal === undefined ? {} : { signal } });
|
|
3240
3240
|
if (!this.documents.isCurrentSnapshot(snapshot))
|
|
3241
3241
|
continue;
|
|
3242
3242
|
const report = this.parseDiagnosticPullReport(result);
|
|
@@ -3317,7 +3317,7 @@ function waitForDiagnosticsActivity(wait, signal) {
|
|
|
3317
3317
|
return wait;
|
|
3318
3318
|
if (signal.aborted)
|
|
3319
3319
|
return Promise.reject(abortError3(signal));
|
|
3320
|
-
return new Promise((
|
|
3320
|
+
return new Promise((resolve, reject) => {
|
|
3321
3321
|
const onAbort = () => {
|
|
3322
3322
|
signal.removeEventListener("abort", onAbort);
|
|
3323
3323
|
reject(abortError3(signal));
|
|
@@ -3325,7 +3325,7 @@ function waitForDiagnosticsActivity(wait, signal) {
|
|
|
3325
3325
|
signal.addEventListener("abort", onAbort, { once: true });
|
|
3326
3326
|
wait.then(() => {
|
|
3327
3327
|
signal.removeEventListener("abort", onAbort);
|
|
3328
|
-
|
|
3328
|
+
resolve();
|
|
3329
3329
|
}, (error) => {
|
|
3330
3330
|
signal.removeEventListener("abort", onAbort);
|
|
3331
3331
|
reject(error);
|
|
@@ -3389,7 +3389,7 @@ async function stopClientBestEffort(client) {
|
|
|
3389
3389
|
function awaitWithSignal2(promise, signal) {
|
|
3390
3390
|
if (!signal)
|
|
3391
3391
|
return promise;
|
|
3392
|
-
return new Promise((
|
|
3392
|
+
return new Promise((resolve, reject) => {
|
|
3393
3393
|
let settled = false;
|
|
3394
3394
|
const onAbort = () => {
|
|
3395
3395
|
if (settled)
|
|
@@ -3407,7 +3407,7 @@ function awaitWithSignal2(promise, signal) {
|
|
|
3407
3407
|
return;
|
|
3408
3408
|
settled = true;
|
|
3409
3409
|
signal.removeEventListener("abort", onAbort);
|
|
3410
|
-
|
|
3410
|
+
resolve(value);
|
|
3411
3411
|
}, (err) => {
|
|
3412
3412
|
if (settled)
|
|
3413
3413
|
return;
|
|
@@ -3430,7 +3430,7 @@ class LspManager {
|
|
|
3430
3430
|
this.initTimeoutMs = options.initTimeoutMs ?? INIT_TIMEOUT_MS;
|
|
3431
3431
|
this.maxResidentClients = options.maxResidentClients ?? MAX_RESIDENT_CLIENTS;
|
|
3432
3432
|
this.reaperIntervalMs = options.reaperIntervalMs ?? REAPER_INTERVAL_MS;
|
|
3433
|
-
this.clientFactory = options.clientFactory ?? ((root,
|
|
3433
|
+
this.clientFactory = options.clientFactory ?? ((root, server) => new LspClient(root, server));
|
|
3434
3434
|
this.now = options.now ?? (() => Date.now());
|
|
3435
3435
|
this.startReaper();
|
|
3436
3436
|
this.signalDisposer = installProcessSignalCleanup(() => this.stopAll());
|
|
@@ -3523,12 +3523,12 @@ class LspManager {
|
|
|
3523
3523
|
await this.tombstoneStop(key, managed.client);
|
|
3524
3524
|
}
|
|
3525
3525
|
}
|
|
3526
|
-
async getClient(root,
|
|
3526
|
+
async getClient(root, server, signal) {
|
|
3527
3527
|
if (this.disposed) {
|
|
3528
3528
|
throw new Error("LspManager has been disposed");
|
|
3529
3529
|
}
|
|
3530
3530
|
signal?.throwIfAborted();
|
|
3531
|
-
const key = this.getKey(root,
|
|
3531
|
+
const key = this.getKey(root, server.id);
|
|
3532
3532
|
for (;; ) {
|
|
3533
3533
|
const pendingStop = this.pendingStops.get(key);
|
|
3534
3534
|
if (pendingStop === undefined)
|
|
@@ -3570,7 +3570,7 @@ class LspManager {
|
|
|
3570
3570
|
this.clients.delete(key);
|
|
3571
3571
|
}
|
|
3572
3572
|
await this.tombstoneStop(key, managed.client);
|
|
3573
|
-
return this.getClient(root,
|
|
3573
|
+
return this.getClient(root, server, signal);
|
|
3574
3574
|
}
|
|
3575
3575
|
this.markHealthyGeneration(key);
|
|
3576
3576
|
managed.refCount++;
|
|
@@ -3578,8 +3578,8 @@ class LspManager {
|
|
|
3578
3578
|
return managed.client;
|
|
3579
3579
|
}
|
|
3580
3580
|
this.evictForAdmission();
|
|
3581
|
-
this.ensureRespawnAllowed(key, root,
|
|
3582
|
-
const client = this.clientFactory(root,
|
|
3581
|
+
this.ensureRespawnAllowed(key, root, server.id);
|
|
3582
|
+
const client = this.clientFactory(root, server);
|
|
3583
3583
|
const initStartedAt = this.now();
|
|
3584
3584
|
const initPromise = (async () => {
|
|
3585
3585
|
await client.start();
|
|
@@ -3619,7 +3619,7 @@ class LspManager {
|
|
|
3619
3619
|
this.clients.delete(key);
|
|
3620
3620
|
}
|
|
3621
3621
|
await this.tombstoneStop(key, client);
|
|
3622
|
-
return this.getClient(root,
|
|
3622
|
+
return this.getClient(root, server, signal);
|
|
3623
3623
|
}
|
|
3624
3624
|
this.markHealthyGeneration(key);
|
|
3625
3625
|
newManaged.refCount++;
|
|
@@ -3644,19 +3644,19 @@ class LspManager {
|
|
|
3644
3644
|
this.clients.delete(key);
|
|
3645
3645
|
this.tombstoneStop(key, managed.client);
|
|
3646
3646
|
}
|
|
3647
|
-
warmupClient(root,
|
|
3647
|
+
warmupClient(root, server) {
|
|
3648
3648
|
if (this.disposed)
|
|
3649
3649
|
return;
|
|
3650
|
-
const key = this.getKey(root,
|
|
3650
|
+
const key = this.getKey(root, server.id);
|
|
3651
3651
|
if (this.clients.has(key) || this.pendingStops.has(key))
|
|
3652
3652
|
return;
|
|
3653
3653
|
this.evictForAdmission();
|
|
3654
3654
|
try {
|
|
3655
|
-
this.ensureRespawnAllowed(key, root,
|
|
3655
|
+
this.ensureRespawnAllowed(key, root, server.id);
|
|
3656
3656
|
} catch {
|
|
3657
3657
|
return;
|
|
3658
3658
|
}
|
|
3659
|
-
const client = this.clientFactory(root,
|
|
3659
|
+
const client = this.clientFactory(root, server);
|
|
3660
3660
|
const initStartedAt = this.now();
|
|
3661
3661
|
const initPromise = (async () => {
|
|
3662
3662
|
await client.start();
|
|
@@ -3946,11 +3946,11 @@ function getInstallDecisionsPath() {
|
|
|
3946
3946
|
return lspRequestContext().installDecisionsPath;
|
|
3947
3947
|
}
|
|
3948
3948
|
function loadInstallDecisions() {
|
|
3949
|
-
const
|
|
3950
|
-
if (!existsSync8(
|
|
3949
|
+
const path = getInstallDecisionsPath();
|
|
3950
|
+
if (!existsSync8(path))
|
|
3951
3951
|
return {};
|
|
3952
3952
|
try {
|
|
3953
|
-
const parsed = JSON.parse(readFileSync4(
|
|
3953
|
+
const parsed = JSON.parse(readFileSync4(path, "utf8"));
|
|
3954
3954
|
return isInstallDecisions(parsed) ? parsed : {};
|
|
3955
3955
|
} catch {
|
|
3956
3956
|
return {};
|
|
@@ -3968,12 +3968,12 @@ function isInstallDecision(value) {
|
|
|
3968
3968
|
return value === "declined" || value === "allowed";
|
|
3969
3969
|
}
|
|
3970
3970
|
function writeInstallDecisions(decisions) {
|
|
3971
|
-
const
|
|
3972
|
-
mkdirSync3(dirname8(
|
|
3973
|
-
const tmpPath = `${
|
|
3971
|
+
const path = getInstallDecisionsPath();
|
|
3972
|
+
mkdirSync3(dirname8(path), { recursive: true });
|
|
3973
|
+
const tmpPath = `${path}.tmp`;
|
|
3974
3974
|
writeFileSync2(tmpPath, `${JSON.stringify(decisions, null, 2)}
|
|
3975
3975
|
`, "utf8");
|
|
3976
|
-
renameSync2(tmpPath,
|
|
3976
|
+
renameSync2(tmpPath, path);
|
|
3977
3977
|
}
|
|
3978
3978
|
function isInstallDecisions(value) {
|
|
3979
3979
|
return isRecord5(value) && Object.values(value).every(isInstallDecisionRecord);
|
|
@@ -3992,11 +3992,11 @@ function getProjectConfigPaths() {
|
|
|
3992
3992
|
function getUserConfigPath() {
|
|
3993
3993
|
return lspRequestContext().userConfigPath;
|
|
3994
3994
|
}
|
|
3995
|
-
function loadJsonFile(
|
|
3996
|
-
if (!existsSync9(
|
|
3995
|
+
function loadJsonFile(path) {
|
|
3996
|
+
if (!existsSync9(path))
|
|
3997
3997
|
return null;
|
|
3998
3998
|
try {
|
|
3999
|
-
const parsed = JSON.parse(readFileSync5(
|
|
3999
|
+
const parsed = JSON.parse(readFileSync5(path, "utf-8"));
|
|
4000
4000
|
return isConfigJson(parsed) ? parsed : null;
|
|
4001
4001
|
} catch {
|
|
4002
4002
|
return null;
|
|
@@ -4013,8 +4013,8 @@ function loadAllConfigs() {
|
|
|
4013
4013
|
return configs;
|
|
4014
4014
|
}
|
|
4015
4015
|
function loadFirstJsonFile(paths) {
|
|
4016
|
-
for (const
|
|
4017
|
-
const config = loadJsonFile(
|
|
4016
|
+
for (const path of paths) {
|
|
4017
|
+
const config = loadJsonFile(path);
|
|
4018
4018
|
if (config)
|
|
4019
4019
|
return config;
|
|
4020
4020
|
}
|
|
@@ -4040,10 +4040,10 @@ function getMergedServers() {
|
|
|
4040
4040
|
}
|
|
4041
4041
|
if (seen.has(id))
|
|
4042
4042
|
continue;
|
|
4043
|
-
const
|
|
4044
|
-
if (!
|
|
4043
|
+
const server = createServerFromEntry(id, entry, source);
|
|
4044
|
+
if (!server)
|
|
4045
4045
|
continue;
|
|
4046
|
-
servers.push(
|
|
4046
|
+
servers.push(server);
|
|
4047
4047
|
seen.add(id);
|
|
4048
4048
|
}
|
|
4049
4049
|
}
|
|
@@ -4075,7 +4075,7 @@ function createServerFromEntry(id, entry, source) {
|
|
|
4075
4075
|
if (source === "project") {
|
|
4076
4076
|
if (!builtin)
|
|
4077
4077
|
return null;
|
|
4078
|
-
const
|
|
4078
|
+
const server = createServer({
|
|
4079
4079
|
id,
|
|
4080
4080
|
command: builtin.command,
|
|
4081
4081
|
extensions: entry.extensions ?? builtin.extensions,
|
|
@@ -4083,35 +4083,35 @@ function createServerFromEntry(id, entry, source) {
|
|
|
4083
4083
|
source
|
|
4084
4084
|
});
|
|
4085
4085
|
if (entry.initialization !== undefined) {
|
|
4086
|
-
|
|
4086
|
+
server.initialization = entry.initialization;
|
|
4087
4087
|
}
|
|
4088
|
-
return
|
|
4088
|
+
return server;
|
|
4089
4089
|
}
|
|
4090
4090
|
if (entry.command && entry.extensions) {
|
|
4091
|
-
const
|
|
4091
|
+
const server = createServer({
|
|
4092
4092
|
id,
|
|
4093
4093
|
command: entry.command,
|
|
4094
4094
|
extensions: entry.extensions,
|
|
4095
4095
|
priority: entry.priority ?? 0,
|
|
4096
4096
|
source
|
|
4097
4097
|
});
|
|
4098
|
-
applyOptionalServerFields(
|
|
4099
|
-
return
|
|
4098
|
+
applyOptionalServerFields(server, entry);
|
|
4099
|
+
return server;
|
|
4100
4100
|
}
|
|
4101
4101
|
if (!builtin)
|
|
4102
4102
|
return null;
|
|
4103
|
-
const
|
|
4103
|
+
const server = createServer({
|
|
4104
4104
|
id,
|
|
4105
4105
|
command: entry.command ?? builtin.command,
|
|
4106
4106
|
extensions: entry.extensions ?? builtin.extensions,
|
|
4107
4107
|
priority: entry.priority ?? 0,
|
|
4108
4108
|
source
|
|
4109
4109
|
});
|
|
4110
|
-
applyOptionalServerFields(
|
|
4111
|
-
return
|
|
4110
|
+
applyOptionalServerFields(server, entry);
|
|
4111
|
+
return server;
|
|
4112
4112
|
}
|
|
4113
4113
|
function createServer(input) {
|
|
4114
|
-
const
|
|
4114
|
+
const server = {
|
|
4115
4115
|
id: input.id,
|
|
4116
4116
|
command: input.command,
|
|
4117
4117
|
extensions: input.extensions,
|
|
@@ -4119,19 +4119,19 @@ function createServer(input) {
|
|
|
4119
4119
|
source: input.source
|
|
4120
4120
|
};
|
|
4121
4121
|
if (input.env !== undefined) {
|
|
4122
|
-
|
|
4122
|
+
server.env = input.env;
|
|
4123
4123
|
}
|
|
4124
4124
|
if (input.initialization !== undefined) {
|
|
4125
|
-
|
|
4125
|
+
server.initialization = input.initialization;
|
|
4126
4126
|
}
|
|
4127
|
-
return
|
|
4127
|
+
return server;
|
|
4128
4128
|
}
|
|
4129
|
-
function applyOptionalServerFields(
|
|
4129
|
+
function applyOptionalServerFields(server, entry) {
|
|
4130
4130
|
if (entry.env !== undefined) {
|
|
4131
|
-
|
|
4131
|
+
server.env = entry.env;
|
|
4132
4132
|
}
|
|
4133
4133
|
if (entry.initialization !== undefined) {
|
|
4134
|
-
|
|
4134
|
+
server.initialization = entry.initialization;
|
|
4135
4135
|
}
|
|
4136
4136
|
}
|
|
4137
4137
|
function isConfigJson(value) {
|
|
@@ -4216,9 +4216,9 @@ var LOCAL_BIN_RULES = [
|
|
|
4216
4216
|
];
|
|
4217
4217
|
var resolutionCache = new Map;
|
|
4218
4218
|
var probeCount = 0;
|
|
4219
|
-
function probe(
|
|
4219
|
+
function probe(path) {
|
|
4220
4220
|
probeCount += 1;
|
|
4221
|
-
return existsSync10(
|
|
4221
|
+
return existsSync10(path);
|
|
4222
4222
|
}
|
|
4223
4223
|
function executableSuffixes(platform, pathExt) {
|
|
4224
4224
|
if (platform !== "win32")
|
|
@@ -4316,24 +4316,24 @@ function withResolvedCommand(command, binaryPath) {
|
|
|
4316
4316
|
function findServerForExtension(ext) {
|
|
4317
4317
|
const servers = getMergedServers();
|
|
4318
4318
|
const workingDirectory = contextCwd();
|
|
4319
|
-
for (const
|
|
4320
|
-
if (!
|
|
4319
|
+
for (const server of servers) {
|
|
4320
|
+
if (!server.extensions.includes(ext))
|
|
4321
4321
|
continue;
|
|
4322
|
-
const binaryPath = resolveServerBinary(
|
|
4322
|
+
const binaryPath = resolveServerBinary(server.command, workingDirectory);
|
|
4323
4323
|
if (binaryPath !== null) {
|
|
4324
4324
|
const resolvedServer = {
|
|
4325
|
-
id:
|
|
4326
|
-
command: withResolvedCommand(
|
|
4327
|
-
extensions:
|
|
4328
|
-
priority:
|
|
4325
|
+
id: server.id,
|
|
4326
|
+
command: withResolvedCommand(server.command, binaryPath),
|
|
4327
|
+
extensions: server.extensions,
|
|
4328
|
+
priority: server.priority
|
|
4329
4329
|
};
|
|
4330
|
-
if (
|
|
4330
|
+
if (server.env !== undefined) {
|
|
4331
4331
|
return {
|
|
4332
4332
|
status: "found",
|
|
4333
4333
|
server: {
|
|
4334
4334
|
...resolvedServer,
|
|
4335
|
-
env:
|
|
4336
|
-
...
|
|
4335
|
+
env: server.env,
|
|
4336
|
+
...server.initialization === undefined ? {} : { initialization: server.initialization }
|
|
4337
4337
|
}
|
|
4338
4338
|
};
|
|
4339
4339
|
}
|
|
@@ -4341,20 +4341,20 @@ function findServerForExtension(ext) {
|
|
|
4341
4341
|
status: "found",
|
|
4342
4342
|
server: {
|
|
4343
4343
|
...resolvedServer,
|
|
4344
|
-
...
|
|
4344
|
+
...server.initialization === undefined ? {} : { initialization: server.initialization }
|
|
4345
4345
|
}
|
|
4346
4346
|
};
|
|
4347
4347
|
}
|
|
4348
4348
|
}
|
|
4349
|
-
for (const
|
|
4350
|
-
if (
|
|
4351
|
-
const installHint = LSP_INSTALL_HINTS[
|
|
4349
|
+
for (const server of servers) {
|
|
4350
|
+
if (server.extensions.includes(ext)) {
|
|
4351
|
+
const installHint = LSP_INSTALL_HINTS[server.id] ?? `Install '${server.command[0]}' and ensure it's in your PATH`;
|
|
4352
4352
|
return {
|
|
4353
4353
|
status: "not_installed",
|
|
4354
4354
|
server: {
|
|
4355
|
-
id:
|
|
4356
|
-
command:
|
|
4357
|
-
extensions:
|
|
4355
|
+
id: server.id,
|
|
4356
|
+
command: server.command,
|
|
4357
|
+
extensions: server.extensions
|
|
4358
4358
|
},
|
|
4359
4359
|
installHint
|
|
4360
4360
|
};
|
|
@@ -4373,18 +4373,18 @@ function getAllServers() {
|
|
|
4373
4373
|
const workingDirectory = contextCwd();
|
|
4374
4374
|
const result = [];
|
|
4375
4375
|
const seen = new Set;
|
|
4376
|
-
for (const
|
|
4377
|
-
if (seen.has(
|
|
4376
|
+
for (const server of servers) {
|
|
4377
|
+
if (seen.has(server.id))
|
|
4378
4378
|
continue;
|
|
4379
4379
|
result.push({
|
|
4380
|
-
id:
|
|
4381
|
-
installed: isServerInstalled(
|
|
4382
|
-
extensions:
|
|
4380
|
+
id: server.id,
|
|
4381
|
+
installed: isServerInstalled(server.command, workingDirectory),
|
|
4382
|
+
extensions: server.extensions,
|
|
4383
4383
|
disabled: false,
|
|
4384
|
-
source:
|
|
4385
|
-
priority:
|
|
4384
|
+
source: server.source,
|
|
4385
|
+
priority: server.priority
|
|
4386
4386
|
});
|
|
4387
|
-
seen.add(
|
|
4387
|
+
seen.add(server.id);
|
|
4388
4388
|
}
|
|
4389
4389
|
for (const id of disabled) {
|
|
4390
4390
|
if (seen.has(id))
|
|
@@ -4457,8 +4457,8 @@ function resolvePathInsideContext(filePath) {
|
|
|
4457
4457
|
}
|
|
4458
4458
|
return canonical;
|
|
4459
4459
|
}
|
|
4460
|
-
function rebaseThroughCanonicalAncestor(
|
|
4461
|
-
let current =
|
|
4460
|
+
function rebaseThroughCanonicalAncestor(path, cwd) {
|
|
4461
|
+
let current = path;
|
|
4462
4462
|
const suffix = [];
|
|
4463
4463
|
while (true) {
|
|
4464
4464
|
if (existsSync11(current)) {
|
|
@@ -4530,20 +4530,20 @@ function formatInstallOptions(serverId, installHint) {
|
|
|
4530
4530
|
];
|
|
4531
4531
|
}
|
|
4532
4532
|
function formatNotInstalled(result) {
|
|
4533
|
-
const { server
|
|
4534
|
-
const extensions =
|
|
4535
|
-
const decision = loadInstallDecision(
|
|
4533
|
+
const { server, installHint } = result;
|
|
4534
|
+
const extensions = server.extensions.join(", ");
|
|
4535
|
+
const decision = loadInstallDecision(server.id)?.decision;
|
|
4536
4536
|
const context = lspRequestContext();
|
|
4537
4537
|
if (decision === "declined") {
|
|
4538
|
-
return `LSP server '${
|
|
4538
|
+
return `LSP server '${server.id}' (${extensions}) is NOT INSTALLED; user previously declined installation — proceed without LSP.`;
|
|
4539
4539
|
}
|
|
4540
4540
|
const header = [
|
|
4541
|
-
`LSP server '${
|
|
4541
|
+
`LSP server '${server.id}' for ${extensions} is NOT INSTALLED.`,
|
|
4542
4542
|
"",
|
|
4543
|
-
`Command not found: ${
|
|
4543
|
+
`Command not found: ${server.command[0]}`,
|
|
4544
4544
|
""
|
|
4545
4545
|
];
|
|
4546
|
-
const installOptions = formatInstallOptions(
|
|
4546
|
+
const installOptions = formatInstallOptions(server.id, installHint);
|
|
4547
4547
|
if (decision === "allowed") {
|
|
4548
4548
|
return [
|
|
4549
4549
|
...header,
|
|
@@ -4569,7 +4569,7 @@ function formatNotInstalled(result) {
|
|
|
4569
4569
|
"ACTION REQUIRED — ASK THE USER whether to install this LSP server.",
|
|
4570
4570
|
"- If the user agrees: run the install command above, then retry this tool.",
|
|
4571
4571
|
"- If the user declines, OR has NOT explicitly asked for LSP installation:",
|
|
4572
|
-
` call lsp_install_decision { server_id: "${
|
|
4572
|
+
` call lsp_install_decision { server_id: "${server.id}", decision: "declined" },`,
|
|
4573
4573
|
` which writes to ${context.installDecisionsPath},`,
|
|
4574
4574
|
" then ignore this message and proceed WITHOUT LSP."
|
|
4575
4575
|
].join(`
|
|
@@ -4593,26 +4593,26 @@ async function withLspClient(filePath, fn, toolName, options = {}) {
|
|
|
4593
4593
|
if (result.status !== "found") {
|
|
4594
4594
|
throw new LspServerLookupError(formatServerLookupError(result), result);
|
|
4595
4595
|
}
|
|
4596
|
-
const
|
|
4596
|
+
const server = result.server;
|
|
4597
4597
|
const root = findWorkspaceRoot(absPath);
|
|
4598
4598
|
const manager = options.manager ?? getLspManager();
|
|
4599
4599
|
const acquireAndCall = async (allowRetry) => {
|
|
4600
|
-
const client = await manager.getClient(root,
|
|
4600
|
+
const client = await manager.getClient(root, server, options.signal);
|
|
4601
4601
|
try {
|
|
4602
4602
|
return await fn(client, root, absPath);
|
|
4603
4603
|
} catch (err) {
|
|
4604
4604
|
if (allowRetry && READ_ONLY_TOOLS.has(toolName) && isLspDeadConnectionError(err)) {
|
|
4605
|
-
manager.invalidateClient(root,
|
|
4605
|
+
manager.invalidateClient(root, server.id, client);
|
|
4606
4606
|
return acquireAndCall(false);
|
|
4607
4607
|
}
|
|
4608
4608
|
if (err instanceof LspRequestTimeoutError) {
|
|
4609
|
-
if (manager.isServerInitializing(root,
|
|
4609
|
+
if (manager.isServerInitializing(root, server.id)) {
|
|
4610
4610
|
throw new LspServerInitializingError(err);
|
|
4611
4611
|
}
|
|
4612
4612
|
}
|
|
4613
4613
|
throw err;
|
|
4614
4614
|
} finally {
|
|
4615
|
-
manager.releaseClient(root,
|
|
4615
|
+
manager.releaseClient(root, server.id);
|
|
4616
4616
|
}
|
|
4617
4617
|
};
|
|
4618
4618
|
return acquireAndCall(true);
|
|
@@ -4628,10 +4628,10 @@ function uriToPath(uri) {
|
|
|
4628
4628
|
}
|
|
4629
4629
|
function formatLocation(loc) {
|
|
4630
4630
|
if ("targetUri" in loc) {
|
|
4631
|
-
const
|
|
4632
|
-
const
|
|
4633
|
-
const
|
|
4634
|
-
return `${
|
|
4631
|
+
const uri = uriToPath(loc.targetUri);
|
|
4632
|
+
const line = loc.targetRange.start.line + 1;
|
|
4633
|
+
const char = loc.targetRange.start.character;
|
|
4634
|
+
return `${uri}:${line}:${char}`;
|
|
4635
4635
|
}
|
|
4636
4636
|
const uri = uriToPath(loc.uri);
|
|
4637
4637
|
const line = loc.range.start.line + 1;
|
|
@@ -4774,7 +4774,7 @@ async function aggregateDiagnosticsForDirectory(directory, extension, severity,
|
|
|
4774
4774
|
if (serverResult.status !== "found") {
|
|
4775
4775
|
throw new LspServerLookupError(formatServerLookupError(serverResult));
|
|
4776
4776
|
}
|
|
4777
|
-
const
|
|
4777
|
+
const server = serverResult.server;
|
|
4778
4778
|
const allFiles = (options.listFiles ?? collectFilesWithExtension)(absDir, extension, maxFiles + 1);
|
|
4779
4779
|
const wasCapped = allFiles.length > maxFiles;
|
|
4780
4780
|
const filesToProcess = allFiles.slice(0, maxFiles);
|
|
@@ -4794,7 +4794,7 @@ async function aggregateDiagnosticsForDirectory(directory, extension, severity,
|
|
|
4794
4794
|
const fileErrors = [];
|
|
4795
4795
|
const maxConcurrency = Math.max(1, options.maxConcurrency ?? DIRECTORY_DIAGNOSTICS_MAX_CONCURRENCY);
|
|
4796
4796
|
options.signal?.throwIfAborted();
|
|
4797
|
-
const client = await manager.getClient(root,
|
|
4797
|
+
const client = await manager.getClient(root, server, options.signal);
|
|
4798
4798
|
try {
|
|
4799
4799
|
let nextIndex = 0;
|
|
4800
4800
|
const workers = Array.from({ length: Math.min(maxConcurrency, filesToProcess.length) }, async () => {
|
|
@@ -4822,7 +4822,7 @@ async function aggregateDiagnosticsForDirectory(directory, extension, severity,
|
|
|
4822
4822
|
});
|
|
4823
4823
|
await Promise.all(workers);
|
|
4824
4824
|
} finally {
|
|
4825
|
-
manager.releaseClient(root,
|
|
4825
|
+
manager.releaseClient(root, server.id);
|
|
4826
4826
|
}
|
|
4827
4827
|
const displayDiagnostics = allDiagnostics.slice(0, DEFAULT_MAX_DIAGNOSTICS);
|
|
4828
4828
|
const wasDiagCapped = allDiagnostics.length > DEFAULT_MAX_DIAGNOSTICS;
|
|
@@ -5017,8 +5017,8 @@ function severityFilter(params) {
|
|
|
5017
5017
|
function clientOptions(signal) {
|
|
5018
5018
|
return signal === undefined ? {} : { signal };
|
|
5019
5019
|
}
|
|
5020
|
-
function text(
|
|
5021
|
-
return { content: [{ type: "text", text
|
|
5020
|
+
function text(text, details, isError = false) {
|
|
5021
|
+
return { content: [{ type: "text", text }], details, isError };
|
|
5022
5022
|
}
|
|
5023
5023
|
function asDiagnosticArray(result) {
|
|
5024
5024
|
if (!result)
|
|
@@ -5036,7 +5036,7 @@ async function executeLspDiagnostics(params, signal) {
|
|
|
5036
5036
|
const extension = inferExtensionFromDirectory(absPath);
|
|
5037
5037
|
if (!extension) {
|
|
5038
5038
|
const message = `No supported source files found in directory: ${absPath}`;
|
|
5039
|
-
const
|
|
5039
|
+
const details = {
|
|
5040
5040
|
filePath,
|
|
5041
5041
|
severity,
|
|
5042
5042
|
mode: "directory",
|
|
@@ -5046,24 +5046,24 @@ async function executeLspDiagnostics(params, signal) {
|
|
|
5046
5046
|
error: message,
|
|
5047
5047
|
errorKind: "no_files"
|
|
5048
5048
|
};
|
|
5049
|
-
return text(message,
|
|
5049
|
+
return text(message, details);
|
|
5050
5050
|
}
|
|
5051
|
-
const
|
|
5052
|
-
const
|
|
5051
|
+
const output = await aggregateDiagnosticsForDirectory(absPath, extension, severity, undefined, signal === undefined ? {} : { signal });
|
|
5052
|
+
const details = {
|
|
5053
5053
|
filePath,
|
|
5054
5054
|
severity,
|
|
5055
5055
|
mode: "directory",
|
|
5056
5056
|
diagnostics: [],
|
|
5057
|
-
totalDiagnostics:
|
|
5057
|
+
totalDiagnostics: output.totalDiagnostics,
|
|
5058
5058
|
truncated: false,
|
|
5059
|
-
fileFailures: [...
|
|
5059
|
+
fileFailures: [...output.fileFailures]
|
|
5060
5060
|
};
|
|
5061
|
-
return text(
|
|
5061
|
+
return text(output.output, details);
|
|
5062
5062
|
}
|
|
5063
5063
|
const result = await withLspClient(filePath, async (client, _workspaceRoot, resolvedFilePath) => client.diagnostics(resolvedFilePath, signal), "diagnostics", clientOptions(signal));
|
|
5064
5064
|
if (result.transientError) {
|
|
5065
5065
|
const message = result.transientError.message;
|
|
5066
|
-
const
|
|
5066
|
+
const details = {
|
|
5067
5067
|
filePath,
|
|
5068
5068
|
severity,
|
|
5069
5069
|
mode: "file",
|
|
@@ -5073,7 +5073,7 @@ async function executeLspDiagnostics(params, signal) {
|
|
|
5073
5073
|
error: message,
|
|
5074
5074
|
errorKind: result.transientError.kind
|
|
5075
5075
|
};
|
|
5076
|
-
return text(message,
|
|
5076
|
+
return text(message, details, true);
|
|
5077
5077
|
}
|
|
5078
5078
|
const diagnostics = filterDiagnosticsBySeverity(asDiagnosticArray(result), severity);
|
|
5079
5079
|
const total = diagnostics.length;
|
|
@@ -5198,7 +5198,7 @@ async function executeLspInstallDecision(params) {
|
|
|
5198
5198
|
if (!isInstallDecision(decision)) {
|
|
5199
5199
|
return text(`Invalid decision '${String(decision)}'. Expected "declined" or "allowed".`, { serverId, errorKind: "invalid_decision" }, true);
|
|
5200
5200
|
}
|
|
5201
|
-
const serverIds = [...new Set(getMergedServers().map((
|
|
5201
|
+
const serverIds = [...new Set(getMergedServers().map((server) => server.id))];
|
|
5202
5202
|
if (!serverIds.includes(serverId)) {
|
|
5203
5203
|
const preview = serverIds.slice(0, 20).join(", ");
|
|
5204
5204
|
return text(`Unknown LSP server '${serverId}'. Known servers: ${preview}${serverIds.length > 20 ? "..." : ""}`, { serverId, errorKind: "unknown_server" }, true);
|
|
@@ -5330,10 +5330,10 @@ function objectSchema(properties, required = []) {
|
|
|
5330
5330
|
async function executeLspStatus() {
|
|
5331
5331
|
const servers = getAllServers();
|
|
5332
5332
|
const snapshots = getLspManager().getSnapshot();
|
|
5333
|
-
const installed = servers.filter((
|
|
5334
|
-
const configuredLines = servers.map((
|
|
5335
|
-
const state =
|
|
5336
|
-
return `- ${
|
|
5333
|
+
const installed = servers.filter((server) => server.installed && !server.disabled);
|
|
5334
|
+
const configuredLines = servers.map((server) => {
|
|
5335
|
+
const state = server.disabled ? "disabled" : server.installed ? "installed" : "missing";
|
|
5336
|
+
return `- ${server.id}: ${state}; source=${server.source}; extensions=${server.extensions.join(", ")}`;
|
|
5337
5337
|
});
|
|
5338
5338
|
const activeLines = snapshots.map((snapshot) => {
|
|
5339
5339
|
const state = snapshot.alive ? snapshot.isInitializing ? "initializing" : "alive" : "dead";
|
|
@@ -5374,8 +5374,8 @@ async function executeLspSymbols(params, signal) {
|
|
|
5374
5374
|
errorKind: "missing_query"
|
|
5375
5375
|
});
|
|
5376
5376
|
}
|
|
5377
|
-
const
|
|
5378
|
-
return formatSymbolsResult(filePath, scope,
|
|
5377
|
+
const symbols = await withLspClient(filePath, async (client) => client.workspaceSymbols(query, signal), "workspaceSymbols", clientOptions(signal));
|
|
5378
|
+
return formatSymbolsResult(filePath, scope, symbols, limit, query);
|
|
5379
5379
|
}
|
|
5380
5380
|
const symbols = await withLspClient(filePath, async (client, _workspaceRoot, resolvedFilePath) => client.documentSymbols(resolvedFilePath, signal), "documentSymbols", clientOptions(signal));
|
|
5381
5381
|
return formatSymbolsResult(filePath, scope, symbols, limit);
|
|
@@ -5587,7 +5587,7 @@ function withContext(args, context) {
|
|
|
5587
5587
|
function ensureDaemonAvailable(paths, ensure, signal) {
|
|
5588
5588
|
if (!signal)
|
|
5589
5589
|
return ensure(paths);
|
|
5590
|
-
return new Promise((
|
|
5590
|
+
return new Promise((resolve, reject) => {
|
|
5591
5591
|
let settled = false;
|
|
5592
5592
|
const finish = (run) => {
|
|
5593
5593
|
if (settled)
|
|
@@ -5602,11 +5602,11 @@ function ensureDaemonAvailable(paths, ensure, signal) {
|
|
|
5602
5602
|
return;
|
|
5603
5603
|
}
|
|
5604
5604
|
signal.addEventListener("abort", onAbort, { once: true });
|
|
5605
|
-
Promise.resolve().then(() => ensure(paths, signal)).then(() => finish(() =>
|
|
5605
|
+
Promise.resolve().then(() => ensure(paths, signal)).then(() => finish(() => resolve()), (error) => finish(() => reject(signal.aborted ? new DaemonRequestCancelledError(false) : error)));
|
|
5606
5606
|
});
|
|
5607
5607
|
}
|
|
5608
5608
|
function sendToolCall(paths, token, name, args, options) {
|
|
5609
|
-
return new Promise((
|
|
5609
|
+
return new Promise((resolve, reject) => {
|
|
5610
5610
|
const socket = connect(paths.socket);
|
|
5611
5611
|
const requestId = allocateProxyRequestId();
|
|
5612
5612
|
let settled = false;
|
|
@@ -5659,7 +5659,7 @@ function sendToolCall(paths, token, name, args, options) {
|
|
|
5659
5659
|
}
|
|
5660
5660
|
const result = toToolResult(message, requestId);
|
|
5661
5661
|
if (result)
|
|
5662
|
-
finish(() =>
|
|
5662
|
+
finish(() => resolve(result));
|
|
5663
5663
|
else
|
|
5664
5664
|
finish(() => reject(new DaemonRequestError("invalid daemon response", requestWritten)));
|
|
5665
5665
|
});
|
|
@@ -5834,8 +5834,8 @@ function normalizeDiagnosticsOutcome(outcome) {
|
|
|
5834
5834
|
return normalizeDiagnosticsText(outcome);
|
|
5835
5835
|
return outcome;
|
|
5836
5836
|
}
|
|
5837
|
-
function normalizeDiagnosticsText(
|
|
5838
|
-
return
|
|
5837
|
+
function normalizeDiagnosticsText(text) {
|
|
5838
|
+
return text.trim();
|
|
5839
5839
|
}
|
|
5840
5840
|
function formatDiagnosticsError(error) {
|
|
5841
5841
|
const message = normalizeDiagnosticsText(error.message);
|
|
@@ -5880,18 +5880,18 @@ function parseLspRequestContext2(value) {
|
|
|
5880
5880
|
const installDecisionsPath = stringField2(value, "installDecisionsPath");
|
|
5881
5881
|
const capabilities = capabilitiesField2(value["capabilities"]);
|
|
5882
5882
|
const canonical = canonicalCwd2(cwd);
|
|
5883
|
-
for (const
|
|
5884
|
-
requireAbsolutePath2(
|
|
5885
|
-
const projectPath = canonicalizeExistingOrNearestAncestor2(
|
|
5883
|
+
for (const path of projectConfigPaths) {
|
|
5884
|
+
requireAbsolutePath2(path, "projectConfigPaths");
|
|
5885
|
+
const projectPath = canonicalizeExistingOrNearestAncestor2(path);
|
|
5886
5886
|
if (!isPathInside2(canonical, projectPath)) {
|
|
5887
|
-
throw new LspRequestContextParseError2("project_config_outside_cwd", `Project LSP config path must be inside cwd: ${
|
|
5887
|
+
throw new LspRequestContextParseError2("project_config_outside_cwd", `Project LSP config path must be inside cwd: ${path}`);
|
|
5888
5888
|
}
|
|
5889
5889
|
}
|
|
5890
5890
|
requireAbsolutePath2(userConfigPath, "userConfigPath");
|
|
5891
5891
|
requireAbsolutePath2(installDecisionsPath, "installDecisionsPath");
|
|
5892
5892
|
return {
|
|
5893
5893
|
cwd: canonical,
|
|
5894
|
-
projectConfigPaths: projectConfigPaths.map((
|
|
5894
|
+
projectConfigPaths: projectConfigPaths.map((path) => canonicalizeExistingOrNearestAncestor2(path)),
|
|
5895
5895
|
userConfigPath,
|
|
5896
5896
|
installDecisionsPath,
|
|
5897
5897
|
capabilities
|
|
@@ -5904,8 +5904,8 @@ function canonicalCwd2(cwd) {
|
|
|
5904
5904
|
}
|
|
5905
5905
|
return realpathSync6(resolved);
|
|
5906
5906
|
}
|
|
5907
|
-
function canonicalizeExistingOrNearestAncestor2(
|
|
5908
|
-
let current = resolve10(
|
|
5907
|
+
function canonicalizeExistingOrNearestAncestor2(path) {
|
|
5908
|
+
let current = resolve10(path);
|
|
5909
5909
|
const suffix = [];
|
|
5910
5910
|
while (true) {
|
|
5911
5911
|
try {
|
|
@@ -5947,9 +5947,9 @@ function stringArrayField2(value, field) {
|
|
|
5947
5947
|
}
|
|
5948
5948
|
return fieldValue;
|
|
5949
5949
|
}
|
|
5950
|
-
function requireAbsolutePath2(
|
|
5951
|
-
if (!isAbsolute7(
|
|
5952
|
-
throw new LspRequestContextParseError2("relative_path", `LSP request context.${field} must be absolute: ${
|
|
5950
|
+
function requireAbsolutePath2(path, field) {
|
|
5951
|
+
if (!isAbsolute7(path)) {
|
|
5952
|
+
throw new LspRequestContextParseError2("relative_path", `LSP request context.${field} must be absolute: ${path}`);
|
|
5953
5953
|
}
|
|
5954
5954
|
}
|
|
5955
5955
|
function isPathInside2(parent, child) {
|
|
@@ -5978,9 +5978,9 @@ function errorCode2(error) {
|
|
|
5978
5978
|
}
|
|
5979
5979
|
|
|
5980
5980
|
// src/daemon-cli-path.ts
|
|
5981
|
-
import { existsSync as
|
|
5981
|
+
import { existsSync as existsSync14, readFileSync as readFileSync7 } from "node:fs";
|
|
5982
5982
|
import { createRequire as createRequire2 } from "node:module";
|
|
5983
|
-
import { dirname as dirname11, join as
|
|
5983
|
+
import { dirname as dirname11, join as join9 } from "node:path";
|
|
5984
5984
|
import { fileURLToPath as fileURLToPath4 } from "node:url";
|
|
5985
5985
|
var requireFromHere2 = createRequire2(import.meta.url);
|
|
5986
5986
|
var PACKAGE_LSP_DAEMON_CLI = "@code-yeongyu/lsp-daemon/cli";
|
|
@@ -6002,7 +6002,7 @@ function resolveLspDaemonCli() {
|
|
|
6002
6002
|
if (packageCli !== null)
|
|
6003
6003
|
return resolveConfiguredLspDaemonCli(packageCli);
|
|
6004
6004
|
const bundledCli = fileURLToPath4(new URL("../../lsp-daemon/dist/cli.js", import.meta.url));
|
|
6005
|
-
if (
|
|
6005
|
+
if (existsSync14(bundledCli))
|
|
6006
6006
|
return resolveConfiguredLspDaemonCli(bundledCli);
|
|
6007
6007
|
return resolveConfiguredLspDaemonCli(bundledCli);
|
|
6008
6008
|
}
|
|
@@ -6027,8 +6027,8 @@ function resolveConfiguredLspDaemonCli(cliPath) {
|
|
|
6027
6027
|
}
|
|
6028
6028
|
function readDaemonPackageVersion(cliPath) {
|
|
6029
6029
|
try {
|
|
6030
|
-
const parsed = JSON.parse(readFileSync7(
|
|
6031
|
-
if (
|
|
6030
|
+
const parsed = JSON.parse(readFileSync7(join9(dirname11(cliPath), "package.json"), "utf8"));
|
|
6031
|
+
if (isRecord8(parsed) && typeof parsed["version"] === "string" && parsed["version"].length > 0) {
|
|
6032
6032
|
return parsed["version"];
|
|
6033
6033
|
}
|
|
6034
6034
|
} catch (error) {
|
|
@@ -6037,14 +6037,14 @@ function readDaemonPackageVersion(cliPath) {
|
|
|
6037
6037
|
}
|
|
6038
6038
|
return null;
|
|
6039
6039
|
}
|
|
6040
|
-
function
|
|
6040
|
+
function isRecord8(value) {
|
|
6041
6041
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
6042
6042
|
}
|
|
6043
6043
|
|
|
6044
6044
|
// src/lsp-session-state.ts
|
|
6045
|
-
import { mkdirSync as mkdirSync4, readFileSync as
|
|
6045
|
+
import { mkdirSync as mkdirSync4, readFileSync as readFileSync8, writeFileSync as writeFileSync4 } from "node:fs";
|
|
6046
6046
|
import { homedir } from "node:os";
|
|
6047
|
-
import { dirname as
|
|
6047
|
+
import { dirname as dirname12, join as join10 } from "node:path";
|
|
6048
6048
|
function sessionIdFrom(input) {
|
|
6049
6049
|
return typeof input.session_id === "string" && input.session_id.length > 0 ? input.session_id : undefined;
|
|
6050
6050
|
}
|
|
@@ -6070,24 +6070,24 @@ function isLspDaemonUnreachableDiagnostics(diagnostics) {
|
|
|
6070
6070
|
return diagnostics.includes("LSP daemon unreachable");
|
|
6071
6071
|
}
|
|
6072
6072
|
function sessionStatePath(sessionId) {
|
|
6073
|
-
const root = process.env["PLUGIN_DATA"] ??
|
|
6074
|
-
return
|
|
6073
|
+
const root = process.env["PLUGIN_DATA"] ?? join10(homedir(), ".codex", "codex-lsp");
|
|
6074
|
+
return join10(root, "sessions", `${safePathSegment(sessionId)}.json`);
|
|
6075
6075
|
}
|
|
6076
|
-
function readSessionState(
|
|
6076
|
+
function readSessionState(path) {
|
|
6077
6077
|
try {
|
|
6078
|
-
const parsed = JSON.parse(
|
|
6079
|
-
if (
|
|
6078
|
+
const parsed = JSON.parse(readFileSync8(path, "utf8"));
|
|
6079
|
+
if (isRecord9(parsed) && isLspSessionState(parsed))
|
|
6080
6080
|
return normalizeSessionState(parsed);
|
|
6081
6081
|
return emptyState();
|
|
6082
6082
|
} catch (error) {
|
|
6083
|
-
if (error instanceof SyntaxError ||
|
|
6083
|
+
if (error instanceof SyntaxError || isRecord9(error) && error["code"] === "ENOENT")
|
|
6084
6084
|
return emptyState();
|
|
6085
6085
|
throw error;
|
|
6086
6086
|
}
|
|
6087
6087
|
}
|
|
6088
|
-
function writeSessionState(
|
|
6089
|
-
mkdirSync4(
|
|
6090
|
-
writeFileSync4(
|
|
6088
|
+
function writeSessionState(path, state) {
|
|
6089
|
+
mkdirSync4(dirname12(path), { recursive: true });
|
|
6090
|
+
writeFileSync4(path, `${JSON.stringify(state)}
|
|
6091
6091
|
`);
|
|
6092
6092
|
}
|
|
6093
6093
|
function emptyState() {
|
|
@@ -6106,7 +6106,7 @@ function normalizeSessionState(value) {
|
|
|
6106
6106
|
notConfiguredExtensions: Array.isArray(notConfiguredExtensions) ? notConfiguredExtensions.filter((item) => typeof item === "string").sort() : []
|
|
6107
6107
|
};
|
|
6108
6108
|
}
|
|
6109
|
-
function
|
|
6109
|
+
function isRecord9(value) {
|
|
6110
6110
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
6111
6111
|
}
|
|
6112
6112
|
|
|
@@ -6117,7 +6117,7 @@ function extractMutatedFilePaths(input) {
|
|
|
6117
6117
|
return [];
|
|
6118
6118
|
if (isFailedToolResponse(input.tool_response))
|
|
6119
6119
|
return [];
|
|
6120
|
-
const toolInput =
|
|
6120
|
+
const toolInput = isRecord10(input.tool_input) ? input.tool_input : {};
|
|
6121
6121
|
const paths = new Set;
|
|
6122
6122
|
addStringValue(paths, toolInput["path"]);
|
|
6123
6123
|
addStringValue(paths, toolInput["filePath"]);
|
|
@@ -6136,7 +6136,7 @@ function isMutationTool(value) {
|
|
|
6136
6136
|
return MUTATION_TOOL_NAMES.has(value.toLowerCase());
|
|
6137
6137
|
}
|
|
6138
6138
|
function isFailedToolResponse(value) {
|
|
6139
|
-
if (!
|
|
6139
|
+
if (!isRecord10(value))
|
|
6140
6140
|
return false;
|
|
6141
6141
|
return value["isError"] === true || value["is_error"] === true || value["error"] === true || value["status"] === "error";
|
|
6142
6142
|
}
|
|
@@ -6162,9 +6162,9 @@ function addPatchInput(paths, value) {
|
|
|
6162
6162
|
return;
|
|
6163
6163
|
for (const line of value.split(`
|
|
6164
6164
|
`)) {
|
|
6165
|
-
const
|
|
6166
|
-
if (
|
|
6167
|
-
paths.add(
|
|
6165
|
+
const path = extractPatchHeaderPath(line);
|
|
6166
|
+
if (path !== undefined)
|
|
6167
|
+
paths.add(path);
|
|
6168
6168
|
}
|
|
6169
6169
|
}
|
|
6170
6170
|
function extractPatchHeaderPath(line) {
|
|
@@ -6179,7 +6179,7 @@ function addPatchFiles(paths, value) {
|
|
|
6179
6179
|
if (!Array.isArray(value))
|
|
6180
6180
|
return;
|
|
6181
6181
|
for (const item of value) {
|
|
6182
|
-
if (!
|
|
6182
|
+
if (!isRecord10(item))
|
|
6183
6183
|
continue;
|
|
6184
6184
|
addStringValue(paths, item["path"]);
|
|
6185
6185
|
addStringValue(paths, item["filePath"]);
|
|
@@ -6188,7 +6188,7 @@ function addPatchFiles(paths, value) {
|
|
|
6188
6188
|
addStringValue(paths, item["move_path"]);
|
|
6189
6189
|
}
|
|
6190
6190
|
}
|
|
6191
|
-
function
|
|
6191
|
+
function isRecord10(value) {
|
|
6192
6192
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
6193
6193
|
}
|
|
6194
6194
|
|
|
@@ -6219,10 +6219,10 @@ function postEditOutcomeFromDaemonResult(result) {
|
|
|
6219
6219
|
`);
|
|
6220
6220
|
}
|
|
6221
6221
|
function notConfiguredAvailability(details) {
|
|
6222
|
-
if (!
|
|
6222
|
+
if (!isRecord11(details))
|
|
6223
6223
|
return;
|
|
6224
6224
|
const availability = details["availability"];
|
|
6225
|
-
if (!
|
|
6225
|
+
if (!isRecord11(availability))
|
|
6226
6226
|
return;
|
|
6227
6227
|
if (availability["kind"] !== "not_configured")
|
|
6228
6228
|
return;
|
|
@@ -6230,13 +6230,13 @@ function notConfiguredAvailability(details) {
|
|
|
6230
6230
|
return typeof extension === "string" && extension.length > 0 ? { extension } : undefined;
|
|
6231
6231
|
}
|
|
6232
6232
|
function codexLspRequestContext(env = process.env, cwd = process.cwd()) {
|
|
6233
|
-
const
|
|
6234
|
-
const codexHome =
|
|
6233
|
+
const canonicalCwd = realpathSync7(resolve11(cwd));
|
|
6234
|
+
const codexHome = resolve11(env["CODEX_HOME"]?.trim() || join11(homedir3(), ".codex"));
|
|
6235
6235
|
return parseLspRequestContext2({
|
|
6236
|
-
cwd:
|
|
6237
|
-
projectConfigPaths: [
|
|
6238
|
-
userConfigPath:
|
|
6239
|
-
installDecisionsPath:
|
|
6236
|
+
cwd: canonicalCwd,
|
|
6237
|
+
projectConfigPaths: [join11(canonicalCwd, ".codex", "lsp-client.json")],
|
|
6238
|
+
userConfigPath: join11(codexHome, "lsp-client.json"),
|
|
6239
|
+
installDecisionsPath: join11(codexHome, "lsp-install-decisions.json"),
|
|
6240
6240
|
capabilities: { installDecisionTool: true }
|
|
6241
6241
|
});
|
|
6242
6242
|
}
|
|
@@ -6330,29 +6330,29 @@ function isContextPressureTranscript(transcriptPath) {
|
|
|
6330
6330
|
if (typeof transcriptPath !== "string")
|
|
6331
6331
|
return false;
|
|
6332
6332
|
try {
|
|
6333
|
-
return hasContextPressureMarker(
|
|
6333
|
+
return hasContextPressureMarker(readFileSync9(transcriptPath, "utf8"));
|
|
6334
6334
|
} catch (error) {
|
|
6335
6335
|
if (error instanceof Error)
|
|
6336
6336
|
return false;
|
|
6337
6337
|
throw error;
|
|
6338
6338
|
}
|
|
6339
6339
|
}
|
|
6340
|
-
function hasContextPressureMarker(
|
|
6341
|
-
const normalizedText =
|
|
6340
|
+
function hasContextPressureMarker(text) {
|
|
6341
|
+
const normalizedText = text.toLowerCase();
|
|
6342
6342
|
return CONTEXT_PRESSURE_MARKERS.some((marker) => normalizedText.includes(marker));
|
|
6343
6343
|
}
|
|
6344
|
-
function limitHookText(
|
|
6345
|
-
if (
|
|
6346
|
-
return
|
|
6344
|
+
function limitHookText(text, maxChars) {
|
|
6345
|
+
if (text.length <= maxChars)
|
|
6346
|
+
return text;
|
|
6347
6347
|
const marker = `
|
|
6348
6348
|
|
|
6349
6349
|
[Truncated hook output to ${maxChars} chars to avoid Codex context overflow.]`;
|
|
6350
6350
|
if (marker.length >= maxChars)
|
|
6351
6351
|
return marker.slice(0, maxChars);
|
|
6352
|
-
const head =
|
|
6352
|
+
const head = text.slice(0, maxChars - marker.length).replace(/[ \t\r\n]+$/, "");
|
|
6353
6353
|
return `${head}${marker}`;
|
|
6354
6354
|
}
|
|
6355
|
-
function
|
|
6355
|
+
function isRecord11(value) {
|
|
6356
6356
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
6357
6357
|
}
|
|
6358
6358
|
|
|
@@ -6369,7 +6369,7 @@ async function runHookCli(runHook, stdin) {
|
|
|
6369
6369
|
if (!raw.trim())
|
|
6370
6370
|
return;
|
|
6371
6371
|
const parsed = JSON.parse(raw);
|
|
6372
|
-
const input =
|
|
6372
|
+
const input = isRecord11(parsed) ? parsed : {};
|
|
6373
6373
|
const output = await runHook(input);
|
|
6374
6374
|
if (output)
|
|
6375
6375
|
process.stdout.write(output);
|
|
@@ -6413,14 +6413,14 @@ main().catch((error) => {
|
|
|
6413
6413
|
async function runPackageLspMcpCli() {
|
|
6414
6414
|
const cliPath = resolveLspDaemonCliPath();
|
|
6415
6415
|
const child = spawn3(execPath2, [cliPath, "mcp"], { stdio: "inherit", windowsHide: true });
|
|
6416
|
-
await new Promise((
|
|
6416
|
+
await new Promise((resolve, reject) => {
|
|
6417
6417
|
child.once("error", reject);
|
|
6418
6418
|
child.once("exit", (code, signal) => {
|
|
6419
6419
|
if (code !== null && code !== 0)
|
|
6420
6420
|
process.exitCode = code;
|
|
6421
6421
|
if (code === null && signal !== null)
|
|
6422
6422
|
process.exitCode = 1;
|
|
6423
|
-
|
|
6423
|
+
resolve();
|
|
6424
6424
|
});
|
|
6425
6425
|
});
|
|
6426
6426
|
}
|