oh-my-opencode 4.17.1 → 4.18.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/SKILL.md +2 -0
- package/.agents/skills/codex-qa/scripts/lsp-e2e.sh +3654 -0
- package/.agents/skills/opencode-qa/scripts/lsp-e2e.sh +3071 -0
- package/.agents/skills/work-with-pr/SKILL.md +16 -37
- package/.agents/skills/work-with-pr-workspace/evals/evals.json +3 -3
- package/.opencode/skills/work-with-pr/SKILL.md +16 -37
- package/.opencode/skills/work-with-pr-workspace/evals/evals.json +3 -3
- package/dist/cli/get-local-version/types.d.ts +1 -1
- package/dist/cli/index.js +498 -165
- package/dist/cli-node/index.js +498 -165
- package/dist/index.js +425 -392
- package/dist/skills/frontend/SKILL.md +1 -1
- package/dist/skills/frontend/references/design/README.md +9 -0
- package/dist/skills/frontend/references/design/design-system-architecture.md +4 -2
- package/dist/skills/frontend/references/design/layout-skill.md +107 -0
- package/dist/skills/programming/SKILL.md +12 -2
- package/package.json +17 -16
- package/packages/lsp-core/package.json +4 -0
- package/packages/lsp-core/src/index.ts +1 -0
- package/packages/lsp-core/src/lsp/cleanup-errors.test.ts +18 -0
- package/packages/lsp-core/src/lsp/cleanup-errors.ts +12 -3
- package/packages/lsp-core/src/lsp/client-diagnostics-freshness.integration.test.ts +261 -0
- package/packages/lsp-core/src/lsp/client-wrapper.test.ts +63 -0
- package/packages/lsp-core/src/lsp/client-wrapper.ts +35 -5
- package/packages/lsp-core/src/lsp/client.ts +262 -80
- package/packages/lsp-core/src/lsp/config-loader.ts +5 -17
- package/packages/lsp-core/src/lsp/connection.ts +12 -6
- package/packages/lsp-core/src/lsp/directory-diagnostics.test.ts +104 -0
- package/packages/lsp-core/src/lsp/directory-diagnostics.ts +60 -27
- package/packages/lsp-core/src/lsp/errors.ts +11 -0
- package/packages/lsp-core/src/lsp/fixtures/diagnostics-freshness-contract-probe.ts +283 -0
- package/packages/lsp-core/src/lsp/fixtures/workspace-edit-contract-probe.ts +196 -0
- package/packages/lsp-core/src/lsp/fixtures/workspace-edit-server.mjs +215 -0
- package/packages/lsp-core/src/lsp/formatters.ts +3 -0
- package/packages/lsp-core/src/lsp/json-rpc-connection-cancellation.test.ts +97 -0
- package/packages/lsp-core/src/lsp/json-rpc-connection.ts +73 -5
- package/packages/lsp-core/src/lsp/server-install-state.ts +3 -6
- package/packages/lsp-core/src/lsp/transport-protocol.ts +52 -0
- package/packages/lsp-core/src/lsp/transport.ts +96 -70
- package/packages/lsp-core/src/lsp/workspace-apply-edit-failure.ts +19 -0
- package/packages/lsp-core/src/lsp/workspace-apply-edit-lease.integration.test.ts +214 -0
- package/packages/lsp-core/src/lsp/workspace-apply-edit-sync.integration.test.ts +113 -0
- package/packages/lsp-core/src/lsp/workspace-apply-edit-test-support.ts +163 -0
- package/packages/lsp-core/src/lsp/workspace-apply-edit.integration.test.ts +163 -0
- package/packages/lsp-core/src/lsp/workspace-document-state.test.ts +67 -0
- package/packages/lsp-core/src/lsp/workspace-document-state.ts +368 -0
- package/packages/lsp-core/src/lsp/workspace-edit-adversarial.test.ts +113 -0
- package/packages/lsp-core/src/lsp/workspace-edit-commit.test.ts +140 -0
- package/packages/lsp-core/src/lsp/workspace-edit-commit.ts +220 -0
- package/packages/lsp-core/src/lsp/workspace-edit-contract-evidence.test.ts +56 -0
- package/packages/lsp-core/src/lsp/workspace-edit-contract-evidence.ts +30 -0
- package/packages/lsp-core/src/lsp/workspace-edit-fingerprint.ts +44 -0
- package/packages/lsp-core/src/lsp/workspace-edit-options.test.ts +147 -0
- package/packages/lsp-core/src/lsp/workspace-edit-parse-helpers.ts +59 -0
- package/packages/lsp-core/src/lsp/workspace-edit-parser.ts +130 -0
- package/packages/lsp-core/src/lsp/workspace-edit-path.ts +98 -0
- package/packages/lsp-core/src/lsp/workspace-edit-plan-types.ts +60 -0
- package/packages/lsp-core/src/lsp/workspace-edit-plan.ts +73 -0
- package/packages/lsp-core/src/lsp/workspace-edit-prevalidation.test.ts +174 -0
- package/packages/lsp-core/src/lsp/workspace-edit-resource-parser.ts +89 -0
- package/packages/lsp-core/src/lsp/workspace-edit-simulation.ts +183 -0
- package/packages/lsp-core/src/lsp/workspace-edit-snapshot.ts +53 -0
- package/packages/lsp-core/src/lsp/workspace-edit-text.ts +125 -0
- package/packages/lsp-core/src/lsp/workspace-edit-types.ts +121 -0
- package/packages/lsp-core/src/lsp/workspace-edit.characterization.test.ts +95 -0
- package/packages/lsp-core/src/lsp/workspace-edit.ts +49 -200
- package/packages/lsp-core/src/lsp/workspace-mutation-controller.ts +182 -0
- package/packages/lsp-core/src/mcp.ts +18 -7
- package/packages/lsp-core/src/missing-dependency-result.test.ts +105 -0
- package/packages/lsp-core/src/missing-dependency-result.ts +57 -0
- package/packages/lsp-core/src/post-edit/index.ts +1 -0
- package/packages/lsp-core/src/post-edit/orchestration.test.ts +157 -0
- package/packages/lsp-core/src/post-edit/orchestration.ts +178 -0
- package/packages/lsp-core/src/request-context.test.ts +171 -0
- package/packages/lsp-core/src/request-context.ts +222 -9
- package/packages/lsp-core/src/tool-surface.test.ts +4 -1
- package/packages/lsp-core/src/tools/diagnostics.ts +32 -13
- package/packages/lsp-core/src/tools/navigation.ts +12 -12
- package/packages/lsp-core/src/tools/rename.ts +10 -15
- package/packages/lsp-core/src/tools/symbols.ts +11 -11
- package/packages/lsp-core/src/tools/types.ts +2 -1
- package/packages/lsp-daemon/dist/cli.js +3114 -747
- package/packages/lsp-daemon/dist/client.d.ts +105 -0
- package/packages/lsp-daemon/dist/client.js +5851 -0
- package/packages/lsp-daemon/dist/daemon-client.d.ts +11 -6
- package/packages/lsp-daemon/dist/daemon-client.js +113 -30
- package/packages/lsp-daemon/dist/daemon-server.d.ts +1 -0
- package/packages/lsp-daemon/dist/daemon-server.js +40 -15
- package/packages/lsp-daemon/dist/ensure-daemon.d.ts +8 -7
- package/packages/lsp-daemon/dist/ensure-daemon.js +67 -44
- package/packages/lsp-daemon/dist/index.d.ts +2 -2
- package/packages/lsp-daemon/dist/index.js +2862 -754
- package/packages/lsp-daemon/dist/ipc-protocol.d.ts +46 -0
- package/packages/lsp-daemon/dist/ipc-protocol.js +187 -0
- package/packages/lsp-daemon/dist/lock.js +14 -4
- package/packages/lsp-daemon/dist/ownership.d.ts +49 -0
- package/packages/lsp-daemon/dist/ownership.js +168 -0
- package/packages/lsp-daemon/dist/paths.d.ts +33 -9
- package/packages/lsp-daemon/dist/paths.js +72 -33
- package/packages/lsp-daemon/dist/proxy.d.ts +3 -0
- package/packages/lsp-daemon/dist/proxy.js +54 -3
- package/packages/lsp-daemon/dist/request-routing.d.ts +7 -2
- package/packages/lsp-daemon/dist/request-routing.js +71 -22
- package/packages/lsp-daemon/dist/run-daemon.js +9 -2
- package/packages/lsp-daemon/dist/runtime-contract.d.ts +21 -0
- package/packages/lsp-daemon/dist/runtime-contract.js +58 -0
- package/packages/lsp-daemon/dist/socket-jsonrpc.js +6 -1
- package/packages/lsp-daemon/package.json +12 -3
- package/packages/lsp-tools-mcp/dist/cli.js +2115 -442
- package/packages/lsp-tools-mcp/dist/lsp/manager.js +1741 -148
- package/packages/lsp-tools-mcp/dist/mcp.js +2127 -454
- package/packages/lsp-tools-mcp/dist/request-context.js +176 -6
- package/packages/lsp-tools-mcp/dist/tools.js +2118 -446
- package/packages/omo-codex/plugin/.codex-plugin/plugin.json +1 -1
- package/packages/omo-codex/plugin/components/bootstrap/hooks/hooks.json +1 -1
- package/packages/omo-codex/plugin/components/bootstrap/package.json +1 -1
- package/packages/omo-codex/plugin/components/codegraph/package.json +1 -1
- package/packages/omo-codex/plugin/components/comment-checker/hooks/hooks.json +1 -1
- package/packages/omo-codex/plugin/components/comment-checker/package.json +1 -1
- package/packages/omo-codex/plugin/components/git-bash/hooks/hooks.json +2 -2
- package/packages/omo-codex/plugin/components/git-bash/package.json +1 -1
- package/packages/omo-codex/plugin/components/lazycodex-executor-verify/hooks/hooks.json +1 -1
- package/packages/omo-codex/plugin/components/lazycodex-executor-verify/package.json +1 -1
- package/packages/omo-codex/plugin/components/lsp/dist/.omo-runtime-manifest.json +55 -0
- package/packages/omo-codex/plugin/components/lsp/dist/cli.js +2959 -944
- package/packages/omo-codex/plugin/components/lsp/dist/codex-hook-cli.js +0 -4
- package/packages/omo-codex/plugin/components/lsp/dist/codex-hook.d.ts +5 -2
- package/packages/omo-codex/plugin/components/lsp/dist/codex-hook.js +41 -62
- package/packages/omo-codex/plugin/components/lsp/dist/daemon-cli-path.d.ts +1 -1
- package/packages/omo-codex/plugin/components/lsp/dist/daemon-cli-path.js +24 -15
- package/packages/omo-codex/plugin/components/lsp/dist/lsp-session-state.d.ts +3 -7
- package/packages/omo-codex/plugin/components/lsp/dist/lsp-session-state.js +23 -49
- package/packages/omo-codex/plugin/components/lsp/hooks/hooks.json +2 -2
- package/packages/omo-codex/plugin/components/lsp/package.json +3 -2
- package/packages/omo-codex/plugin/components/lsp/scripts/build-lsp-daemon.mjs +31 -1
- package/packages/omo-codex/plugin/components/lsp/scripts/build-lsp-daemon.test.mjs +76 -0
- package/packages/omo-codex/plugin/components/lsp/scripts/build-runtime.mjs +201 -0
- package/packages/omo-codex/plugin/components/lsp/scripts/build-runtime.test.mjs +55 -0
- package/packages/omo-codex/plugin/components/lsp/src/codex-hook-cli.ts +0 -4
- package/packages/omo-codex/plugin/components/lsp/src/codex-hook.ts +49 -71
- package/packages/omo-codex/plugin/components/lsp/src/daemon-cli-path.ts +26 -15
- package/packages/omo-codex/plugin/components/lsp/src/lsp-session-state.ts +26 -64
- package/packages/omo-codex/plugin/components/lsp/test/codex-hook-unavailable.test.ts +16 -17
- package/packages/omo-codex/plugin/components/lsp/test/codex-hook.test.ts +30 -4
- package/packages/omo-codex/plugin/components/lsp/test/package-smoke.test.ts +19 -5
- package/packages/omo-codex/plugin/components/rules/bundled-rules/hephaestus/gpt-5.5.md +1 -1
- package/packages/omo-codex/plugin/components/rules/bundled-rules/hephaestus/gpt-5.6.md +8 -6
- 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/start-work-continuation/directive.md +1 -1
- package/packages/omo-codex/plugin/components/start-work-continuation/hooks/hooks.json +2 -2
- package/packages/omo-codex/plugin/components/start-work-continuation/package.json +1 -1
- package/packages/omo-codex/plugin/components/teammode/hooks/hooks.json +1 -1
- package/packages/omo-codex/plugin/components/teammode/package.json +1 -1
- package/packages/omo-codex/plugin/components/telemetry/hooks/hooks.json +1 -1
- package/packages/omo-codex/plugin/components/telemetry/package.json +1 -1
- package/packages/omo-codex/plugin/components/ultrawork/directive.md +37 -10
- 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/ultrawork/skills/ultrawork/SKILL.md +37 -10
- package/packages/omo-codex/plugin/components/ulw-loop/directive.md +37 -10
- package/packages/omo-codex/plugin/components/ulw-loop/hooks/hooks.json +4 -4
- package/packages/omo-codex/plugin/components/ulw-loop/package.json +1 -1
- package/packages/omo-codex/plugin/components/ulw-loop/skills/ulw-loop/SKILL.md +2 -2
- package/packages/omo-codex/plugin/components/ulw-loop/skills/ulw-loop/references/full-workflow.md +10 -9
- package/packages/omo-codex/plugin/hooks/post-compact-resetting-git-bash-mcp-reminder.json +1 -1
- package/packages/omo-codex/plugin/hooks/post-compact-resetting-lsp-diagnostics-cache.json +1 -1
- package/packages/omo-codex/plugin/hooks/post-compact-resetting-project-rule-cache.json +1 -1
- package/packages/omo-codex/plugin/hooks/post-tool-use-checking-codegraph-init-guidance.json +1 -1
- package/packages/omo-codex/plugin/hooks/post-tool-use-checking-comments.json +1 -1
- package/packages/omo-codex/plugin/hooks/post-tool-use-checking-lsp-diagnostics.json +1 -1
- package/packages/omo-codex/plugin/hooks/post-tool-use-checking-thread-title-hygiene.json +1 -1
- package/packages/omo-codex/plugin/hooks/post-tool-use-matching-project-rules.json +1 -1
- package/packages/omo-codex/plugin/hooks/pre-tool-use-enforcing-unlimited-goal-budget.json +1 -1
- package/packages/omo-codex/plugin/hooks/pre-tool-use-guarding-ulw-loop-spawns.json +1 -1
- package/packages/omo-codex/plugin/hooks/pre-tool-use-recommending-git-bash-mcp.json +1 -1
- package/packages/omo-codex/plugin/hooks/session-start-checking-auto-update.json +1 -1
- package/packages/omo-codex/plugin/hooks/session-start-checking-bootstrap-provisioning.json +1 -1
- package/packages/omo-codex/plugin/hooks/session-start-checking-codegraph-bootstrap.json +1 -1
- package/packages/omo-codex/plugin/hooks/session-start-loading-project-rules.json +1 -1
- package/packages/omo-codex/plugin/hooks/session-start-recording-session-telemetry.json +1 -1
- package/packages/omo-codex/plugin/hooks/stop-checking-start-work-continuation.json +1 -1
- package/packages/omo-codex/plugin/hooks/stop-checking-ulw-loop-resume.json +1 -1
- package/packages/omo-codex/plugin/hooks/subagent-stop-checking-start-work-continuation.json +1 -1
- package/packages/omo-codex/plugin/hooks/subagent-stop-verifying-lazycodex-executor-evidence.json +1 -1
- package/packages/omo-codex/plugin/hooks/user-prompt-submit-checking-ultrawork-trigger.json +1 -1
- package/packages/omo-codex/plugin/hooks/user-prompt-submit-checking-ulw-loop-steering.json +1 -1
- package/packages/omo-codex/plugin/hooks/user-prompt-submit-loading-project-rules.json +1 -1
- package/packages/omo-codex/plugin/package-lock.json +26 -14
- package/packages/omo-codex/plugin/package.json +1 -1
- package/packages/omo-codex/plugin/scripts/build-bundled-mcp-runtimes.mjs +2 -3
- package/packages/omo-codex/plugin/scripts/build-components.mjs +13 -1
- package/packages/omo-codex/plugin/scripts/sync-skills.mjs +1 -1
- package/packages/omo-codex/plugin/skills/frontend/SKILL.md +1 -1
- package/packages/omo-codex/plugin/skills/frontend/references/design/README.md +9 -0
- package/packages/omo-codex/plugin/skills/frontend/references/design/design-system-architecture.md +4 -2
- package/packages/omo-codex/plugin/skills/frontend/references/design/layout-skill.md +107 -0
- package/packages/omo-codex/plugin/skills/programming/SKILL.md +12 -2
- package/packages/omo-codex/plugin/skills/start-work/SKILL.md +1 -1
- package/packages/omo-codex/plugin/skills/ultrawork/SKILL.md +37 -10
- package/packages/omo-codex/plugin/skills/ulw-loop/SKILL.md +2 -2
- package/packages/omo-codex/plugin/skills/ulw-loop/references/full-workflow.md +10 -9
- package/packages/omo-codex/plugin/test/aggregate-build.test.mjs +8 -0
- package/packages/omo-codex/plugin/test/component-bundled-cli.test.mjs +128 -15
- package/packages/omo-codex/plugin/test/install-time-build-runtime.test.mjs +10 -0
- package/packages/omo-codex/plugin/test/lsp-prebuild-layouts.test.mjs +2 -0
- package/packages/omo-codex/plugin/test/sync-skills-test-support.mjs +1 -1
- package/packages/omo-codex/scripts/install-dist/install-local.mjs +351 -74
- package/packages/shared-skills/skills/frontend/SKILL.md +1 -1
- package/packages/shared-skills/skills/frontend/references/design/README.md +9 -0
- package/packages/shared-skills/skills/frontend/references/design/design-system-architecture.md +4 -2
- package/packages/shared-skills/skills/frontend/references/design/layout-skill.md +107 -0
- package/packages/shared-skills/skills/programming/SKILL.md +12 -2
|
@@ -1,19 +1,30 @@
|
|
|
1
|
+
import { existsSync, realpathSync } from "node:fs";
|
|
2
|
+
import { basename, delimiter, dirname, isAbsolute } from "node:path";
|
|
1
3
|
import { jsonRpcId, runJsonRpcStdioServer, successResponse } from "@oh-my-opencode/mcp-stdio-core";
|
|
2
4
|
import { isPlainRecord } from "@oh-my-opencode/mcp-stdio-core/record";
|
|
3
5
|
import { handleLspMcpRequest } from "@oh-my-opencode/lsp-core/mcp";
|
|
4
|
-
import {
|
|
6
|
+
import { createStandaloneMcpRequestContext, runWithRequestContext } from "@oh-my-opencode/lsp-core/request-context";
|
|
7
|
+
import { callToolViaDaemon } from "./daemon-client.js";
|
|
5
8
|
import { daemonPaths } from "./paths.js";
|
|
6
9
|
export async function runMcpStdioProxy(options = {}) {
|
|
7
10
|
const input = options.input ?? process.stdin;
|
|
8
11
|
const output = options.output ?? process.stdout;
|
|
9
12
|
const paths = options.paths ?? daemonPaths();
|
|
10
|
-
const
|
|
13
|
+
const env = options.env ?? process.env;
|
|
14
|
+
const cwd = options.cwd ?? inferOpenCodeProjectCwd(env["LSP_TOOLS_MCP_PROJECT_CONFIG"]);
|
|
15
|
+
const contextEnv = cwd === undefined ? env : canonicalizeContextEnv(env);
|
|
16
|
+
const contextInput = {
|
|
17
|
+
env: contextEnv,
|
|
18
|
+
...(cwd === undefined ? {} : { cwd }),
|
|
19
|
+
...(options.homeDir === undefined ? {} : { homeDir: options.homeDir }),
|
|
20
|
+
};
|
|
21
|
+
const context = options.context ?? createStandaloneMcpRequestContext(contextInput);
|
|
11
22
|
const callOptions = { paths, context, ...(options.ensure ? { ensure: options.ensure } : {}) };
|
|
12
23
|
await runJsonRpcStdioServer({
|
|
13
24
|
input,
|
|
14
25
|
output,
|
|
15
26
|
idleTimeoutMs: 0,
|
|
16
|
-
handler: handleProxyRequest,
|
|
27
|
+
handler: (request, requestOptions) => runWithRequestContext(context, () => handleProxyRequest(request, requestOptions)),
|
|
17
28
|
handlerOptions: callOptions,
|
|
18
29
|
onHandlerError: (error) => {
|
|
19
30
|
process.stderr.write(`[lsp-daemon] proxy error: ${error instanceof Error ? error.message : String(error)}\n`);
|
|
@@ -36,3 +47,43 @@ function asToolCall(parsed) {
|
|
|
36
47
|
const args = params["arguments"];
|
|
37
48
|
return { id: jsonRpcId(parsed["id"]), name: params["name"], args: isPlainRecord(args) ? args : {} };
|
|
38
49
|
}
|
|
50
|
+
function inferOpenCodeProjectCwd(projectConfigEnv) {
|
|
51
|
+
if (!projectConfigEnv)
|
|
52
|
+
return undefined;
|
|
53
|
+
for (const entry of projectConfigEnv.split(delimiter)) {
|
|
54
|
+
const projectRoot = projectRootFromOpenCodeConfigPath(entry);
|
|
55
|
+
if (projectRoot)
|
|
56
|
+
return projectRoot;
|
|
57
|
+
}
|
|
58
|
+
return undefined;
|
|
59
|
+
}
|
|
60
|
+
function canonicalizeContextEnv(env) {
|
|
61
|
+
return {
|
|
62
|
+
...env,
|
|
63
|
+
LSP_TOOLS_MCP_PROJECT_CONFIG: canonicalizePathList(env["LSP_TOOLS_MCP_PROJECT_CONFIG"]),
|
|
64
|
+
LSP_TOOLS_MCP_USER_CONFIG: canonicalizePath(env["LSP_TOOLS_MCP_USER_CONFIG"]),
|
|
65
|
+
LSP_TOOLS_MCP_INSTALL_DECISIONS: canonicalizePath(env["LSP_TOOLS_MCP_INSTALL_DECISIONS"]),
|
|
66
|
+
};
|
|
67
|
+
}
|
|
68
|
+
function canonicalizePathList(value) {
|
|
69
|
+
if (value === undefined)
|
|
70
|
+
return undefined;
|
|
71
|
+
return value
|
|
72
|
+
.split(delimiter)
|
|
73
|
+
.map((entry) => canonicalizePath(entry) ?? entry)
|
|
74
|
+
.join(delimiter);
|
|
75
|
+
}
|
|
76
|
+
function canonicalizePath(value) {
|
|
77
|
+
if (value === undefined || !isAbsolute(value) || !existsSync(value))
|
|
78
|
+
return value;
|
|
79
|
+
return realpathSync(value);
|
|
80
|
+
}
|
|
81
|
+
function projectRootFromOpenCodeConfigPath(path) {
|
|
82
|
+
if (basename(path) !== "lsp.json" && basename(path) !== "lsp-client.json")
|
|
83
|
+
return undefined;
|
|
84
|
+
const configDir = dirname(path);
|
|
85
|
+
const configDirName = basename(configDir);
|
|
86
|
+
if (configDirName !== ".opencode" && configDirName !== ".omo")
|
|
87
|
+
return undefined;
|
|
88
|
+
return dirname(configDir);
|
|
89
|
+
}
|
|
@@ -1,9 +1,14 @@
|
|
|
1
|
-
import { type JsonRpcResponse } from "@oh-my-opencode/lsp-core/mcp";
|
|
2
1
|
import { type RequestContext } from "@oh-my-opencode/lsp-core/request-context";
|
|
2
|
+
import type { DaemonOwner } from "./ownership.js";
|
|
3
3
|
export declare const CONTEXT_KEY = "_context";
|
|
4
4
|
export interface RoutedRequest {
|
|
5
5
|
input: unknown;
|
|
6
6
|
context: RequestContext | undefined;
|
|
7
7
|
}
|
|
8
8
|
export declare function extractRequestContext(raw: unknown): RoutedRequest;
|
|
9
|
-
export
|
|
9
|
+
export type DaemonRouteState = {
|
|
10
|
+
readonly token: string;
|
|
11
|
+
readonly owner: DaemonOwner;
|
|
12
|
+
readonly activeRequests?: Map<string, AbortController>;
|
|
13
|
+
};
|
|
14
|
+
export declare function handleDaemonMessage(raw: unknown, state: DaemonRouteState): Promise<unknown>;
|
|
@@ -1,42 +1,91 @@
|
|
|
1
1
|
import { handleLspMcpRequest } from "@oh-my-opencode/lsp-core/mcp";
|
|
2
|
-
import { runWithRequestContext } from "@oh-my-opencode/lsp-core/request-context";
|
|
2
|
+
import { parseLspRequestContext, runWithRequestContext } from "@oh-my-opencode/lsp-core/request-context";
|
|
3
3
|
import { isPlainRecord } from "@oh-my-opencode/mcp-stdio-core/record";
|
|
4
|
+
import { authenticateMessage, OMO_DAEMON_PROTOCOL_VERSION } from "./ipc-protocol.js";
|
|
4
5
|
export const CONTEXT_KEY = "_context";
|
|
6
|
+
class InvalidDaemonRequestError extends Error {
|
|
7
|
+
constructor() {
|
|
8
|
+
super(...arguments);
|
|
9
|
+
this.name = "InvalidDaemonRequestError";
|
|
10
|
+
}
|
|
11
|
+
}
|
|
5
12
|
export function extractRequestContext(raw) {
|
|
6
13
|
if (!isPlainRecord(raw) || raw["method"] !== "tools/call")
|
|
7
14
|
return { input: raw, context: undefined };
|
|
8
15
|
const params = raw["params"];
|
|
9
16
|
if (!isPlainRecord(params))
|
|
10
|
-
|
|
17
|
+
throw new InvalidDaemonRequestError("Daemon tools/call params must be an object.");
|
|
11
18
|
const args = params["arguments"];
|
|
12
19
|
if (!isPlainRecord(args))
|
|
13
|
-
|
|
20
|
+
throw new InvalidDaemonRequestError("Daemon tools/call arguments must be an object.");
|
|
21
|
+
if (!Object.hasOwn(args, CONTEXT_KEY)) {
|
|
22
|
+
throw new InvalidDaemonRequestError("Daemon tools/call arguments must include _context.");
|
|
23
|
+
}
|
|
14
24
|
const context = parseContext(args[CONTEXT_KEY]);
|
|
15
|
-
if (!context)
|
|
16
|
-
return { input: raw, context: undefined };
|
|
17
25
|
const cleanedArgs = { ...args };
|
|
18
26
|
delete cleanedArgs[CONTEXT_KEY];
|
|
19
27
|
const cleaned = { ...raw, params: { ...params, arguments: cleanedArgs } };
|
|
20
28
|
return { input: cleaned, context };
|
|
21
29
|
}
|
|
22
|
-
export function handleDaemonMessage(raw) {
|
|
23
|
-
const
|
|
24
|
-
if (
|
|
25
|
-
return
|
|
26
|
-
|
|
30
|
+
export function handleDaemonMessage(raw, state) {
|
|
31
|
+
const authenticated = authenticateMessage(raw, state.token);
|
|
32
|
+
if ("error" in authenticated)
|
|
33
|
+
return Promise.resolve(authenticated);
|
|
34
|
+
if (authenticated.method === "omo/ping") {
|
|
35
|
+
return Promise.resolve({
|
|
36
|
+
jsonrpc: "2.0",
|
|
37
|
+
id: authenticated.id,
|
|
38
|
+
result: { protocolVersion: OMO_DAEMON_PROTOCOL_VERSION, ...state.owner },
|
|
39
|
+
});
|
|
40
|
+
}
|
|
41
|
+
if (authenticated.method === "$/cancelRequest") {
|
|
42
|
+
const targetId = cancellationTargetId(authenticated.input);
|
|
43
|
+
if (targetId !== undefined)
|
|
44
|
+
state.activeRequests?.get(String(targetId))?.abort();
|
|
45
|
+
return Promise.resolve(undefined);
|
|
46
|
+
}
|
|
47
|
+
let routed;
|
|
48
|
+
try {
|
|
49
|
+
routed = extractRequestContext(authenticated.input);
|
|
50
|
+
}
|
|
51
|
+
catch (error) {
|
|
52
|
+
const message = error instanceof Error ? error.message : "invalid daemon request";
|
|
53
|
+
return Promise.resolve({
|
|
54
|
+
jsonrpc: "2.0",
|
|
55
|
+
id: authenticated.id,
|
|
56
|
+
error: { code: -32602, message, data: { code: "invalid_daemon_request" } },
|
|
57
|
+
});
|
|
58
|
+
}
|
|
59
|
+
const { input, context } = routed;
|
|
60
|
+
const key = routeRequestKey(authenticated.id);
|
|
61
|
+
if (key === undefined || !state.activeRequests) {
|
|
62
|
+
if (context)
|
|
63
|
+
return runWithRequestContext(context, () => handleLspMcpRequest(input));
|
|
64
|
+
return handleLspMcpRequest(input);
|
|
65
|
+
}
|
|
66
|
+
const controller = new AbortController();
|
|
67
|
+
state.activeRequests.set(key, controller);
|
|
68
|
+
const options = { signal: controller.signal };
|
|
69
|
+
const run = context
|
|
70
|
+
? runWithRequestContext(context, () => handleLspMcpRequest(input, options))
|
|
71
|
+
: handleLspMcpRequest(input, options);
|
|
72
|
+
return run.finally(() => {
|
|
73
|
+
if (state.activeRequests?.get(key) === controller)
|
|
74
|
+
state.activeRequests.delete(key);
|
|
75
|
+
});
|
|
27
76
|
}
|
|
28
|
-
function
|
|
29
|
-
|
|
77
|
+
function routeRequestKey(id) {
|
|
78
|
+
return typeof id === "string" || typeof id === "number" ? String(id) : undefined;
|
|
79
|
+
}
|
|
80
|
+
function cancellationTargetId(input) {
|
|
81
|
+
const params = input["params"];
|
|
82
|
+
if (!isPlainRecord(params))
|
|
30
83
|
return undefined;
|
|
31
|
-
const
|
|
32
|
-
|
|
33
|
-
if (typeof cwd === "string")
|
|
34
|
-
context.cwd = cwd;
|
|
35
|
-
const env = value["env"];
|
|
36
|
-
if (isStringRecord(env))
|
|
37
|
-
context.env = env;
|
|
38
|
-
return context.cwd === undefined && context.env === undefined ? undefined : context;
|
|
84
|
+
const id = params["id"];
|
|
85
|
+
return typeof id === "string" || typeof id === "number" ? id : undefined;
|
|
39
86
|
}
|
|
40
|
-
function
|
|
41
|
-
|
|
87
|
+
function parseContext(value) {
|
|
88
|
+
if (!isPlainRecord(value))
|
|
89
|
+
throw new InvalidDaemonRequestError("LSP request _context must be an object.");
|
|
90
|
+
return parseLspRequestContext(value);
|
|
42
91
|
}
|
|
@@ -1,9 +1,16 @@
|
|
|
1
|
-
import { startDaemonServer } from "./daemon-server.js";
|
|
1
|
+
import { DaemonAlreadyRunningError, startDaemonServer } from "./daemon-server.js";
|
|
2
2
|
import { daemonPaths } from "./paths.js";
|
|
3
3
|
export async function runDaemon() {
|
|
4
4
|
process.on("uncaughtException", (error) => logNonFatal("uncaughtException", error));
|
|
5
5
|
process.on("unhandledRejection", (reason) => logNonFatal("unhandledRejection", reason));
|
|
6
|
-
|
|
6
|
+
try {
|
|
7
|
+
await startDaemonServer(daemonPaths());
|
|
8
|
+
}
|
|
9
|
+
catch (error) {
|
|
10
|
+
if (error instanceof DaemonAlreadyRunningError)
|
|
11
|
+
return;
|
|
12
|
+
throw error;
|
|
13
|
+
}
|
|
7
14
|
}
|
|
8
15
|
function logNonFatal(kind, error) {
|
|
9
16
|
const message = error instanceof Error ? (error.stack ?? error.message) : String(error);
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
export declare const OMO_LSP_DAEMON_DIR = "OMO_LSP_DAEMON_DIR";
|
|
2
|
+
export declare const OMO_LSP_DAEMON_CLI = "OMO_LSP_DAEMON_CLI";
|
|
3
|
+
export declare const OMO_LSP_DAEMON_VERSION = "OMO_LSP_DAEMON_VERSION";
|
|
4
|
+
export interface DaemonRuntime {
|
|
5
|
+
readonly cliPath: string;
|
|
6
|
+
readonly version: string;
|
|
7
|
+
}
|
|
8
|
+
export type DaemonRuntimeDefaults = DaemonRuntime;
|
|
9
|
+
export type InvalidRuntimeOverrideReason = "paired_values_required" | "cli_must_be_absolute" | "cli_not_found" | "cli_not_file" | "packaged_cli_must_be_absolute";
|
|
10
|
+
export declare class InvalidRuntimeOverrideError extends Error {
|
|
11
|
+
readonly code = "invalid_runtime_override";
|
|
12
|
+
readonly reason: InvalidRuntimeOverrideReason;
|
|
13
|
+
constructor(reason: InvalidRuntimeOverrideReason, message: string);
|
|
14
|
+
}
|
|
15
|
+
export declare class InvalidDaemonVersionError extends Error {
|
|
16
|
+
readonly code = "invalid_daemon_version";
|
|
17
|
+
readonly version: string;
|
|
18
|
+
constructor(version: string);
|
|
19
|
+
}
|
|
20
|
+
export declare function validateDaemonVersion(version: string): string;
|
|
21
|
+
export declare function resolveDaemonRuntime(env: NodeJS.ProcessEnv, defaults: DaemonRuntimeDefaults): DaemonRuntime;
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
import { statSync } from "node:fs";
|
|
2
|
+
import { isAbsolute } from "node:path";
|
|
3
|
+
export const OMO_LSP_DAEMON_DIR = "OMO_LSP_DAEMON_DIR";
|
|
4
|
+
export const OMO_LSP_DAEMON_CLI = "OMO_LSP_DAEMON_CLI";
|
|
5
|
+
export const OMO_LSP_DAEMON_VERSION = "OMO_LSP_DAEMON_VERSION";
|
|
6
|
+
const DAEMON_VERSION_PATTERN = /^[A-Za-z0-9][A-Za-z0-9._+-]{0,127}$/;
|
|
7
|
+
export class InvalidRuntimeOverrideError extends Error {
|
|
8
|
+
constructor(reason, message) {
|
|
9
|
+
super(message);
|
|
10
|
+
this.code = "invalid_runtime_override";
|
|
11
|
+
this.name = "InvalidRuntimeOverrideError";
|
|
12
|
+
this.reason = reason;
|
|
13
|
+
}
|
|
14
|
+
}
|
|
15
|
+
export class InvalidDaemonVersionError extends Error {
|
|
16
|
+
constructor(version) {
|
|
17
|
+
super("LSP daemon version must match [A-Za-z0-9][A-Za-z0-9._+-]{0,127}");
|
|
18
|
+
this.code = "invalid_daemon_version";
|
|
19
|
+
this.name = "InvalidDaemonVersionError";
|
|
20
|
+
this.version = version;
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
export function validateDaemonVersion(version) {
|
|
24
|
+
if (!DAEMON_VERSION_PATTERN.test(version))
|
|
25
|
+
throw new InvalidDaemonVersionError(version);
|
|
26
|
+
return version;
|
|
27
|
+
}
|
|
28
|
+
export function resolveDaemonRuntime(env, defaults) {
|
|
29
|
+
const cliOverride = env[OMO_LSP_DAEMON_CLI];
|
|
30
|
+
const versionOverride = env[OMO_LSP_DAEMON_VERSION];
|
|
31
|
+
const hasCliOverride = cliOverride !== undefined;
|
|
32
|
+
const hasVersionOverride = versionOverride !== undefined;
|
|
33
|
+
if (hasCliOverride !== hasVersionOverride) {
|
|
34
|
+
throw new InvalidRuntimeOverrideError("paired_values_required", `${OMO_LSP_DAEMON_CLI} and ${OMO_LSP_DAEMON_VERSION} must be set together`);
|
|
35
|
+
}
|
|
36
|
+
if (!hasCliOverride || !hasVersionOverride) {
|
|
37
|
+
if (!isAbsolute(defaults.cliPath)) {
|
|
38
|
+
throw new InvalidRuntimeOverrideError("packaged_cli_must_be_absolute", "Packaged LSP daemon CLI path must be absolute");
|
|
39
|
+
}
|
|
40
|
+
return { cliPath: defaults.cliPath, version: validateDaemonVersion(defaults.version) };
|
|
41
|
+
}
|
|
42
|
+
if (!isAbsolute(cliOverride)) {
|
|
43
|
+
throw new InvalidRuntimeOverrideError("cli_must_be_absolute", `${OMO_LSP_DAEMON_CLI} must be an absolute path to an existing regular file`);
|
|
44
|
+
}
|
|
45
|
+
let cliStats;
|
|
46
|
+
try {
|
|
47
|
+
cliStats = statSync(cliOverride);
|
|
48
|
+
}
|
|
49
|
+
catch (error) {
|
|
50
|
+
if (!(error instanceof Error))
|
|
51
|
+
throw error;
|
|
52
|
+
throw new InvalidRuntimeOverrideError("cli_not_found", `${OMO_LSP_DAEMON_CLI} must name an existing regular file`);
|
|
53
|
+
}
|
|
54
|
+
if (!cliStats.isFile()) {
|
|
55
|
+
throw new InvalidRuntimeOverrideError("cli_not_file", `${OMO_LSP_DAEMON_CLI} must name an existing regular file`);
|
|
56
|
+
}
|
|
57
|
+
return { cliPath: cliOverride, version: validateDaemonVersion(versionOverride) };
|
|
58
|
+
}
|
|
@@ -15,7 +15,12 @@ export function createLineDecoder(onMessage, onParseError) {
|
|
|
15
15
|
onMessage(JSON.parse(raw));
|
|
16
16
|
}
|
|
17
17
|
catch (error) {
|
|
18
|
-
|
|
18
|
+
if (error instanceof Error) {
|
|
19
|
+
onParseError?.(raw, error);
|
|
20
|
+
}
|
|
21
|
+
else {
|
|
22
|
+
throw error;
|
|
23
|
+
}
|
|
19
24
|
}
|
|
20
25
|
}
|
|
21
26
|
index = buffer.indexOf("\n");
|
|
@@ -5,8 +5,16 @@
|
|
|
5
5
|
"type": "module",
|
|
6
6
|
"packageManager": "npm@11.16.0",
|
|
7
7
|
"license": "MIT",
|
|
8
|
-
"
|
|
9
|
-
|
|
8
|
+
"exports": {
|
|
9
|
+
"./client": {
|
|
10
|
+
"types": "./dist/client.d.ts",
|
|
11
|
+
"default": "./dist/client.js"
|
|
12
|
+
},
|
|
13
|
+
"./cli": {
|
|
14
|
+
"types": "./dist/cli.d.ts",
|
|
15
|
+
"default": "./dist/cli.js"
|
|
16
|
+
}
|
|
17
|
+
},
|
|
10
18
|
"bin": {
|
|
11
19
|
"omo-lsp-daemon": "./dist/cli.js"
|
|
12
20
|
},
|
|
@@ -17,7 +25,8 @@
|
|
|
17
25
|
"README.md"
|
|
18
26
|
],
|
|
19
27
|
"scripts": {
|
|
20
|
-
"build": "tsc -p tsconfig.build.json && bun build src/cli.ts src/index.ts --outdir dist --target node --format esm && node scripts/stamp-dist-version.mjs",
|
|
28
|
+
"build": "node scripts/clean-dist.mjs && tsc -p tsconfig.build.json && bun build src/cli.ts src/index.ts src/client.ts --outdir dist --target node --format esm && node scripts/stamp-dist-version.mjs",
|
|
29
|
+
"smoke:client-package": "node scripts/client-package-smoke.mjs",
|
|
21
30
|
"test": "vitest --run",
|
|
22
31
|
"test:watch": "vitest",
|
|
23
32
|
"typecheck": "tsc --noEmit",
|