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,24 @@
|
|
|
1
1
|
import type { ToolExecutionResult } from "@oh-my-opencode/lsp-core/tools";
|
|
2
|
+
import { type LspRequestContext } from "@oh-my-opencode/lsp-core/request-context";
|
|
2
3
|
import { type DaemonPaths } from "./paths.js";
|
|
3
4
|
export declare class DaemonRequestError extends Error {
|
|
4
5
|
readonly requestWritten: boolean;
|
|
5
6
|
constructor(message: string, requestWritten: boolean);
|
|
6
7
|
}
|
|
7
|
-
export
|
|
8
|
-
|
|
9
|
-
env?: Record<string, string>;
|
|
8
|
+
export declare class DaemonAuthenticationRejectedError extends DaemonRequestError {
|
|
9
|
+
constructor();
|
|
10
10
|
}
|
|
11
|
+
export declare class DaemonRequestCancelledError extends DaemonRequestError {
|
|
12
|
+
constructor(requestWritten: boolean);
|
|
13
|
+
}
|
|
14
|
+
export type DaemonToolContext = LspRequestContext;
|
|
11
15
|
export interface CallToolOptions {
|
|
12
|
-
context
|
|
16
|
+
context: DaemonToolContext;
|
|
13
17
|
paths?: DaemonPaths;
|
|
14
18
|
requestTimeoutMs?: number;
|
|
19
|
+
signal?: AbortSignal;
|
|
15
20
|
ensure?: (paths: DaemonPaths) => Promise<void>;
|
|
16
21
|
}
|
|
17
|
-
export declare function callToolViaDaemon(name: string, args: Record<string, unknown>, options
|
|
18
|
-
export declare function callDiagnosticsViaDaemon(filePath: string, options
|
|
22
|
+
export declare function callToolViaDaemon(name: string, args: Record<string, unknown>, options: CallToolOptions): Promise<ToolExecutionResult>;
|
|
23
|
+
export declare function callDiagnosticsViaDaemon(filePath: string, options: CallToolOptions): Promise<ToolExecutionResult>;
|
|
19
24
|
export declare function currentRequestContext(env?: NodeJS.ProcessEnv): DaemonToolContext;
|
|
@@ -1,11 +1,15 @@
|
|
|
1
1
|
import { connect } from "node:net";
|
|
2
|
+
import { homedir } from "node:os";
|
|
3
|
+
import { join } from "node:path";
|
|
4
|
+
import { parseLspRequestContext } from "@oh-my-opencode/lsp-core/request-context";
|
|
2
5
|
import { isPlainRecord } from "@oh-my-opencode/mcp-stdio-core/record";
|
|
3
6
|
import { ensureDaemonRunning } from "./ensure-daemon.js";
|
|
7
|
+
import { authEnvelope, isAuthErrorResponse, readAuthToken } from "./ipc-protocol.js";
|
|
4
8
|
import { daemonPaths } from "./paths.js";
|
|
5
9
|
import { CONTEXT_KEY } from "./request-routing.js";
|
|
6
10
|
import { createLineDecoder, encodeJsonLine } from "./socket-jsonrpc.js";
|
|
7
11
|
const DEFAULT_REQUEST_TIMEOUT_MS = 30_000;
|
|
8
|
-
|
|
12
|
+
let nextProxyRequestId = 1;
|
|
9
13
|
export class DaemonRequestError extends Error {
|
|
10
14
|
constructor(message, requestWritten) {
|
|
11
15
|
super(message);
|
|
@@ -13,45 +17,69 @@ export class DaemonRequestError extends Error {
|
|
|
13
17
|
this.requestWritten = requestWritten;
|
|
14
18
|
}
|
|
15
19
|
}
|
|
16
|
-
export
|
|
20
|
+
export class DaemonAuthenticationRejectedError extends DaemonRequestError {
|
|
21
|
+
constructor() {
|
|
22
|
+
super("daemon authentication failed before dispatch", true);
|
|
23
|
+
this.name = "DaemonAuthenticationRejectedError";
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
export class DaemonRequestCancelledError extends DaemonRequestError {
|
|
27
|
+
constructor(requestWritten) {
|
|
28
|
+
super("daemon request cancelled", requestWritten);
|
|
29
|
+
this.name = "DaemonRequestCancelledError";
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
export async function callToolViaDaemon(name, args, options) {
|
|
33
|
+
const context = requireContext(options.context);
|
|
17
34
|
const paths = options.paths ?? daemonPaths();
|
|
18
35
|
const ensure = options.ensure ?? ensureDaemonRunning;
|
|
19
36
|
const timeoutMs = options.requestTimeoutMs ?? DEFAULT_REQUEST_TIMEOUT_MS;
|
|
20
|
-
const requestArgs = withContext(args,
|
|
37
|
+
const requestArgs = withContext(args, context);
|
|
21
38
|
let lastError;
|
|
22
|
-
|
|
39
|
+
let authRefreshUsed = false;
|
|
40
|
+
for (let attempt = 0; attempt < 3; attempt += 1) {
|
|
23
41
|
try {
|
|
24
42
|
await ensure(paths);
|
|
25
|
-
|
|
43
|
+
const token = readAuthToken(paths);
|
|
44
|
+
if (!token)
|
|
45
|
+
throw new DaemonRequestError("daemon auth token missing", false);
|
|
46
|
+
const sendOptions = options.signal === undefined ? { timeoutMs } : { timeoutMs, signal: options.signal };
|
|
47
|
+
return await sendToolCall(paths, token, name, requestArgs, sendOptions);
|
|
26
48
|
}
|
|
27
49
|
catch (error) {
|
|
28
50
|
lastError = error;
|
|
29
|
-
if (error instanceof
|
|
51
|
+
if (error instanceof DaemonAuthenticationRejectedError && !authRefreshUsed) {
|
|
52
|
+
authRefreshUsed = true;
|
|
53
|
+
continue;
|
|
54
|
+
}
|
|
55
|
+
if (error instanceof DaemonRequestCancelledError)
|
|
56
|
+
break;
|
|
57
|
+
if (error instanceof DaemonRequestError && (error.requestWritten || !isRetryableTool(name)))
|
|
30
58
|
break;
|
|
31
59
|
}
|
|
32
60
|
}
|
|
33
61
|
return daemonUnreachableResult(paths, lastError);
|
|
34
62
|
}
|
|
35
|
-
export function callDiagnosticsViaDaemon(filePath, options
|
|
63
|
+
export function callDiagnosticsViaDaemon(filePath, options) {
|
|
36
64
|
return callToolViaDaemon("diagnostics", { filePath, severity: "error" }, options);
|
|
37
65
|
}
|
|
38
|
-
const FORWARDED_ENV_KEYS = [
|
|
39
|
-
"LSP_TOOLS_MCP_PROJECT_CONFIG",
|
|
40
|
-
"LSP_TOOLS_MCP_USER_CONFIG",
|
|
41
|
-
"LSP_TOOLS_MCP_INSTALL_DECISIONS",
|
|
42
|
-
];
|
|
43
66
|
export function currentRequestContext(env = process.env) {
|
|
44
|
-
const
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
67
|
+
const cwd = process.cwd();
|
|
68
|
+
const home = env["HOME"] ?? homedir();
|
|
69
|
+
return parseLspRequestContext({
|
|
70
|
+
cwd,
|
|
71
|
+
projectConfigPaths: [join(cwd, ".codex", "lsp-client.json")],
|
|
72
|
+
userConfigPath: join(home, ".codex", "lsp-client.json"),
|
|
73
|
+
installDecisionsPath: join(home, ".codex", "lsp-install-decisions.json"),
|
|
74
|
+
capabilities: { installDecisionTool: true },
|
|
75
|
+
});
|
|
76
|
+
}
|
|
77
|
+
function requireContext(context) {
|
|
78
|
+
if (!context)
|
|
79
|
+
throw new DaemonRequestError("daemon tool context is required", false);
|
|
80
|
+
return parseLspRequestContext(context);
|
|
51
81
|
}
|
|
52
82
|
function withContext(args, context) {
|
|
53
|
-
if (!context || (context.cwd === undefined && context.env === undefined))
|
|
54
|
-
return args;
|
|
55
83
|
return { ...args, [CONTEXT_KEY]: context };
|
|
56
84
|
}
|
|
57
85
|
function daemonUnreachableResult(paths, error) {
|
|
@@ -64,39 +92,84 @@ function daemonUnreachableResult(paths, error) {
|
|
|
64
92
|
].join("\n");
|
|
65
93
|
return { content: [{ type: "text", text }], isError: true };
|
|
66
94
|
}
|
|
67
|
-
function sendToolCall(
|
|
95
|
+
function sendToolCall(paths, token, name, args, options) {
|
|
68
96
|
return new Promise((resolve, reject) => {
|
|
69
|
-
const socket = connect(
|
|
97
|
+
const socket = connect(paths.socket);
|
|
98
|
+
const requestId = allocateProxyRequestId();
|
|
70
99
|
let settled = false;
|
|
71
100
|
let requestWritten = false;
|
|
101
|
+
let cancelAfterWrite = false;
|
|
102
|
+
const cancelPayload = () => encodeJsonLine({
|
|
103
|
+
jsonrpc: "2.0",
|
|
104
|
+
method: "$/cancelRequest",
|
|
105
|
+
params: { _omo: authEnvelope(token), id: requestId },
|
|
106
|
+
});
|
|
72
107
|
const finish = (run) => {
|
|
73
108
|
if (settled)
|
|
74
109
|
return;
|
|
75
110
|
settled = true;
|
|
76
111
|
clearTimeout(timer);
|
|
77
|
-
|
|
112
|
+
options.signal?.removeEventListener("abort", onAbort);
|
|
113
|
+
destroyAfterCancel();
|
|
78
114
|
run();
|
|
79
115
|
};
|
|
80
|
-
const
|
|
116
|
+
const sendCancel = () => {
|
|
117
|
+
if (!requestWritten) {
|
|
118
|
+
cancelAfterWrite = true;
|
|
119
|
+
return;
|
|
120
|
+
}
|
|
121
|
+
if (!socket.writable)
|
|
122
|
+
return;
|
|
123
|
+
socket.write(cancelPayload());
|
|
124
|
+
};
|
|
125
|
+
const destroyAfterCancel = () => {
|
|
126
|
+
socket.destroy();
|
|
127
|
+
};
|
|
128
|
+
const onAbort = () => {
|
|
129
|
+
sendCancel();
|
|
130
|
+
finish(() => reject(new DaemonRequestCancelledError(requestWritten)));
|
|
131
|
+
};
|
|
132
|
+
const timer = setTimeout(() => {
|
|
133
|
+
sendCancel();
|
|
134
|
+
finish(() => reject(new DaemonRequestError("daemon request timed out", requestWritten)));
|
|
135
|
+
}, options.timeoutMs);
|
|
81
136
|
timer.unref();
|
|
137
|
+
if (options.signal?.aborted) {
|
|
138
|
+
onAbort();
|
|
139
|
+
return;
|
|
140
|
+
}
|
|
141
|
+
options.signal?.addEventListener("abort", onAbort, { once: true });
|
|
82
142
|
const decoder = createLineDecoder((message) => {
|
|
83
|
-
|
|
143
|
+
if (isAuthErrorResponse(message)) {
|
|
144
|
+
finish(() => reject(new DaemonAuthenticationRejectedError()));
|
|
145
|
+
return;
|
|
146
|
+
}
|
|
147
|
+
const result = toToolResult(message, requestId);
|
|
84
148
|
if (result)
|
|
85
149
|
finish(() => resolve(result));
|
|
86
150
|
else
|
|
87
151
|
finish(() => reject(new DaemonRequestError("invalid daemon response", requestWritten)));
|
|
88
152
|
});
|
|
89
153
|
socket.once("connect", () => {
|
|
90
|
-
|
|
91
|
-
|
|
154
|
+
const payload = encodeJsonLine({
|
|
155
|
+
jsonrpc: "2.0",
|
|
156
|
+
id: requestId,
|
|
157
|
+
method: "tools/call",
|
|
158
|
+
params: { _omo: authEnvelope(token), name, arguments: args },
|
|
159
|
+
});
|
|
160
|
+
socket.write(payload, () => {
|
|
161
|
+
requestWritten = true;
|
|
162
|
+
if (cancelAfterWrite && socket.writable)
|
|
163
|
+
socket.write(cancelPayload());
|
|
164
|
+
});
|
|
92
165
|
});
|
|
93
166
|
socket.on("data", (chunk) => decoder.push(chunk));
|
|
94
167
|
socket.once("error", (error) => finish(() => reject(new DaemonRequestError(error.message, requestWritten))));
|
|
95
168
|
socket.once("close", () => finish(() => reject(new DaemonRequestError("daemon connection closed", requestWritten))));
|
|
96
169
|
});
|
|
97
170
|
}
|
|
98
|
-
function toToolResult(message) {
|
|
99
|
-
if (!isPlainRecord(message) || message["id"] !==
|
|
171
|
+
function toToolResult(message, requestId) {
|
|
172
|
+
if (!isPlainRecord(message) || message["id"] !== requestId)
|
|
100
173
|
return null;
|
|
101
174
|
const result = message["result"];
|
|
102
175
|
if (!isPlainRecord(result) || !Array.isArray(result["content"]))
|
|
@@ -107,6 +180,16 @@ function toToolResult(message) {
|
|
|
107
180
|
details: result["details"],
|
|
108
181
|
};
|
|
109
182
|
}
|
|
183
|
+
function allocateProxyRequestId() {
|
|
184
|
+
const id = nextProxyRequestId;
|
|
185
|
+
nextProxyRequestId += 1;
|
|
186
|
+
if (nextProxyRequestId > Number.MAX_SAFE_INTEGER)
|
|
187
|
+
nextProxyRequestId = 1;
|
|
188
|
+
return id;
|
|
189
|
+
}
|
|
190
|
+
function isRetryableTool(name) {
|
|
191
|
+
return name !== "rename" && name !== "lsp_rename";
|
|
192
|
+
}
|
|
110
193
|
function errorText(error) {
|
|
111
194
|
return error instanceof Error ? error.message : String(error);
|
|
112
195
|
}
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { type Server } from "node:net";
|
|
2
2
|
import type { DaemonPaths } from "./paths.js";
|
|
3
|
+
export { DaemonAlreadyRunningError, DaemonStartupDeferredError } from "./ownership.js";
|
|
3
4
|
export interface DaemonServerOptions {
|
|
4
5
|
idleShutdownMs?: number;
|
|
5
6
|
idleCheckIntervalMs?: number;
|
|
@@ -1,41 +1,58 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { chmodSync } from "node:fs";
|
|
2
2
|
import { createServer } from "node:net";
|
|
3
|
-
import { join } from "node:path";
|
|
4
3
|
import { disposeDefaultLspManager, getLspManager } from "@oh-my-opencode/lsp-core/lsp/manager";
|
|
5
|
-
import {
|
|
4
|
+
import { setPrivateFileMode } from "./ipc-protocol.js";
|
|
5
|
+
import { pingDaemon } from "./ensure-daemon.js";
|
|
6
|
+
import { acquireStartupLease, DaemonStartupDeferredError, endpointIdentity, removeDaemonMetadataForOwner, writeDaemonOwner, } from "./ownership.js";
|
|
6
7
|
import { handleDaemonMessage } from "./request-routing.js";
|
|
7
8
|
import { createLineDecoder, encodeJsonLine } from "./socket-jsonrpc.js";
|
|
9
|
+
export { DaemonAlreadyRunningError, DaemonStartupDeferredError } from "./ownership.js";
|
|
8
10
|
const DEFAULT_IDLE_SHUTDOWN_MS = 30 * 60_000;
|
|
9
11
|
const DEFAULT_IDLE_CHECK_INTERVAL_MS = 60_000;
|
|
10
12
|
export async function startDaemonServer(paths, options = {}) {
|
|
11
13
|
const idleShutdownMs = options.idleShutdownMs ?? DEFAULT_IDLE_SHUTDOWN_MS;
|
|
12
14
|
const idleCheckIntervalMs = options.idleCheckIntervalMs ?? DEFAULT_IDLE_CHECK_INTERVAL_MS;
|
|
13
|
-
|
|
14
|
-
unlinkQuietly(paths.socket);
|
|
15
|
+
const lease = await acquireStartupLease(paths, (token) => pingDaemon(paths, token));
|
|
15
16
|
const connections = new Set();
|
|
16
17
|
let lastActiveAt = Date.now();
|
|
17
18
|
const touch = () => {
|
|
18
19
|
lastActiveAt = Date.now();
|
|
19
20
|
};
|
|
21
|
+
let routeOwner = lease.owner;
|
|
20
22
|
const server = createServer((socket) => {
|
|
21
23
|
connections.add(socket);
|
|
24
|
+
const activeRequests = new Map();
|
|
22
25
|
touch();
|
|
23
26
|
const decoder = createLineDecoder((message) => {
|
|
24
27
|
touch();
|
|
25
|
-
void respond(socket, message);
|
|
28
|
+
void respond(socket, message, lease.token, routeOwner, activeRequests);
|
|
26
29
|
});
|
|
27
30
|
socket.on("data", (chunk) => decoder.push(chunk));
|
|
28
31
|
socket.on("error", () => socket.destroy());
|
|
29
32
|
socket.on("close", () => {
|
|
33
|
+
for (const controller of activeRequests.values())
|
|
34
|
+
controller.abort();
|
|
35
|
+
activeRequests.clear();
|
|
30
36
|
connections.delete(socket);
|
|
31
37
|
touch();
|
|
32
38
|
});
|
|
33
39
|
});
|
|
34
40
|
server.on("error", (error) => logServerError(error));
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
41
|
+
let owner;
|
|
42
|
+
try {
|
|
43
|
+
await listen(server, paths.socket);
|
|
44
|
+
if (process.platform !== "win32")
|
|
45
|
+
chmodSync(paths.socket, 0o600);
|
|
46
|
+
owner = { ...lease.owner, endpoint: endpointIdentity(paths.socket) };
|
|
47
|
+
routeOwner = owner;
|
|
48
|
+
writeDaemonOwner(paths, owner);
|
|
49
|
+
await assertSelfProbe(paths, lease.token, owner);
|
|
50
|
+
}
|
|
51
|
+
catch (error) {
|
|
52
|
+
lease.lock.release();
|
|
53
|
+
throw error;
|
|
54
|
+
}
|
|
55
|
+
lease.lock.release();
|
|
39
56
|
let closed = false;
|
|
40
57
|
const close = async () => {
|
|
41
58
|
if (closed)
|
|
@@ -46,9 +63,7 @@ export async function startDaemonServer(paths, options = {}) {
|
|
|
46
63
|
socket.destroy();
|
|
47
64
|
connections.clear();
|
|
48
65
|
await closeServer(server);
|
|
49
|
-
|
|
50
|
-
unlinkQuietly(paths.pid);
|
|
51
|
-
unlinkQuietly(endpointPath);
|
|
66
|
+
removeDaemonMetadataForOwner(paths, owner);
|
|
52
67
|
await disposeDefaultLspManager();
|
|
53
68
|
};
|
|
54
69
|
const idleTimer = setInterval(() => {
|
|
@@ -70,16 +85,26 @@ export async function startDaemonServer(paths, options = {}) {
|
|
|
70
85
|
installSignalHandlers(close);
|
|
71
86
|
return { server, close };
|
|
72
87
|
}
|
|
73
|
-
async function respond(socket, message) {
|
|
88
|
+
async function respond(socket, message, token, owner, activeRequests) {
|
|
74
89
|
try {
|
|
75
|
-
const response = await handleDaemonMessage(message);
|
|
90
|
+
const response = await handleDaemonMessage(message, { token, owner, activeRequests });
|
|
76
91
|
if (response && socket.writable)
|
|
77
92
|
socket.write(encodeJsonLine(response));
|
|
78
93
|
}
|
|
79
94
|
catch (error) {
|
|
95
|
+
if (!(error instanceof Error))
|
|
96
|
+
throw error;
|
|
80
97
|
logServerError(error);
|
|
81
98
|
}
|
|
82
99
|
}
|
|
100
|
+
async function assertSelfProbe(paths, token, owner) {
|
|
101
|
+
setPrivateFileMode(paths.pid);
|
|
102
|
+
setPrivateFileMode(paths.endpoint);
|
|
103
|
+
setPrivateFileMode(paths.owner);
|
|
104
|
+
const ping = await pingDaemon(paths, token);
|
|
105
|
+
if (!ping || ping.nonce !== owner.nonce)
|
|
106
|
+
throw new DaemonStartupDeferredError("self_probe_failed");
|
|
107
|
+
}
|
|
83
108
|
function listen(server, socketPath) {
|
|
84
109
|
return new Promise((resolve, reject) => {
|
|
85
110
|
const onError = (error) => reject(error);
|
|
@@ -1,12 +1,12 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import type
|
|
1
|
+
import type { OwnerPing } from "./ownership.js";
|
|
2
|
+
import { type DaemonPaths } from "./paths.js";
|
|
3
|
+
import { type DaemonRuntimeDefaults } from "./runtime-contract.js";
|
|
4
|
+
export { InvalidRuntimeOverrideError, OMO_LSP_DAEMON_CLI, resolveDaemonRuntime } from "./runtime-contract.js";
|
|
3
5
|
export declare class DaemonUnreachableError extends Error {
|
|
4
6
|
constructor(socketPath: string);
|
|
5
7
|
}
|
|
6
8
|
export interface EnsureDaemonDeps {
|
|
7
|
-
probe(
|
|
8
|
-
acquireLock(lockPath: string): LockHandle | null;
|
|
9
|
-
cleanupStaleSocket(socketPath: string): void;
|
|
9
|
+
probe(paths: DaemonPaths): Promise<boolean>;
|
|
10
10
|
spawnDaemon(paths: DaemonPaths): void;
|
|
11
11
|
sleep(ms: number): Promise<void>;
|
|
12
12
|
now(): number;
|
|
@@ -16,7 +16,8 @@ export interface EnsureDaemonOptions {
|
|
|
16
16
|
pollIntervalMs?: number;
|
|
17
17
|
}
|
|
18
18
|
export declare function ensureDaemonRunning(paths: DaemonPaths, deps?: EnsureDaemonDeps, options?: EnsureDaemonOptions): Promise<void>;
|
|
19
|
-
export declare function
|
|
19
|
+
export declare function probeDaemon(paths: DaemonPaths, timeoutMs?: number): Promise<boolean>;
|
|
20
|
+
export declare function pingDaemon(paths: DaemonPaths, token: string, timeoutMs?: number): Promise<OwnerPing | null>;
|
|
20
21
|
export declare function spawnDaemonProcess(paths: DaemonPaths): void;
|
|
21
|
-
export declare function resolveDaemonCliPath(env?: NodeJS.ProcessEnv): string;
|
|
22
|
+
export declare function resolveDaemonCliPath(env?: NodeJS.ProcessEnv, defaults?: DaemonRuntimeDefaults): string;
|
|
22
23
|
export declare function defaultEnsureDaemonDeps(): EnsureDaemonDeps;
|
|
@@ -1,14 +1,16 @@
|
|
|
1
1
|
import { spawn } from "node:child_process";
|
|
2
|
-
import { closeSync,
|
|
2
|
+
import { closeSync, mkdirSync, openSync } from "node:fs";
|
|
3
3
|
import { connect } from "node:net";
|
|
4
4
|
import { dirname } from "node:path";
|
|
5
5
|
import { execPath } from "node:process";
|
|
6
|
-
import {
|
|
7
|
-
import {
|
|
6
|
+
import { authEnvelope, readAuthToken } from "./ipc-protocol.js";
|
|
7
|
+
import { packagedRuntimeDefaults } from "./paths.js";
|
|
8
|
+
import { resolveDaemonRuntime } from "./runtime-contract.js";
|
|
9
|
+
import { createLineDecoder, encodeJsonLine } from "./socket-jsonrpc.js";
|
|
10
|
+
export { InvalidRuntimeOverrideError, OMO_LSP_DAEMON_CLI, resolveDaemonRuntime } from "./runtime-contract.js";
|
|
8
11
|
const PROBE_TIMEOUT_MS = 500;
|
|
9
12
|
const DEFAULT_READY_TIMEOUT_MS = 5_000;
|
|
10
13
|
const DEFAULT_POLL_INTERVAL_MS = 100;
|
|
11
|
-
const CODEX_LSP_DAEMON_CLI_ENV = "CODEX_LSP_DAEMON_CLI";
|
|
12
14
|
export class DaemonUnreachableError extends Error {
|
|
13
15
|
constructor(socketPath) {
|
|
14
16
|
super(`LSP daemon did not become reachable at ${socketPath}`);
|
|
@@ -18,50 +20,51 @@ export class DaemonUnreachableError extends Error {
|
|
|
18
20
|
export async function ensureDaemonRunning(paths, deps = defaultEnsureDaemonDeps(), options = {}) {
|
|
19
21
|
const readyTimeoutMs = options.readyTimeoutMs ?? DEFAULT_READY_TIMEOUT_MS;
|
|
20
22
|
const pollIntervalMs = options.pollIntervalMs ?? DEFAULT_POLL_INTERVAL_MS;
|
|
21
|
-
if (await deps.probe(paths
|
|
23
|
+
if (await deps.probe(paths))
|
|
22
24
|
return;
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
await waitUntilReachable(paths.socket, deps, readyTimeoutMs, pollIntervalMs);
|
|
26
|
-
return;
|
|
27
|
-
}
|
|
28
|
-
try {
|
|
29
|
-
if (await deps.probe(paths.socket))
|
|
30
|
-
return;
|
|
31
|
-
deps.cleanupStaleSocket(paths.socket);
|
|
32
|
-
deps.spawnDaemon(paths);
|
|
33
|
-
await waitUntilReachable(paths.socket, deps, readyTimeoutMs, pollIntervalMs);
|
|
34
|
-
}
|
|
35
|
-
finally {
|
|
36
|
-
lock.release();
|
|
37
|
-
}
|
|
25
|
+
deps.spawnDaemon(paths);
|
|
26
|
+
await waitUntilReachable(paths, deps, readyTimeoutMs, pollIntervalMs);
|
|
38
27
|
}
|
|
39
|
-
async function waitUntilReachable(
|
|
28
|
+
async function waitUntilReachable(paths, deps, readyTimeoutMs, pollIntervalMs) {
|
|
40
29
|
const deadline = deps.now() + readyTimeoutMs;
|
|
41
30
|
for (;;) {
|
|
42
|
-
if (await deps.probe(
|
|
31
|
+
if (await deps.probe(paths))
|
|
43
32
|
return;
|
|
44
33
|
if (deps.now() >= deadline)
|
|
45
|
-
throw new DaemonUnreachableError(
|
|
34
|
+
throw new DaemonUnreachableError(paths.socket);
|
|
46
35
|
await deps.sleep(pollIntervalMs);
|
|
47
36
|
}
|
|
48
37
|
}
|
|
49
|
-
export function
|
|
38
|
+
export async function probeDaemon(paths, timeoutMs = PROBE_TIMEOUT_MS) {
|
|
39
|
+
const token = readAuthToken(paths);
|
|
40
|
+
if (!token)
|
|
41
|
+
return false;
|
|
42
|
+
return (await pingDaemon(paths, token, timeoutMs)) !== null;
|
|
43
|
+
}
|
|
44
|
+
export function pingDaemon(paths, token, timeoutMs = PROBE_TIMEOUT_MS) {
|
|
50
45
|
return new Promise((resolve) => {
|
|
51
|
-
const socket = connect(
|
|
52
|
-
|
|
46
|
+
const socket = connect(paths.socket);
|
|
47
|
+
let settled = false;
|
|
48
|
+
const finish = (value) => {
|
|
49
|
+
if (settled)
|
|
50
|
+
return;
|
|
51
|
+
settled = true;
|
|
53
52
|
socket.destroy();
|
|
54
|
-
resolve(
|
|
53
|
+
resolve(value);
|
|
55
54
|
};
|
|
56
|
-
const timer = setTimeout(() => finish(
|
|
55
|
+
const timer = setTimeout(() => finish(null), timeoutMs);
|
|
57
56
|
timer.unref?.();
|
|
58
|
-
|
|
57
|
+
const decoder = createLineDecoder((message) => {
|
|
59
58
|
clearTimeout(timer);
|
|
60
|
-
finish(
|
|
59
|
+
finish(parsePingResponse(message));
|
|
60
|
+
});
|
|
61
|
+
socket.once("connect", () => {
|
|
62
|
+
socket.write(encodeJsonLine({ jsonrpc: "2.0", id: 1, method: "omo/ping", params: { _omo: authEnvelope(token) } }));
|
|
61
63
|
});
|
|
64
|
+
socket.on("data", (chunk) => decoder.push(chunk));
|
|
62
65
|
socket.once("error", () => {
|
|
63
66
|
clearTimeout(timer);
|
|
64
|
-
finish(
|
|
67
|
+
finish(null);
|
|
65
68
|
});
|
|
66
69
|
});
|
|
67
70
|
}
|
|
@@ -69,8 +72,7 @@ export function spawnDaemonProcess(paths) {
|
|
|
69
72
|
mkdirSync(dirname(paths.log), { recursive: true });
|
|
70
73
|
const logFd = openSync(paths.log, "a");
|
|
71
74
|
try {
|
|
72
|
-
const
|
|
73
|
-
const child = spawn(execPath, [cliPath, "daemon"], {
|
|
75
|
+
const child = spawn(execPath, [paths.cliPath, "daemon"], {
|
|
74
76
|
detached: true,
|
|
75
77
|
stdio: ["ignore", logFd, logFd],
|
|
76
78
|
});
|
|
@@ -80,20 +82,12 @@ export function spawnDaemonProcess(paths) {
|
|
|
80
82
|
closeSync(logFd);
|
|
81
83
|
}
|
|
82
84
|
}
|
|
83
|
-
export function resolveDaemonCliPath(env = process.env) {
|
|
84
|
-
|
|
85
|
-
if (override)
|
|
86
|
-
return override;
|
|
87
|
-
return fileURLToPath(new URL("./cli.js", import.meta.url));
|
|
85
|
+
export function resolveDaemonCliPath(env = process.env, defaults = packagedRuntimeDefaults()) {
|
|
86
|
+
return resolveDaemonRuntime(env, defaults).cliPath;
|
|
88
87
|
}
|
|
89
88
|
export function defaultEnsureDaemonDeps() {
|
|
90
89
|
return {
|
|
91
|
-
probe: (
|
|
92
|
-
acquireLock: (lockPath) => tryAcquireLock(lockPath),
|
|
93
|
-
cleanupStaleSocket: (socketPath) => {
|
|
94
|
-
if (existsSync(socketPath))
|
|
95
|
-
unlinkQuietly(socketPath);
|
|
96
|
-
},
|
|
90
|
+
probe: (paths) => probeDaemon(paths),
|
|
97
91
|
spawnDaemon: (paths) => spawnDaemonProcess(paths),
|
|
98
92
|
sleep: (ms) => new Promise((resolve) => {
|
|
99
93
|
setTimeout(resolve, ms);
|
|
@@ -101,3 +95,32 @@ export function defaultEnsureDaemonDeps() {
|
|
|
101
95
|
now: () => Date.now(),
|
|
102
96
|
};
|
|
103
97
|
}
|
|
98
|
+
function parsePingResponse(message) {
|
|
99
|
+
if (!message || typeof message !== "object" || Array.isArray(message))
|
|
100
|
+
return null;
|
|
101
|
+
const result = Reflect.get(message, "result");
|
|
102
|
+
if (!result || typeof result !== "object" || Array.isArray(result))
|
|
103
|
+
return null;
|
|
104
|
+
const pid = Reflect.get(result, "pid");
|
|
105
|
+
const nonce = Reflect.get(result, "nonce");
|
|
106
|
+
const startedAt = Reflect.get(result, "startedAt");
|
|
107
|
+
const endpoint = Reflect.get(result, "endpoint");
|
|
108
|
+
if (typeof pid !== "number" || typeof nonce !== "string" || typeof startedAt !== "string")
|
|
109
|
+
return null;
|
|
110
|
+
if (!endpoint || typeof endpoint !== "object" || Array.isArray(endpoint))
|
|
111
|
+
return null;
|
|
112
|
+
const path = Reflect.get(endpoint, "path");
|
|
113
|
+
const kind = Reflect.get(endpoint, "kind");
|
|
114
|
+
if (typeof path !== "string")
|
|
115
|
+
return null;
|
|
116
|
+
if (kind === "windows")
|
|
117
|
+
return { pid, nonce, startedAt, endpoint: { kind, path } };
|
|
118
|
+
if (kind === "missing")
|
|
119
|
+
return { pid, nonce, startedAt, endpoint: { kind, path } };
|
|
120
|
+
const dev = Reflect.get(endpoint, "dev");
|
|
121
|
+
const ino = Reflect.get(endpoint, "ino");
|
|
122
|
+
if (kind === "unix" && typeof dev === "number" && typeof ino === "number") {
|
|
123
|
+
return { pid, nonce, startedAt, endpoint: { kind, path, dev, ino } };
|
|
124
|
+
}
|
|
125
|
+
return null;
|
|
126
|
+
}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
export { disposeDefaultLspManager } from "@oh-my-opencode/lsp-core/lsp/manager";
|
|
2
2
|
export { type CallToolOptions, callDiagnosticsViaDaemon, callToolViaDaemon, currentRequestContext, type DaemonToolContext, } from "./daemon-client.js";
|
|
3
|
-
export { ensureDaemonRunning } from "./ensure-daemon.js";
|
|
4
|
-
export { type DaemonPaths, daemonPaths } from "./paths.js";
|
|
3
|
+
export { ensureDaemonRunning, InvalidRuntimeOverrideError, OMO_LSP_DAEMON_CLI, probeDaemon, resolveDaemonRuntime, } from "./ensure-daemon.js";
|
|
4
|
+
export { type DaemonPaths, daemonPaths, InvalidDaemonDirectoryError, InvalidDaemonVersionError, OMO_LSP_DAEMON_DIR, OMO_LSP_DAEMON_VERSION, validateDaemonVersion, } from "./paths.js";
|
|
5
5
|
export { runMcpStdioProxy } from "./proxy.js";
|