oh-my-opencode 4.14.0 → 4.14.1
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/.agents/skills/codex-qa/references/isolation.md +1 -1
- package/README.md +1 -1
- package/dist/cli/doctor/framework/types.d.ts +2 -0
- package/dist/cli/index.js +149 -1426
- package/dist/cli-node/index.js +149 -1426
- package/dist/index.js +4255 -714
- package/dist/plugin/native-skills.d.ts +9 -0
- package/dist/plugin/system-transform.d.ts +1 -1
- package/dist/skills/lcx-contribute-bug-fix/SKILL.md +44 -13
- package/dist/skills/lcx-contribute-bug-fix/agents/openai.yaml +1 -1
- package/dist/skills/lcx-doctor/SKILL.md +48 -13
- package/dist/skills/lcx-doctor/agents/openai.yaml +1 -1
- package/dist/skills/lcx-report-bug/SKILL.md +44 -13
- package/dist/skills/lcx-report-bug/agents/openai.yaml +1 -1
- package/dist/skills/visual-qa/SKILL.md +5 -5
- package/dist/skills/visual-qa/references/agent-browser-setup.md +5 -4
- package/dist/skills/visual-qa/scripts/cli.test.ts +7 -2
- package/dist/skills/visual-qa/scripts/skill-prompt-contract.test.ts +10 -2
- package/dist/skills/visual-qa/scripts/visual-qa.mjs +530 -0
- package/dist/tools/delegate-task/skill-resolver.d.ts +1 -0
- package/dist/tools/delegate-task/types.d.ts +2 -0
- package/dist/tools/skill/types.d.ts +1 -0
- package/package.json +26 -13
- package/packages/git-bash-mcp/dist/cli.js +2 -0
- package/packages/lsp-daemon/dist/cli.js +15 -4
- package/packages/lsp-daemon/dist/ensure-daemon.d.ts +1 -0
- package/packages/lsp-daemon/dist/ensure-daemon.js +9 -3
- package/packages/lsp-daemon/dist/index.js +15 -4
- package/packages/lsp-daemon/dist/paths.d.ts +1 -0
- package/packages/lsp-daemon/dist/paths.js +6 -1
- package/packages/omo-codex/plugin/.codex-plugin/plugin.json +1 -1
- package/packages/omo-codex/plugin/components/bootstrap/dist/cli.js +4 -7
- package/packages/omo-codex/plugin/components/bootstrap/package.json +1 -1
- package/packages/omo-codex/plugin/components/bootstrap/src/setup.ts +1 -1
- package/packages/omo-codex/plugin/components/codegraph/dist/cli.js +123 -10
- package/packages/omo-codex/plugin/components/codegraph/dist/serve.js +123 -10
- package/packages/omo-codex/plugin/components/codegraph/package.json +1 -1
- package/packages/omo-codex/plugin/components/codegraph/src/mcp-bridge.ts +126 -9
- package/packages/omo-codex/plugin/components/codegraph/test/serve-mcp-bridge.test.ts +141 -0
- package/packages/omo-codex/plugin/components/comment-checker/package.json +1 -1
- package/packages/omo-codex/plugin/components/git-bash/package.json +1 -1
- package/packages/omo-codex/plugin/components/lazycodex-executor-verify/package.json +1 -1
- package/packages/omo-codex/plugin/components/lsp/dist/cli.js +90 -25
- package/packages/omo-codex/plugin/components/lsp/dist/codex-hook.js +2 -0
- package/packages/omo-codex/plugin/components/lsp/dist/daemon-cli-path.d.ts +2 -0
- package/packages/omo-codex/plugin/components/lsp/dist/daemon-cli-path.js +56 -0
- package/packages/omo-codex/plugin/components/lsp/package.json +1 -1
- package/packages/omo-codex/plugin/components/lsp/src/cli.ts +2 -5
- package/packages/omo-codex/plugin/components/lsp/src/codex-hook.ts +2 -0
- package/packages/omo-codex/plugin/components/lsp/src/daemon-cli-path.ts +65 -0
- package/packages/omo-codex/plugin/components/lsp/test/package-smoke.test.ts +6 -1
- package/packages/omo-codex/plugin/components/rules/dist/cli.js +8 -106
- package/packages/omo-codex/plugin/components/rules/package.json +1 -1
- package/packages/omo-codex/plugin/components/rules/src/static-injection.ts +4 -17
- package/packages/omo-codex/plugin/components/start-work-continuation/package.json +1 -1
- package/packages/omo-codex/plugin/components/teammode/package.json +1 -1
- package/packages/omo-codex/plugin/components/teammode/skills/teammode/SKILL.md +17 -5
- package/packages/omo-codex/plugin/components/teammode/skills/teammode/scripts/team-state.mjs +63 -1
- package/packages/omo-codex/plugin/components/teammode/skills/teammode/scripts/team.mjs +80 -50
- package/packages/omo-codex/plugin/components/telemetry/package.json +1 -1
- package/packages/omo-codex/plugin/components/ultrawork/agents/explorer.toml +1 -1
- package/packages/omo-codex/plugin/components/ultrawork/directive.md +4 -12
- package/packages/omo-codex/plugin/components/ultrawork/package.json +1 -1
- package/packages/omo-codex/plugin/components/ultrawork/test/package-smoke.test.ts +7 -33
- package/packages/omo-codex/plugin/components/ulw-loop/directive.md +4 -12
- package/packages/omo-codex/plugin/components/ulw-loop/package.json +4 -2
- package/packages/omo-codex/plugin/components/ulw-loop/skills/ulw-loop/SKILL.md +1 -1
- package/packages/omo-codex/plugin/components/ulw-loop/skills/ulw-loop/references/full-workflow.md +4 -4
- package/packages/omo-codex/plugin/components/ulw-loop/test/fixtures/sample-quality-gate.json +7 -7
- package/packages/omo-codex/plugin/components/ulw-loop/test/package-smoke.test.ts +3 -1
- package/packages/omo-codex/plugin/components/ulw-loop/test/quality-gate-doc.test.ts +2 -2
- package/packages/omo-codex/plugin/components/ulw-loop/test/quality-gate.test.ts +7 -6
- package/packages/omo-codex/plugin/package-lock.json +16 -56
- package/packages/omo-codex/plugin/package.json +1 -1
- package/packages/omo-codex/plugin/skills/lcx-contribute-bug-fix/SKILL.md +44 -13
- package/packages/omo-codex/plugin/skills/lcx-contribute-bug-fix/agents/openai.yaml +1 -1
- package/packages/omo-codex/plugin/skills/lcx-doctor/SKILL.md +48 -13
- package/packages/omo-codex/plugin/skills/lcx-doctor/agents/openai.yaml +1 -1
- package/packages/omo-codex/plugin/skills/lcx-report-bug/SKILL.md +44 -13
- package/packages/omo-codex/plugin/skills/lcx-report-bug/agents/openai.yaml +1 -1
- package/packages/omo-codex/plugin/skills/teammode/SKILL.md +17 -5
- package/packages/omo-codex/plugin/skills/teammode/scripts/team-state.mjs +63 -1
- package/packages/omo-codex/plugin/skills/teammode/scripts/team.mjs +80 -50
- package/packages/omo-codex/plugin/skills/ulw-loop/SKILL.md +1 -1
- package/packages/omo-codex/plugin/skills/ulw-loop/references/full-workflow.md +4 -4
- package/packages/omo-codex/plugin/skills/visual-qa/SKILL.md +5 -5
- package/packages/omo-codex/plugin/skills/visual-qa/references/agent-browser-setup.md +5 -4
- package/packages/omo-codex/plugin/skills/visual-qa/scripts/visual-qa.mjs +530 -0
- package/packages/omo-codex/plugin/test/bootstrap-binlinks.test.mjs +38 -2
- package/packages/omo-codex/plugin/test/component-bin-names.test.mjs +12 -11
- package/packages/omo-codex/plugin/test/component-bundled-cli.test.mjs +99 -1
- package/packages/omo-codex/plugin/test/lcx-bug-skills.test.mjs +62 -8
- package/packages/omo-codex/plugin/test/node-install-surface.test.mjs +1 -0
- package/packages/omo-codex/plugin/test/teammode-archive-ambiguity.test.mjs +102 -0
- package/packages/omo-codex/plugin/test/teammode-safety-fixture.mjs +41 -1
- package/packages/omo-codex/plugin/test/teammode-safety.test.mjs +93 -0
- package/packages/omo-codex/scripts/install-bin-links.test.mjs +6 -0
- package/packages/omo-codex/scripts/install-cache-copy.test.mjs +28 -0
- package/packages/omo-codex/scripts/install-config-autonomous-features.test.mjs +43 -3
- package/packages/omo-codex/scripts/install-delegated-command.test.mjs +93 -0
- package/packages/omo-codex/scripts/install-dist/install-local.mjs +103 -28
- package/packages/omo-codex/scripts/install-local-entrypoint.test.mjs +21 -2
- package/packages/omo-codex/scripts/install-local.test.mjs +0 -1
- package/packages/shared-skills/skills/lcx-contribute-bug-fix/SKILL.md +44 -13
- package/packages/shared-skills/skills/lcx-contribute-bug-fix/agents/openai.yaml +1 -1
- package/packages/shared-skills/skills/lcx-doctor/SKILL.md +48 -13
- package/packages/shared-skills/skills/lcx-doctor/agents/openai.yaml +1 -1
- package/packages/shared-skills/skills/lcx-report-bug/SKILL.md +44 -13
- package/packages/shared-skills/skills/lcx-report-bug/agents/openai.yaml +1 -1
- package/packages/shared-skills/skills/visual-qa/SKILL.md +5 -5
- package/packages/shared-skills/skills/visual-qa/references/agent-browser-setup.md +5 -4
- package/packages/shared-skills/skills/visual-qa/scripts/cli.test.ts +7 -2
- package/packages/shared-skills/skills/visual-qa/scripts/skill-prompt-contract.test.ts +10 -2
- package/packages/shared-skills/skills/visual-qa/scripts/visual-qa.mjs +530 -0
- package/dist/cli/sparkshell-appserver-websocket.d.ts +0 -4
- package/dist/cli/sparkshell-appserver.d.ts +0 -16
- package/dist/cli/sparkshell-condense.d.ts +0 -10
- package/dist/cli/sparkshell-parse.d.ts +0 -24
- package/dist/cli/sparkshell-session-context.d.ts +0 -20
- package/dist/cli/sparkshell-spark.d.ts +0 -23
- package/dist/cli/sparkshell.d.ts +0 -33
- package/dist/shared/sparkshell-awareness.d.ts +0 -5
- package/packages/omo-codex/plugin/components/rules/src/sparkshell-awareness.ts +0 -106
- package/packages/omo-codex/plugin/components/rules/test/sparkshell-awareness.test.ts +0 -355
|
@@ -20,6 +20,21 @@ class CodegraphBridgeStdioError extends Error {
|
|
|
20
20
|
}
|
|
21
21
|
}
|
|
22
22
|
|
|
23
|
+
interface PendingClientResponse {
|
|
24
|
+
readonly method: string | null;
|
|
25
|
+
readonly responseMode: StdioJsonRpcResponseMode;
|
|
26
|
+
readonly toolName: string | null;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
const CODEGRAPH_NODE_DESCRIPTION =
|
|
30
|
+
"Inspect one named symbol or file. In symbol mode, includeCode=true includes leaf-symbol source when available. Container symbols such as classes, interfaces, structs, enums, modules, and namespaces return structural outlines with member lists by design. For container source, request a specific member symbol or use file mode with symbolsOnly=false plus offset/limit.";
|
|
31
|
+
|
|
32
|
+
const CODEGRAPH_NODE_INCLUDE_CODE_DESCRIPTION =
|
|
33
|
+
"Symbol mode: include leaf-symbol source when available. Container symbols such as classes, interfaces, structs, enums, modules, and namespaces intentionally return structural outlines with members; request a specific member symbol or use file mode with symbolsOnly=false plus offset/limit for source.";
|
|
34
|
+
|
|
35
|
+
const CODEGRAPH_CONTAINER_OUTLINE_GUIDANCE =
|
|
36
|
+
"Container symbols intentionally return structural outlines with members. For source, request a specific member symbol or call codegraph_node in file mode with symbolsOnly=false plus offset/limit around the symbol location.";
|
|
37
|
+
|
|
23
38
|
export async function runBridgedCodegraphProcess(
|
|
24
39
|
command: string,
|
|
25
40
|
args: readonly string[],
|
|
@@ -36,7 +51,7 @@ export async function runBridgedCodegraphProcess(
|
|
|
36
51
|
if (childInput === null) throw new CodegraphBridgeStdioError("stdin");
|
|
37
52
|
if (childOutput === null) throw new CodegraphBridgeStdioError("stdout");
|
|
38
53
|
|
|
39
|
-
const
|
|
54
|
+
const pendingResponses = new Map<string, PendingClientResponse>();
|
|
40
55
|
let defaultResponseMode: StdioJsonRpcResponseMode = "framed";
|
|
41
56
|
const childExit = new Promise<number>((resolveExit, reject) => {
|
|
42
57
|
child.once("error", reject);
|
|
@@ -49,10 +64,10 @@ export async function runBridgedCodegraphProcess(
|
|
|
49
64
|
});
|
|
50
65
|
});
|
|
51
66
|
const bridgeDone = Promise.all([
|
|
52
|
-
forwardClientToCodegraph(options.input, childInput,
|
|
67
|
+
forwardClientToCodegraph(options.input, childInput, pendingResponses, (mode) => {
|
|
53
68
|
defaultResponseMode = mode;
|
|
54
69
|
}),
|
|
55
|
-
forwardCodegraphToClient(childOutput, options.output,
|
|
70
|
+
forwardCodegraphToClient(childOutput, options.output, pendingResponses, () => defaultResponseMode),
|
|
56
71
|
]);
|
|
57
72
|
const destroyChildPipes = (): void => {
|
|
58
73
|
childInput.destroy();
|
|
@@ -65,7 +80,7 @@ export async function runBridgedCodegraphProcess(
|
|
|
65
80
|
async function forwardClientToCodegraph(
|
|
66
81
|
input: Readable,
|
|
67
82
|
childInput: Writable,
|
|
68
|
-
|
|
83
|
+
pendingResponses: Map<string, PendingClientResponse>,
|
|
69
84
|
setDefaultResponseMode: (mode: StdioJsonRpcResponseMode) => void,
|
|
70
85
|
): Promise<void> {
|
|
71
86
|
for await (const message of readStdioJsonRpcMessages(input)) {
|
|
@@ -75,7 +90,13 @@ async function forwardClientToCodegraph(
|
|
|
75
90
|
const responseMode = message.responseMode;
|
|
76
91
|
setDefaultResponseMode(responseMode);
|
|
77
92
|
const key = responseModeKey(message.payload);
|
|
78
|
-
if (key !== null)
|
|
93
|
+
if (key !== null) {
|
|
94
|
+
pendingResponses.set(key, {
|
|
95
|
+
method: jsonRpcMethod(message.payload),
|
|
96
|
+
responseMode,
|
|
97
|
+
toolName: jsonRpcToolName(message.payload),
|
|
98
|
+
});
|
|
99
|
+
}
|
|
79
100
|
await writeLine(childInput, JSON.stringify(message.payload));
|
|
80
101
|
}
|
|
81
102
|
childInput.end();
|
|
@@ -84,7 +105,7 @@ async function forwardClientToCodegraph(
|
|
|
84
105
|
async function forwardCodegraphToClient(
|
|
85
106
|
childOutput: Readable,
|
|
86
107
|
output: Writable,
|
|
87
|
-
|
|
108
|
+
pendingResponses: Map<string, PendingClientResponse>,
|
|
88
109
|
defaultResponseMode: () => StdioJsonRpcResponseMode,
|
|
89
110
|
): Promise<void> {
|
|
90
111
|
for await (const message of readStdioJsonRpcMessages(childOutput)) {
|
|
@@ -93,9 +114,10 @@ async function forwardCodegraphToClient(
|
|
|
93
114
|
continue;
|
|
94
115
|
}
|
|
95
116
|
const key = responseModeKey(message.payload);
|
|
96
|
-
const
|
|
97
|
-
|
|
98
|
-
|
|
117
|
+
const pendingResponse = key === null ? undefined : pendingResponses.get(key);
|
|
118
|
+
const responseMode = pendingResponse?.responseMode ?? defaultResponseMode();
|
|
119
|
+
if (key !== null) pendingResponses.delete(key);
|
|
120
|
+
writeStdioJsonRpcResponse(output, clarifyCodegraphResponse(message.payload, pendingResponse), responseMode);
|
|
99
121
|
}
|
|
100
122
|
}
|
|
101
123
|
|
|
@@ -105,6 +127,101 @@ function responseModeKey(payload: unknown): string | null {
|
|
|
105
127
|
return `${typeof id}:${String(id)}`;
|
|
106
128
|
}
|
|
107
129
|
|
|
130
|
+
function jsonRpcMethod(payload: unknown): string | null {
|
|
131
|
+
if (!isPlainRecord(payload)) return null;
|
|
132
|
+
const method = payload["method"];
|
|
133
|
+
return typeof method === "string" ? method : null;
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
function jsonRpcToolName(payload: unknown): string | null {
|
|
137
|
+
if (jsonRpcMethod(payload) !== "tools/call" || !isPlainRecord(payload)) return null;
|
|
138
|
+
const params = payload["params"];
|
|
139
|
+
if (!isPlainRecord(params)) return null;
|
|
140
|
+
const name = params["name"];
|
|
141
|
+
return typeof name === "string" ? name : null;
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
function clarifyCodegraphResponse(payload: unknown, pendingResponse: PendingClientResponse | undefined): unknown {
|
|
145
|
+
if (pendingResponse?.method === "tools/list") return clarifyCodegraphToolsList(payload);
|
|
146
|
+
if (pendingResponse?.method === "tools/call" && pendingResponse.toolName === "codegraph_node") {
|
|
147
|
+
return clarifyCodegraphNodeCallResult(payload);
|
|
148
|
+
}
|
|
149
|
+
return payload;
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
function clarifyCodegraphToolsList(payload: unknown): unknown {
|
|
153
|
+
if (!isPlainRecord(payload)) return payload;
|
|
154
|
+
const result = payload["result"];
|
|
155
|
+
if (!isPlainRecord(result) || !Array.isArray(result["tools"])) return payload;
|
|
156
|
+
|
|
157
|
+
let changed = false;
|
|
158
|
+
const tools = result["tools"].map((tool) => {
|
|
159
|
+
if (!isPlainRecord(tool) || tool["name"] !== "codegraph_node") return tool;
|
|
160
|
+
if (!hasCodegraphNodeContractMetadata(tool)) return tool;
|
|
161
|
+
changed = true;
|
|
162
|
+
return clarifyCodegraphNodeTool(tool);
|
|
163
|
+
});
|
|
164
|
+
if (!changed) return payload;
|
|
165
|
+
return { ...payload, result: { ...result, tools } };
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
function clarifyCodegraphNodeTool(tool: Record<string, unknown>): Record<string, unknown> {
|
|
169
|
+
const clarified: Record<string, unknown> = {
|
|
170
|
+
...tool,
|
|
171
|
+
description: CODEGRAPH_NODE_DESCRIPTION,
|
|
172
|
+
};
|
|
173
|
+
const inputSchema = tool["inputSchema"];
|
|
174
|
+
if (isPlainRecord(inputSchema)) clarified["inputSchema"] = clarifyCodegraphNodeInputSchema(inputSchema);
|
|
175
|
+
return clarified;
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
function hasCodegraphNodeContractMetadata(tool: Record<string, unknown>): boolean {
|
|
179
|
+
if (typeof tool["description"] === "string") return true;
|
|
180
|
+
const inputSchema = tool["inputSchema"];
|
|
181
|
+
if (!isPlainRecord(inputSchema)) return false;
|
|
182
|
+
const properties = inputSchema["properties"];
|
|
183
|
+
return isPlainRecord(properties) && isPlainRecord(properties["includeCode"]);
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
function clarifyCodegraphNodeInputSchema(inputSchema: Record<string, unknown>): Record<string, unknown> {
|
|
187
|
+
const properties = inputSchema["properties"];
|
|
188
|
+
if (!isPlainRecord(properties)) return inputSchema;
|
|
189
|
+
const includeCode = properties["includeCode"];
|
|
190
|
+
if (!isPlainRecord(includeCode)) return inputSchema;
|
|
191
|
+
return {
|
|
192
|
+
...inputSchema,
|
|
193
|
+
properties: {
|
|
194
|
+
...properties,
|
|
195
|
+
includeCode: {
|
|
196
|
+
...includeCode,
|
|
197
|
+
description: CODEGRAPH_NODE_INCLUDE_CODE_DESCRIPTION,
|
|
198
|
+
},
|
|
199
|
+
},
|
|
200
|
+
};
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
function clarifyCodegraphNodeCallResult(payload: unknown): unknown {
|
|
204
|
+
if (!isPlainRecord(payload)) return payload;
|
|
205
|
+
const result = payload["result"];
|
|
206
|
+
if (!isPlainRecord(result) || !Array.isArray(result["content"])) return payload;
|
|
207
|
+
|
|
208
|
+
let changed = false;
|
|
209
|
+
const content = result["content"].map((item) => {
|
|
210
|
+
if (!isPlainRecord(item) || item["type"] !== "text" || typeof item["text"] !== "string") return item;
|
|
211
|
+
const text = clarifyContainerOutlineGuidance(item["text"]);
|
|
212
|
+
if (text === item["text"]) return item;
|
|
213
|
+
changed = true;
|
|
214
|
+
return { ...item, text };
|
|
215
|
+
});
|
|
216
|
+
if (!changed) return payload;
|
|
217
|
+
return { ...payload, result: { ...result, content } };
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
function clarifyContainerOutlineGuidance(text: string): string {
|
|
221
|
+
if (!text.includes("Structural outline only")) return text;
|
|
222
|
+
return text.replace(/Structural outline only[^\n]*(?:\n[^\n]*(?:Read|read)[^\n]*)?/g, CODEGRAPH_CONTAINER_OUTLINE_GUIDANCE);
|
|
223
|
+
}
|
|
224
|
+
|
|
108
225
|
async function writeLine(output: Writable, line: string): Promise<void> {
|
|
109
226
|
if (output.write(`${line}\n`)) return;
|
|
110
227
|
await new Promise<void>((resolveDrain, reject) => {
|
|
@@ -93,6 +93,90 @@ describe("runCodegraphServe MCP protocol bridge", () => {
|
|
|
93
93
|
rmSync(tempRoot, { recursive: true, force: true });
|
|
94
94
|
}
|
|
95
95
|
});
|
|
96
|
+
|
|
97
|
+
it("#given old upstream codegraph_node metadata and container outline guidance #when bridging #then it exposes the corrected LazyCodex contract", async () => {
|
|
98
|
+
// given
|
|
99
|
+
const tempRoot = mkdtempSync(join(tmpdir(), "omo-codegraph-contract-"));
|
|
100
|
+
const projectRoot = join(tempRoot, "project");
|
|
101
|
+
const fakeCodegraph = join(tempRoot, "codegraph-contract-fake.cjs");
|
|
102
|
+
const childLog = join(tempRoot, "child.log");
|
|
103
|
+
const input = new PassThrough();
|
|
104
|
+
const output = new PassThrough();
|
|
105
|
+
let stdout = "";
|
|
106
|
+
output.on("data", (chunk: Buffer) => {
|
|
107
|
+
stdout += chunk.toString("utf8");
|
|
108
|
+
});
|
|
109
|
+
|
|
110
|
+
try {
|
|
111
|
+
mkdirSync(projectRoot, { recursive: true });
|
|
112
|
+
writeFakeContractCodegraph(fakeCodegraph);
|
|
113
|
+
|
|
114
|
+
const run = runCodegraphServe({
|
|
115
|
+
cwd: tempRoot,
|
|
116
|
+
env: {
|
|
117
|
+
CODEGRAPH_ALLOW_UNSAFE_NODE: "1",
|
|
118
|
+
CODEGRAPH_FAKE_LOG: childLog,
|
|
119
|
+
OMO_CODEGRAPH_BIN: fakeCodegraph,
|
|
120
|
+
OMO_CODEGRAPH_PROJECT_CWD: projectRoot,
|
|
121
|
+
PATH: process.env["PATH"],
|
|
122
|
+
},
|
|
123
|
+
nodeVersion: "22.14.0",
|
|
124
|
+
buildEnv: () => ({}),
|
|
125
|
+
resolve: () => ({ argsPrefix: [], command: fakeCodegraph, exists: true, source: "env" }),
|
|
126
|
+
stderr: { write: () => undefined },
|
|
127
|
+
stdin: input,
|
|
128
|
+
stdout: output,
|
|
129
|
+
});
|
|
130
|
+
|
|
131
|
+
// when
|
|
132
|
+
input.end([
|
|
133
|
+
frameMcpRequest({
|
|
134
|
+
id: 1,
|
|
135
|
+
method: "tools/list",
|
|
136
|
+
params: {},
|
|
137
|
+
}),
|
|
138
|
+
frameMcpRequest({
|
|
139
|
+
id: 2,
|
|
140
|
+
method: "tools/call",
|
|
141
|
+
params: {
|
|
142
|
+
arguments: { includeCode: true, symbol: "JsonlMCP" },
|
|
143
|
+
name: "codegraph_node",
|
|
144
|
+
},
|
|
145
|
+
}),
|
|
146
|
+
].join(""));
|
|
147
|
+
const exitCode = await run;
|
|
148
|
+
|
|
149
|
+
// then
|
|
150
|
+
expect(exitCode).toBe(0);
|
|
151
|
+
const bodies = parseMcpBodies(stdout);
|
|
152
|
+
const tools = arrayProperty(recordProperty(recordValue(bodies[0]), "result"), "tools");
|
|
153
|
+
const nodeTool = findTool(tools, "codegraph_node");
|
|
154
|
+
const searchTool = findTool(tools, "codegraph_search");
|
|
155
|
+
expect(stringProperty(nodeTool, "description")).toContain("Container symbols");
|
|
156
|
+
expect(stringProperty(nodeTool, "description")).toContain("file mode");
|
|
157
|
+
expect(stringProperty(nodeTool, "description")).not.toContain("verbatim source");
|
|
158
|
+
expect(stringProperty(nodeTool, "description")).not.toContain("full body");
|
|
159
|
+
expect(
|
|
160
|
+
stringProperty(
|
|
161
|
+
recordProperty(recordProperty(recordProperty(nodeTool, "inputSchema"), "properties"), "includeCode"),
|
|
162
|
+
"description",
|
|
163
|
+
),
|
|
164
|
+
).toBe(
|
|
165
|
+
"Symbol mode: include leaf-symbol source when available. Container symbols such as classes, interfaces, structs, enums, modules, and namespaces intentionally return structural outlines with members; request a specific member symbol or use file mode with symbolsOnly=false plus offset/limit for source.",
|
|
166
|
+
);
|
|
167
|
+
expect(searchTool).toEqual({ description: "search stays unchanged", name: "codegraph_search" });
|
|
168
|
+
|
|
169
|
+
const callResult = recordProperty(recordValue(bodies[1]), "result");
|
|
170
|
+
const text = stringProperty(recordValue(arrayProperty(callResult, "content")[0]), "text");
|
|
171
|
+
expect(text).toContain("Container symbols intentionally return structural outlines");
|
|
172
|
+
expect(text).toContain("specific member symbol");
|
|
173
|
+
expect(text).toContain("file mode");
|
|
174
|
+
expect(text).toContain("symbolsOnly=false");
|
|
175
|
+
expect(text).not.toContain("Read tool");
|
|
176
|
+
} finally {
|
|
177
|
+
rmSync(tempRoot, { recursive: true, force: true });
|
|
178
|
+
}
|
|
179
|
+
});
|
|
96
180
|
});
|
|
97
181
|
|
|
98
182
|
function writeFakeNewlineCodegraph(filePath: string): void {
|
|
@@ -118,6 +202,32 @@ function writeFakeNewlineCodegraph(filePath: string): void {
|
|
|
118
202
|
chmodSync(filePath, 0o755);
|
|
119
203
|
}
|
|
120
204
|
|
|
205
|
+
function writeFakeContractCodegraph(filePath: string): void {
|
|
206
|
+
writeFileSync(
|
|
207
|
+
filePath,
|
|
208
|
+
[
|
|
209
|
+
"#!/usr/bin/env node",
|
|
210
|
+
"const fs = require('node:fs');",
|
|
211
|
+
"const readline = require('node:readline');",
|
|
212
|
+
"fs.writeFileSync(process.env.CODEGRAPH_FAKE_LOG, `cwd=${process.cwd()}\\n`);",
|
|
213
|
+
"const rl = readline.createInterface({ input: process.stdin });",
|
|
214
|
+
"rl.on('line', (line) => {",
|
|
215
|
+
" const request = JSON.parse(line);",
|
|
216
|
+
" if (request.method === 'tools/list') {",
|
|
217
|
+
" process.stdout.write(JSON.stringify({ jsonrpc: '2.0', id: request.id, result: { tools: [",
|
|
218
|
+
" { name: 'codegraph_search', description: 'search stays unchanged' },",
|
|
219
|
+
" { name: 'codegraph_node', description: 'ONE SYMBOL you can name - its location, signature, verbatim source (includeCode=true) and caller/callee trail in one call', inputSchema: { type: 'object', properties: { includeCode: { type: 'boolean', description: \"Symbol mode: include the symbol's full body (default: false).\" }, symbol: { type: 'string' } } } }",
|
|
220
|
+
" ] } }) + '\\n');",
|
|
221
|
+
" }",
|
|
222
|
+
" if (request.method === 'tools/call') {",
|
|
223
|
+
" process.stdout.write(JSON.stringify({ jsonrpc: '2.0', id: request.id, result: { content: [{ type: 'text', text: 'JsonlMCP\\nMembers (7)\\nStructural outline only. For full source, use the Read tool on this file or request a member.' }] } }) + '\\n');",
|
|
224
|
+
" }",
|
|
225
|
+
"});",
|
|
226
|
+
].join("\n"),
|
|
227
|
+
);
|
|
228
|
+
chmodSync(filePath, 0o755);
|
|
229
|
+
}
|
|
230
|
+
|
|
121
231
|
function frameMcpRequest(request: {
|
|
122
232
|
readonly id: number;
|
|
123
233
|
readonly method: string;
|
|
@@ -144,3 +254,34 @@ function parseMcpBodies(transcript: string): readonly unknown[] {
|
|
|
144
254
|
}
|
|
145
255
|
return bodies;
|
|
146
256
|
}
|
|
257
|
+
|
|
258
|
+
function findTool(tools: readonly unknown[], name: string): Record<string, unknown> {
|
|
259
|
+
for (const tool of tools) {
|
|
260
|
+
const record = recordValue(tool);
|
|
261
|
+
if (record["name"] === name) return record;
|
|
262
|
+
}
|
|
263
|
+
throw new Error(`Missing tool ${name}`);
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
function arrayProperty(record: Record<string, unknown>, key: string): readonly unknown[] {
|
|
267
|
+
const value = record[key];
|
|
268
|
+
if (!Array.isArray(value)) throw new Error(`Expected ${key} to be an array`);
|
|
269
|
+
return value;
|
|
270
|
+
}
|
|
271
|
+
|
|
272
|
+
function recordProperty(record: Record<string, unknown>, key: string): Record<string, unknown> {
|
|
273
|
+
return recordValue(record[key]);
|
|
274
|
+
}
|
|
275
|
+
|
|
276
|
+
function stringProperty(record: Record<string, unknown>, key: string): string {
|
|
277
|
+
const value = record[key];
|
|
278
|
+
if (typeof value !== "string") throw new Error(`Expected ${key} to be a string`);
|
|
279
|
+
return value;
|
|
280
|
+
}
|
|
281
|
+
|
|
282
|
+
function recordValue(value: unknown): Record<string, unknown> {
|
|
283
|
+
if (typeof value !== "object" || value === null || Array.isArray(value)) {
|
|
284
|
+
throw new Error("Expected record value");
|
|
285
|
+
}
|
|
286
|
+
return value as Record<string, unknown>;
|
|
287
|
+
}
|
|
@@ -2,7 +2,6 @@
|
|
|
2
2
|
|
|
3
3
|
// components/lsp/src/cli.ts
|
|
4
4
|
import { spawn as spawn3 } from "node:child_process";
|
|
5
|
-
import { createRequire as createRequire2 } from "node:module";
|
|
6
5
|
import { argv, execPath as execPath2, stderr } from "node:process";
|
|
7
6
|
|
|
8
7
|
// components/lsp/src/codex-hook-cli.ts
|
|
@@ -1481,6 +1480,7 @@ function unlinkQuietly(path) {
|
|
|
1481
1480
|
var PROBE_TIMEOUT_MS = 500;
|
|
1482
1481
|
var DEFAULT_READY_TIMEOUT_MS = 5000;
|
|
1483
1482
|
var DEFAULT_POLL_INTERVAL_MS = 100;
|
|
1483
|
+
var CODEX_LSP_DAEMON_CLI_ENV = "CODEX_LSP_DAEMON_CLI";
|
|
1484
1484
|
|
|
1485
1485
|
class DaemonUnreachableError extends Error {
|
|
1486
1486
|
constructor(socketPath) {
|
|
@@ -1541,7 +1541,7 @@ function spawnDaemonProcess(paths) {
|
|
|
1541
1541
|
mkdirSync2(dirname2(paths.log), { recursive: true });
|
|
1542
1542
|
const logFd = openSync2(paths.log, "a");
|
|
1543
1543
|
try {
|
|
1544
|
-
const cliPath =
|
|
1544
|
+
const cliPath = resolveDaemonCliPath();
|
|
1545
1545
|
const child = spawn2(execPath, [cliPath, "daemon"], {
|
|
1546
1546
|
detached: true,
|
|
1547
1547
|
stdio: ["ignore", logFd, logFd]
|
|
@@ -1551,6 +1551,12 @@ function spawnDaemonProcess(paths) {
|
|
|
1551
1551
|
closeSync2(logFd);
|
|
1552
1552
|
}
|
|
1553
1553
|
}
|
|
1554
|
+
function resolveDaemonCliPath(env = process.env) {
|
|
1555
|
+
const override = env[CODEX_LSP_DAEMON_CLI_ENV]?.trim();
|
|
1556
|
+
if (override)
|
|
1557
|
+
return override;
|
|
1558
|
+
return fileURLToPath(new URL("./cli.js", import.meta.url));
|
|
1559
|
+
}
|
|
1554
1560
|
function defaultEnsureDaemonDeps() {
|
|
1555
1561
|
return {
|
|
1556
1562
|
probe: (socketPath) => probeSocket(socketPath),
|
|
@@ -1561,14 +1567,14 @@ function defaultEnsureDaemonDeps() {
|
|
|
1561
1567
|
},
|
|
1562
1568
|
spawnDaemon: (paths) => spawnDaemonProcess(paths),
|
|
1563
1569
|
sleep: (ms) => new Promise((resolve22) => {
|
|
1564
|
-
|
|
1565
|
-
timer.unref?.();
|
|
1570
|
+
setTimeout(resolve22, ms);
|
|
1566
1571
|
}),
|
|
1567
1572
|
now: () => Date.now()
|
|
1568
1573
|
};
|
|
1569
1574
|
}
|
|
1570
1575
|
var requireFromHere = createRequire(import.meta.url);
|
|
1571
1576
|
var MAX_SOCKET_PATH_LENGTH = 100;
|
|
1577
|
+
var CODEX_LSP_DAEMON_VERSION_ENV = "CODEX_LSP_DAEMON_VERSION";
|
|
1572
1578
|
function resolveDaemonVersion(requireFn = requireFromHere) {
|
|
1573
1579
|
for (const candidate of ["./package.json", "../package.json"]) {
|
|
1574
1580
|
try {
|
|
@@ -1590,7 +1596,7 @@ function daemonBaseDir(env = process.env) {
|
|
|
1590
1596
|
const home = codexHome && codexHome.length > 0 ? codexHome : join2(homedir(), ".codex");
|
|
1591
1597
|
return join2(home, "codex-lsp", "daemon");
|
|
1592
1598
|
}
|
|
1593
|
-
function daemonPaths(env = process.env, version = resolveDaemonVersion()) {
|
|
1599
|
+
function daemonPaths(env = process.env, version = resolveDaemonVersionFromEnv(env) ?? resolveDaemonVersion()) {
|
|
1594
1600
|
const dir = join2(daemonBaseDir(env), `v${version}`);
|
|
1595
1601
|
return {
|
|
1596
1602
|
version,
|
|
@@ -1601,6 +1607,10 @@ function daemonPaths(env = process.env, version = resolveDaemonVersion()) {
|
|
|
1601
1607
|
log: join2(dir, "daemon.log")
|
|
1602
1608
|
};
|
|
1603
1609
|
}
|
|
1610
|
+
function resolveDaemonVersionFromEnv(env = process.env) {
|
|
1611
|
+
const version = env[CODEX_LSP_DAEMON_VERSION_ENV]?.trim();
|
|
1612
|
+
return version && version.length > 0 ? version : null;
|
|
1613
|
+
}
|
|
1604
1614
|
function resolveSocketPath(dir, version) {
|
|
1605
1615
|
const digest = createHash("sha256").update(dir).digest("hex").slice(0, 16);
|
|
1606
1616
|
if (process.platform === "win32") {
|
|
@@ -3322,12 +3332,68 @@ function errorText(error) {
|
|
|
3322
3332
|
}
|
|
3323
3333
|
|
|
3324
3334
|
// components/lsp/src/codex-hook.ts
|
|
3325
|
-
import { readFileSync as
|
|
3335
|
+
import { readFileSync as readFileSync9 } from "node:fs";
|
|
3336
|
+
|
|
3337
|
+
// components/lsp/src/daemon-cli-path.ts
|
|
3338
|
+
import { existsSync as existsSync9, readFileSync as readFileSync6 } from "node:fs";
|
|
3339
|
+
import { createRequire as createRequire2 } from "node:module";
|
|
3340
|
+
import { dirname as dirname6, join as join9 } from "node:path";
|
|
3341
|
+
import { fileURLToPath as fileURLToPath4 } from "node:url";
|
|
3342
|
+
var requireFromHere2 = createRequire2(import.meta.url);
|
|
3343
|
+
var PACKAGE_LSP_DAEMON_CLI = "@code-yeongyu/lsp-daemon/dist/cli.js";
|
|
3344
|
+
var CODEX_LSP_DAEMON_CLI_ENV2 = "CODEX_LSP_DAEMON_CLI";
|
|
3345
|
+
var CODEX_LSP_DAEMON_VERSION_ENV2 = "CODEX_LSP_DAEMON_VERSION";
|
|
3346
|
+
function ensureLspDaemonCliEnv(env = process.env) {
|
|
3347
|
+
const configuredCli = env[CODEX_LSP_DAEMON_CLI_ENV2]?.trim();
|
|
3348
|
+
const resolution = configuredCli ? resolveConfiguredLspDaemonCli(configuredCli) : resolveLspDaemonCli();
|
|
3349
|
+
if (!configuredCli)
|
|
3350
|
+
env[CODEX_LSP_DAEMON_CLI_ENV2] = resolution.cliPath;
|
|
3351
|
+
if (!env[CODEX_LSP_DAEMON_VERSION_ENV2]?.trim() && resolution.version !== null) {
|
|
3352
|
+
env[CODEX_LSP_DAEMON_VERSION_ENV2] = resolution.version;
|
|
3353
|
+
}
|
|
3354
|
+
}
|
|
3355
|
+
function resolveLspDaemonCliPath() {
|
|
3356
|
+
return resolveLspDaemonCli().cliPath;
|
|
3357
|
+
}
|
|
3358
|
+
function resolveLspDaemonCli() {
|
|
3359
|
+
const packageCli = resolvePackageLspDaemonCliPath();
|
|
3360
|
+
if (packageCli !== null)
|
|
3361
|
+
return resolveConfiguredLspDaemonCli(packageCli);
|
|
3362
|
+
const bundledCli = fileURLToPath4(new URL("../../lsp-daemon/dist/cli.js", import.meta.url));
|
|
3363
|
+
if (existsSync9(bundledCli))
|
|
3364
|
+
return resolveConfiguredLspDaemonCli(bundledCli);
|
|
3365
|
+
return resolveConfiguredLspDaemonCli(bundledCli);
|
|
3366
|
+
}
|
|
3367
|
+
function resolvePackageLspDaemonCliPath() {
|
|
3368
|
+
try {
|
|
3369
|
+
return requireFromHere2.resolve(PACKAGE_LSP_DAEMON_CLI);
|
|
3370
|
+
} catch {
|
|
3371
|
+
return null;
|
|
3372
|
+
}
|
|
3373
|
+
}
|
|
3374
|
+
function resolveConfiguredLspDaemonCli(cliPath) {
|
|
3375
|
+
return {
|
|
3376
|
+
cliPath,
|
|
3377
|
+
version: readDaemonPackageVersion(cliPath)
|
|
3378
|
+
};
|
|
3379
|
+
}
|
|
3380
|
+
function readDaemonPackageVersion(cliPath) {
|
|
3381
|
+
try {
|
|
3382
|
+
const parsed = JSON.parse(readFileSync6(join9(dirname6(cliPath), "package.json"), "utf8"));
|
|
3383
|
+
if (isRecord4(parsed) && typeof parsed["version"] === "string" && parsed["version"].length > 0) {
|
|
3384
|
+
return parsed["version"];
|
|
3385
|
+
}
|
|
3386
|
+
} catch {}
|
|
3387
|
+
return null;
|
|
3388
|
+
}
|
|
3389
|
+
function isRecord4(value) {
|
|
3390
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
3391
|
+
}
|
|
3326
3392
|
|
|
3327
3393
|
// components/lsp/src/lsp-session-state.ts
|
|
3328
|
-
import { mkdirSync as mkdirSync4, readFileSync as
|
|
3394
|
+
import { mkdirSync as mkdirSync4, readFileSync as readFileSync8, writeFileSync as writeFileSync3 } from "node:fs";
|
|
3329
3395
|
import { homedir as homedir4 } from "node:os";
|
|
3330
|
-
import { dirname as
|
|
3396
|
+
import { dirname as dirname8, extname as extname2, join as join11 } from "node:path";
|
|
3331
3397
|
function sessionIdFrom(input) {
|
|
3332
3398
|
return typeof input.session_id === "string" && input.session_id.length > 0 ? input.session_id : undefined;
|
|
3333
3399
|
}
|
|
@@ -3374,23 +3440,23 @@ function isLspDaemonUnreachableDiagnostics(diagnostics) {
|
|
|
3374
3440
|
return diagnostics.includes("LSP daemon unreachable");
|
|
3375
3441
|
}
|
|
3376
3442
|
function sessionStatePath(sessionId) {
|
|
3377
|
-
const root = process.env["PLUGIN_DATA"] ??
|
|
3378
|
-
return
|
|
3443
|
+
const root = process.env["PLUGIN_DATA"] ?? join11(homedir4(), ".codex", "codex-lsp");
|
|
3444
|
+
return join11(root, "sessions", `${safePathSegment(sessionId)}.json`);
|
|
3379
3445
|
}
|
|
3380
3446
|
function readSessionState(path) {
|
|
3381
3447
|
try {
|
|
3382
|
-
const parsed = JSON.parse(
|
|
3448
|
+
const parsed = JSON.parse(readFileSync8(path, "utf8"));
|
|
3383
3449
|
if (isLspSessionState(parsed))
|
|
3384
3450
|
return parsed;
|
|
3385
3451
|
return emptyState();
|
|
3386
3452
|
} catch (error) {
|
|
3387
|
-
if (error instanceof SyntaxError ||
|
|
3453
|
+
if (error instanceof SyntaxError || isRecord7(error) && error["code"] === "ENOENT")
|
|
3388
3454
|
return emptyState();
|
|
3389
3455
|
throw error;
|
|
3390
3456
|
}
|
|
3391
3457
|
}
|
|
3392
3458
|
function writeSessionState(path, state) {
|
|
3393
|
-
mkdirSync4(
|
|
3459
|
+
mkdirSync4(dirname8(path), { recursive: true });
|
|
3394
3460
|
writeFileSync3(path, `${JSON.stringify(state)}
|
|
3395
3461
|
`);
|
|
3396
3462
|
}
|
|
@@ -3405,12 +3471,12 @@ function safePathSegment(value) {
|
|
|
3405
3471
|
return value.replace(/[^A-Za-z0-9._-]/g, "_").slice(0, 120) || "unknown-session";
|
|
3406
3472
|
}
|
|
3407
3473
|
function isLspSessionState(value) {
|
|
3408
|
-
if (!
|
|
3474
|
+
if (!isRecord7(value) || !Array.isArray(value["unavailableExtensions"]))
|
|
3409
3475
|
return false;
|
|
3410
3476
|
const postCompactProbePending = value["postCompactProbePending"];
|
|
3411
3477
|
return value["unavailableExtensions"].every((item) => typeof item === "string") && (postCompactProbePending === undefined || typeof postCompactProbePending === "boolean");
|
|
3412
3478
|
}
|
|
3413
|
-
function
|
|
3479
|
+
function isRecord7(value) {
|
|
3414
3480
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
3415
3481
|
}
|
|
3416
3482
|
|
|
@@ -3421,7 +3487,7 @@ function extractMutatedFilePaths(input) {
|
|
|
3421
3487
|
return [];
|
|
3422
3488
|
if (isFailedToolResponse(input.tool_response))
|
|
3423
3489
|
return [];
|
|
3424
|
-
const toolInput =
|
|
3490
|
+
const toolInput = isRecord9(input.tool_input) ? input.tool_input : {};
|
|
3425
3491
|
const paths = new Set;
|
|
3426
3492
|
addStringValue(paths, toolInput["path"]);
|
|
3427
3493
|
addStringValue(paths, toolInput["filePath"]);
|
|
@@ -3440,7 +3506,7 @@ function isMutationTool(value) {
|
|
|
3440
3506
|
return MUTATION_TOOL_NAMES.has(value.toLowerCase());
|
|
3441
3507
|
}
|
|
3442
3508
|
function isFailedToolResponse(value) {
|
|
3443
|
-
if (!
|
|
3509
|
+
if (!isRecord9(value))
|
|
3444
3510
|
return false;
|
|
3445
3511
|
return value["isError"] === true || value["is_error"] === true || value["error"] === true || value["status"] === "error";
|
|
3446
3512
|
}
|
|
@@ -3483,7 +3549,7 @@ function addPatchFiles(paths, value) {
|
|
|
3483
3549
|
if (!Array.isArray(value))
|
|
3484
3550
|
return;
|
|
3485
3551
|
for (const item of value) {
|
|
3486
|
-
if (!
|
|
3552
|
+
if (!isRecord9(item))
|
|
3487
3553
|
continue;
|
|
3488
3554
|
addStringValue(paths, item["path"]);
|
|
3489
3555
|
addStringValue(paths, item["filePath"]);
|
|
@@ -3492,7 +3558,7 @@ function addPatchFiles(paths, value) {
|
|
|
3492
3558
|
addStringValue(paths, item["move_path"]);
|
|
3493
3559
|
}
|
|
3494
3560
|
}
|
|
3495
|
-
function
|
|
3561
|
+
function isRecord9(value) {
|
|
3496
3562
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
3497
3563
|
}
|
|
3498
3564
|
|
|
@@ -3514,6 +3580,7 @@ var CONTEXT_PRESSURE_MARKERS = [
|
|
|
3514
3580
|
"long threads and multiple compactions"
|
|
3515
3581
|
];
|
|
3516
3582
|
async function runLspDiagnosticsText(filePath) {
|
|
3583
|
+
ensureLspDaemonCliEnv();
|
|
3517
3584
|
const result = await callDiagnosticsViaDaemon(filePath, { context: currentRequestContext() });
|
|
3518
3585
|
return result.content.map((block) => block.text).join(`
|
|
3519
3586
|
`);
|
|
@@ -3650,7 +3717,7 @@ function isContextPressureTranscript(transcriptPath) {
|
|
|
3650
3717
|
if (typeof transcriptPath !== "string")
|
|
3651
3718
|
return false;
|
|
3652
3719
|
try {
|
|
3653
|
-
return hasContextPressureMarker(
|
|
3720
|
+
return hasContextPressureMarker(readFileSync9(transcriptPath, "utf8"));
|
|
3654
3721
|
} catch (error) {
|
|
3655
3722
|
if (error instanceof Error)
|
|
3656
3723
|
return false;
|
|
@@ -3675,7 +3742,7 @@ function limitHookText(text2, maxChars) {
|
|
|
3675
3742
|
function isCleanDiagnostics(diagnostics) {
|
|
3676
3743
|
return diagnostics.length === 0 || diagnostics === CLEAN_DIAGNOSTICS_TEXT || diagnostics.startsWith(UNSUPPORTED_EXTENSION_TEXT);
|
|
3677
3744
|
}
|
|
3678
|
-
function
|
|
3745
|
+
function isRecord10(value) {
|
|
3679
3746
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
3680
3747
|
}
|
|
3681
3748
|
|
|
@@ -3692,7 +3759,7 @@ async function runHookCli(runHook, stdin) {
|
|
|
3692
3759
|
if (!raw.trim())
|
|
3693
3760
|
return;
|
|
3694
3761
|
const parsed = JSON.parse(raw);
|
|
3695
|
-
const input =
|
|
3762
|
+
const input = isRecord10(parsed) ? parsed : {};
|
|
3696
3763
|
const output = await runHook(input);
|
|
3697
3764
|
if (output)
|
|
3698
3765
|
process.stdout.write(output);
|
|
@@ -3714,8 +3781,6 @@ async function readStdin(stdin) {
|
|
|
3714
3781
|
}
|
|
3715
3782
|
|
|
3716
3783
|
// components/lsp/src/cli.ts
|
|
3717
|
-
var require2 = createRequire2(import.meta.url);
|
|
3718
|
-
var PACKAGE_LSP_MCP_CLI = "@code-yeongyu/lsp-daemon/dist/cli.js";
|
|
3719
3784
|
async function main() {
|
|
3720
3785
|
const [command = "mcp", subcommand = ""] = argv.slice(2);
|
|
3721
3786
|
if (command === "hook" && subcommand === "post-tool-use") {
|
|
@@ -3740,7 +3805,7 @@ main().catch((error) => {
|
|
|
3740
3805
|
process.exitCode = 1;
|
|
3741
3806
|
});
|
|
3742
3807
|
async function runPackageLspMcpCli() {
|
|
3743
|
-
const cliPath =
|
|
3808
|
+
const cliPath = resolveLspDaemonCliPath();
|
|
3744
3809
|
const child = spawn3(execPath2, [cliPath, "mcp"], { stdio: "inherit" });
|
|
3745
3810
|
await new Promise((resolve6, reject) => {
|
|
3746
3811
|
child.once("error", reject);
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { readFileSync } from "node:fs";
|
|
2
2
|
import { callDiagnosticsViaDaemon, currentRequestContext } from "@code-yeongyu/lsp-daemon";
|
|
3
|
+
import { ensureLspDaemonCliEnv } from "./daemon-cli-path.js";
|
|
3
4
|
import { isLspDaemonUnreachableDiagnostics, isUnavailableLspDiagnostics, markLspSessionCompacted, recordLspDiagnosticsObservations, sessionIdFrom, shouldSkipUnavailableLspDiagnostics, } from "./lsp-session-state.js";
|
|
4
5
|
import { extractMutatedFilePaths } from "./mutated-file-paths.js";
|
|
5
6
|
export { extractMutatedFilePaths } from "./mutated-file-paths.js";
|
|
@@ -20,6 +21,7 @@ const CONTEXT_PRESSURE_MARKERS = [
|
|
|
20
21
|
"long threads and multiple compactions",
|
|
21
22
|
];
|
|
22
23
|
export async function runLspDiagnosticsText(filePath) {
|
|
24
|
+
ensureLspDaemonCliEnv();
|
|
23
25
|
const result = await callDiagnosticsViaDaemon(filePath, { context: currentRequestContext() });
|
|
24
26
|
return result.content.map((block) => block.text).join("\n");
|
|
25
27
|
}
|