codexAppServerClient.ts ×15

Frontier kind: Code frontier

unlabeled · c_94e8e4550a1a

27 tests · 4554 LOC · 22 files · introduces 0 tests · 238 LOC · 1 file

Introduces — evidence that enters the hierarchy at this concept

Code
15 ranges238 lines · 1 files
Tests
0 tests

Contains — complete concept membership

All code (extent)
620 ranges4554 lines · 22 files · Browse complete extent
All tests (intent)
27 testsBrowse complete intent

Neighbourhood graph

The orange circle is the focus. Violet and green circles are every ancestor and descendant, broader and narrower, at any distance; blue squares and pink diamonds are the introduced files and exact introduced tests of every visible concept, not only the focus's. Arrows point from broader to narrower concepts and bridge only concepts omitted from this view. Undirected links show source or test introduction. Concept and file size follows LOC; exact test nodes use test-count units.

Introduced files, introduced tests, and structurally relevant concept specialization

In the embedded map, ordinary wheel input scrolls the page; use the visible controls to zoom and drag to pan. Open the full-screen map for canvas navigation: wheel pans, Ctrl/Command plus wheel zooms, and arrow keys pan when this region is focused. On touch screens, open the full-screen map to pan or pinch. If JavaScript or WebGL is unavailable, use the native relationship evidence on this page.

Introduced files, introduced tests, and structurally relevant concept specializationcodexAgent.ts ×13 · 83 introduced LOCcodexAgent.ts ×13codexSessionConfigKeys.test|title=codexSessionConfigKeys resolveSessionConfig preserves legacy read-only permissions on restore|occurrence=1 · 0 introduced LOCcodexSessionConfigKeys.t…codexSessionConfigKeys.test|title=codexSessionConfigKeys resolveSessionConfig exposes a single permissions-preset chip|occurrence=1 · 0 introduced LOCcodexSessionConfigKeys.t…codexAgent.ts ×1 · 27 introduced LOCcodexAgent.ts ×1codexAgent.ts ×24 · 89 introduced LOCcodexAgent.ts ×24codexSessionConfigKeys.ts ×1 · 7 introduced LOCcodexSessionConfigKeys.t…codexSessionConfigKeys.ts ×1 · 2 introduced LOCcodexSessionConfigKeys.t…codexSessionConfigKeys.ts ×7 · 49 introduced LOCcodexSessionConfigKeys.t…codexSessionConfigKeys.ts ×1 · 11 introduced LOCcodexSessionConfigKeys.t…codexSessionConfigKeys.ts ×1 · 2 introduced LOCcodexSessionConfigKeys.t…codexSessionConfigKeys.ts ×2 · 4 introduced LOCcodexSessionConfigKeys.t…codexSessionConfigKeys.ts ×3 · 18 introduced LOCcodexSessionConfigKeys.t…codexSessionConfigKeys.ts ×3 · 19 introduced LOCcodexSessionConfigKeys.t…codexSessionConfigKeys.ts ×2 · 3 introduced LOCcodexSessionConfigKeys.t…codexSessionConfigKeys.ts ×2 · 2 introduced LOCcodexSessionConfigKeys.t…codexSessionConfigKeys.ts ×6 · 23 introduced LOCcodexSessionConfigKeys.t…codexAgent.ts ×1 · 2 introduced LOCcodexAgent.ts ×1codexAgent.ts ×1 · 2 introduced LOCcodexAgent.ts ×1codexAgent.ts ×3 · 7 introduced LOCcodexAgent.ts ×3codexAgent.ts ×1 · 2 introduced LOCcodexAgent.ts ×1codexAgent.ts ×1 · 2 introduced LOCcodexAgent.ts ×1codexAgent.ts ×1 · 2 introduced LOCcodexAgent.ts ×1codexAgent.ts ×1 · 10 introduced LOCcodexAgent.ts ×1codexAgent.ts ×8 · 19 introduced LOCcodexAgent.ts ×8codexAgent.ts ×158 · 1640 introduced LOCcodexAgent.ts ×158codexAppServerClient.ts ×1 · 3 introduced LOCcodexAppServerClient.ts …codexAppServerClient.ts ×1 · 1 introduced LOCcodexAppServerClient.ts …codexAppServerClient.ts ×1 · 2 introduced LOCcodexAppServerClient.ts …codexAppServerClient.ts ×5 · 9 introduced LOCcodexAppServerClient.ts …codexAppServerClient.ts ×1 · 7 introduced LOCcodexAppServerClient.ts …codexAppServerClient.ts ×2 · 4 introduced LOCcodexAppServerClient.ts …codexAppServerClient.ts ×2 · 15 introduced LOCcodexAppServerClient.ts …codexAppServerClient.ts ×1 · 6 introduced LOCcodexAppServerClient.ts …codexAppServerClient.ts ×1 · 9 introduced LOCcodexAppServerClient.ts …codexAppServerClient.ts ×1 · 3 introduced LOCcodexAppServerClient.ts …codexAppServerClient.ts ×4 · 7 introduced LOCcodexAppServerClient.ts …codexAppServerClient.ts ×2 · 9 introduced LOCcodexAppServerClient.ts …codexAppServerClient.ts ×5 · 18 introduced LOCcodexAppServerClient.ts …codexAppServerClient.ts ×1 · 2 introduced LOCcodexAppServerClient.ts …codexAppServerClient.ts ×1 · 2 introduced LOCcodexAppServerClient.ts …codexAppServerClient.ts ×7 · 22 introduced LOCcodexAppServerClient.ts …codexAppServerClient.ts ×1 · 2 introduced LOCcodexAppServerClient.ts …codexAppServerClient.ts ×1 · 1 introduced LOCcodexAppServerClient.ts …codexAppServerClient.ts ×1 · 7 introduced LOCcodexAppServerClient.ts …codexAppServerClient.ts ×2 · 9 introduced LOCcodexAppServerClient.ts …codexAppServerClient.ts ×4 · 12 introduced LOCcodexAppServerClient.ts …codexAppServerClient.ts ×3 · 6 introduced LOCcodexAppServerClient.ts …codexAppServerClient.ts ×3 · 6 introduced LOCcodexAppServerClient.ts …codexAppServerClient.ts ×7 · 26 introduced LOCcodexAppServerClient.ts …lifecycle.ts ×2 · 3 introduced LOClifecycle.ts ×2event.ts ×2 · 4 introduced LOCevent.ts ×2event.ts ×2 · 6 introduced LOCevent.ts ×2event.ts ×93 · 864 introduced LOCevent.ts ×93utils.ts ×3 · 9 introduced LOCutils.ts ×3linkedList.ts ×13 · 44 introduced LOClinkedList.ts ×13lifecycle.ts ×2 · 4 introduced LOClifecycle.ts ×2lifecycle.ts ×1 · 3 introduced LOClifecycle.ts ×1lifecycle.ts ×3 · 9 introduced LOClifecycle.ts ×3lifecycle.ts ×4 · 8 introduced LOClifecycle.ts ×4lifecycle.ts ×6 · 16 introduced LOClifecycle.ts ×6lifecycle.ts ×2 · 2 introduced LOClifecycle.ts ×2lifecycle.ts ×1 · 3 introduced LOClifecycle.ts ×1lifecycle.ts ×1 · 2 introduced LOClifecycle.ts ×1lifecycle.ts ×1 · 2 introduced LOClifecycle.ts ×1lifecycle.ts ×1 · 3 introduced LOClifecycle.ts ×1map.ts ×97 · 3334 introduced LOCmap.ts ×97src/vs/base/common/arrays.ts · 949 LOCcommon/arrays.tssrc/vs/base/common/arraysFind.ts · 226 LOCcommon/arraysFind.tssrc/vs/base/common/assert.ts · 91 LOCcommon/assert.tssrc/vs/base/common/charCode.ts · 450 LOCcommon/charCode.tssrc/vs/base/common/collections.ts · 176 LOCcommon/collections.tssrc/vs/base/common/errors.ts · 357 LOCcommon/errors.tssrc/vs/base/common/event.ts · 1964 LOCcommon/event.tssrc/vs/base/common/functional.ts · 32 LOCcommon/functional.tssrc/vs/base/common/iterator.ts · 194 LOCcommon/iterator.tssrc/vs/base/common/lifecycle.ts · 974 LOCcommon/lifecycle.tssrc/vs/base/common/linkedList.ts · 151 LOCcommon/linkedList.tssrc/vs/base/common/map.ts · 1016 LOCcommon/map.tssrc/vs/base/common/marshallingIds.ts · 33 LOCcommon/marshallingIds.tssrc/vs/base/common/path.ts · 1589 LOCcommon/path.tssrc/vs/base/common/platform.ts · 281 LOCcommon/platform.tssrc/vs/base/common/process.ts · 76 LOCcommon/process.tssrc/vs/base/common/stopwatch.ts · 41 LOCcommon/stopwatch.tssrc/vs/base/common/types.ts · 410 LOCcommon/types.tssrc/vs/base/common/uri.ts · 754 LOCcommon/uri.tssrc/vs/base/test/common/utils.ts · 107 LOCcommon/utils.tssrc/vs/nls.ts · 244 LOCvs/nls.tssrc/vs/platform/agentHost/common/codexSessionConfigKeys.ts · 114 LOCcommon/codexSessionConfi…src/vs/platform/agentHost/node/codex/codexAgent.ts · 4389 LOCcodex/codexAgent.tssrc/vs/platform/agentHost/node/codex/codexAppServerClient.ts · 473 LOCcodex/codexAppServerClie…src/vs/platform/agentHost/node/codex/codexSessionConfigKeys.ts · 197 LOCcodex/codexSessionConfig…src/vs/platform/agentHost/node/codex/codexSessionMetadataStore.ts · 112 LOCcodex/codexSessionMetada…codexAppServerClient.test|title=CodexAppServerClient dispose cancels grace kill when transport exits cleanly|occurrence=1 · introduced test · mocha:v1|namespace=vscode@05c208e9e28d8c1c723fa08f85e2b7a96092e8e5|file=vs/platform/agentHost/test/node/codex/codexAppServerClient.test|title=CodexAppServerClient dispose cancels grace kill when transport exits cleanly|occurrence=1codexAppServerClient.tes…codexAppServerClient.test|title=CodexAppServerClient dispose rejects pending requests with CancellationError|occurrence=1 · introduced test · mocha:v1|namespace=vscode@05c208e9e28d8c1c723fa08f85e2b7a96092e8e5|file=vs/platform/agentHost/test/node/codex/codexAppServerClient.test|title=CodexAppServerClient dispose rejects pending requests with CancellationError|occurrence=1codexAppServerClient.tes…codexAppServerClient.test|title=CodexAppServerClient handles multiple messages arriving in a single chunk|occurrence=1 · introduced test · mocha:v1|namespace=vscode@05c208e9e28d8c1c723fa08f85e2b7a96092e8e5|file=vs/platform/agentHost/test/node/codex/codexAppServerClient.test|title=CodexAppServerClient handles multiple messages arriving in a single chunk|occurrence=1codexAppServerClient.tes…codexAppServerClient.test|title=CodexAppServerClient notify writes a payload with no id|occurrence=1 · introduced test · mocha:v1|namespace=vscode@05c208e9e28d8c1c723fa08f85e2b7a96092e8e5|file=vs/platform/agentHost/test/node/codex/codexAppServerClient.test|title=CodexAppServerClient notify writes a payload with no id|occurrence=1codexAppServerClient.tes…codexAppServerClient.test|title=CodexAppServerClient partial line is buffered until newline arrives|occurrence=1 · introduced test · mocha:v1|namespace=vscode@05c208e9e28d8c1c723fa08f85e2b7a96092e8e5|file=vs/platform/agentHost/test/node/codex/codexAppServerClient.test|title=CodexAppServerClient partial line is buffered until newline arrives|occurrence=1codexAppServerClient.tes…codexAppServerClient.test|title=CodexAppServerClient process exit rejects in-flight requests|occurrence=1 · introduced test · mocha:v1|namespace=vscode@05c208e9e28d8c1c723fa08f85e2b7a96092e8e5|file=vs/platform/agentHost/test/node/codex/codexAppServerClient.test|title=CodexAppServerClient process exit rejects in-flight requests|occurrence=1codexAppServerClient.tes…codexAppServerClient.test|title=CodexAppServerClient request rejects with JsonRpcError on error envelope|occurrence=1 · introduced test · mocha:v1|namespace=vscode@05c208e9e28d8c1c723fa08f85e2b7a96092e8e5|file=vs/platform/agentHost/test/node/codex/codexAppServerClient.test|title=CodexAppServerClient request rejects with JsonRpcError on error envelope|occurrence=1codexAppServerClient.tes…codexAppServerClient.test|title=CodexAppServerClient request response ids must match the numeric id exactly|occurrence=1 · introduced test · mocha:v1|namespace=vscode@05c208e9e28d8c1c723fa08f85e2b7a96092e8e5|file=vs/platform/agentHost/test/node/codex/codexAppServerClient.test|title=CodexAppServerClient request response ids must match the numeric id exactly|occurrence=1codexAppServerClient.tes…codexAppServerClient.test|title=CodexAppServerClient request roundtrip resolves with typed result|occurrence=1 · introduced test · mocha:v1|namespace=vscode@05c208e9e28d8c1c723fa08f85e2b7a96092e8e5|file=vs/platform/agentHost/test/node/codex/codexAppServerClient.test|title=CodexAppServerClient request roundtrip resolves with typed result|occurrence=1codexAppServerClient.tes…codexAppServerClient.test|title=CodexAppServerClient server notification is delivered to registered handler|occurrence=1 · introduced test · mocha:v1|namespace=vscode@05c208e9e28d8c1c723fa08f85e2b7a96092e8e5|file=vs/platform/agentHost/test/node/codex/codexAppServerClient.test|title=CodexAppServerClient server notification is delivered to registered handler|occurrence=1codexAppServerClient.tes…codexAppServerClient.test|title=CodexAppServerClient server request handler throwing is converted to InternalError|occurrence=1 · introduced test · mocha:v1|namespace=vscode@05c208e9e28d8c1c723fa08f85e2b7a96092e8e5|file=vs/platform/agentHost/test/node/codex/codexAppServerClient.test|title=CodexAppServerClient server request handler throwing is converted to InternalError|occurrence=1codexAppServerClient.tes…codexAppServerClient.test|title=CodexAppServerClient server request with handler returns result envelope|occurrence=1 · introduced test · mocha:v1|namespace=vscode@05c208e9e28d8c1c723fa08f85e2b7a96092e8e5|file=vs/platform/agentHost/test/node/codex/codexAppServerClient.test|title=CodexAppServerClient server request with handler returns result envelope|occurrence=1codexAppServerClient.tes…codexAppServerClient.test|title=CodexAppServerClient server request without handler returns MethodNotFound|occurrence=1 · introduced test · mocha:v1|namespace=vscode@05c208e9e28d8c1c723fa08f85e2b7a96092e8e5|file=vs/platform/agentHost/test/node/codex/codexAppServerClient.test|title=CodexAppServerClient server request without handler returns MethodNotFound|occurrence=1codexAppServerClient.tes…codexAppServerClient.test|title=CodexAppServerClient unhandled server notification is dropped with a warning|occurrence=1 · introduced test · mocha:v1|namespace=vscode@05c208e9e28d8c1c723fa08f85e2b7a96092e8e5|file=vs/platform/agentHost/test/node/codex/codexAppServerClient.test|title=CodexAppServerClient unhandled server notification is dropped with a warning|occurrence=1codexAppServerClient.tes…codexModelRefresh.test|title=CodexAgent model refresh keeps the last known-good models when a periodic refresh fails|occurrence=1 · introduced test · mocha:v1|namespace=vscode@05c208e9e28d8c1c723fa08f85e2b7a96092e8e5|file=vs/platform/agentHost/test/node/codex/codexModelRefresh.test|title=CodexAgent model refresh keeps the last known-good models when a periodic refresh fails|occurrence=1codexModelRefresh.test|t…codexPackagePaths.test|title=codex package paths codexBinaryTriple every suffix produced by codexPackageSuffix maps to a rust target triple|occurrence=1 · introduced test · mocha:v1|namespace=vscode@05c208e9e28d8c1c723fa08f85e2b7a96092e8e5|file=vs/platform/agentHost/test/node/codex/codexPackagePaths.test|title=codex package paths codexBinaryTriple every suffix produced by codexPackageSuffix maps to a rust target triple|occurrence=1codexPackagePaths.test|t…codexPackagePaths.test|title=codex package paths codexBinaryTriple returns undefined for unknown suffixes|occurrence=1 · introduced test · mocha:v1|namespace=vscode@05c208e9e28d8c1c723fa08f85e2b7a96092e8e5|file=vs/platform/agentHost/test/node/codex/codexPackagePaths.test|title=codex package paths codexBinaryTriple returns undefined for unknown suffixes|occurrence=1codexPackagePaths.test|t…codexPackagePaths.test|title=codex package paths codexPackageSuffix every supported (platform, arch) returns the npm optionalDependencies suffix|occurrence=1 · introduced test · mocha:v1|namespace=vscode@05c208e9e28d8c1c723fa08f85e2b7a96092e8e5|file=vs/platform/agentHost/test/node/codex/codexPackagePaths.test|title=codex package paths codexPackageSuffix every supported (platform, arch) returns the npm optionalDependencies suffix|occurrence=1codexPackagePaths.test|t…codexPackagePaths.test|title=codex package paths codexPackageSuffix never returns a -musl suffix on Linux (Codex is statically musl-linked)|occurrence=1 · introduced test · mocha:v1|namespace=vscode@05c208e9e28d8c1c723fa08f85e2b7a96092e8e5|file=vs/platform/agentHost/test/node/codex/codexPackagePaths.test|title=codex package paths codexPackageSuffix never returns a -musl suffix on Linux (Codex is statically musl-linked)|occurrence=1codexPackagePaths.test|t…codexPackagePaths.test|title=codex package paths codexPackageSuffix returns undefined for unsupported platforms and architectures|occurrence=1 · introduced test · mocha:v1|namespace=vscode@05c208e9e28d8c1c723fa08f85e2b7a96092e8e5|file=vs/platform/agentHost/test/node/codex/codexPackagePaths.test|title=codex package paths codexPackageSuffix returns undefined for unsupported platforms and architectures|occurrence=1codexPackagePaths.test|t…codex resolves|occurrence=1 · introduced test · mocha:v1|namespace=vscode@05c208e9e28d8c1c723fa08f85e2b7a96092e8e5|file=vs/platform/agentHost/test/node/codex/codexPackagePaths.test|title=codex package paths resolveCodexDevSdkRoot returns the directory containing node_modules when @openai/codex resolves|occurrence=1codex resolves|occurrenc…codexPackagePaths.test|title=codex package paths resolveCodexDevSdkRoot returns undefined when resolution throws (e.g. built product without the devDependency)|occurrence=1 · introduced test · mocha:v1|namespace=vscode@05c208e9e28d8c1c723fa08f85e2b7a96092e8e5|file=vs/platform/agentHost/test/node/codex/codexPackagePaths.test|title=codex package paths resolveCodexDevSdkRoot returns undefined when resolution throws (e.g. built product without the devDependency)|occurrence=1codexPackagePaths.test|t…codexSessionConfigKeys.test|title=codexSessionConfigKeys expands permissions presets and falls back to legacy axes|occurrence=1 · introduced test · mocha:v1|namespace=vscode@05c208e9e28d8c1c723fa08f85e2b7a96092e8e5|file=vs/platform/agentHost/test/node/codex/codexSessionConfigKeys.test|title=codexSessionConfigKeys expands permissions presets and falls back to legacy axes|occurrence=1codexSessionConfigKeys.t…codexSessionConfigKeys.test|title=codexSessionConfigKeys inverts presets and migrates legacy axes without escalating|occurrence=1 · introduced test · mocha:v1|namespace=vscode@05c208e9e28d8c1c723fa08f85e2b7a96092e8e5|file=vs/platform/agentHost/test/node/codex/codexSessionConfigKeys.test|title=codexSessionConfigKeys inverts presets and migrates legacy axes without escalating|occurrence=1codexSessionConfigKeys.t…codexSessionConfigKeys.test|title=codexSessionConfigKeys narrows valid values and rejects invalid values|occurrence=1 · introduced test · mocha:v1|namespace=vscode@05c208e9e28d8c1c723fa08f85e2b7a96092e8e5|file=vs/platform/agentHost/test/node/codex/codexSessionConfigKeys.test|title=codexSessionConfigKeys narrows valid values and rejects invalid values|occurrence=1codexSessionConfigKeys.t…codexSessionConfigKeys.test|title=codexSessionConfigKeys resolveSessionConfig exposes a single permissions-preset chip|occurrence=1 · introduced test · mocha:v1|namespace=vscode@05c208e9e28d8c1c723fa08f85e2b7a96092e8e5|file=vs/platform/agentHost/test/node/codex/codexSessionConfigKeys.test|title=codexSessionConfigKeys resolveSessionConfig exposes a single permissions-preset chip|occurrence=1codexSessionConfigKeys.t…codexSessionConfigKeys.test|title=codexSessionConfigKeys resolveSessionConfig preserves legacy read-only permissions on restore|occurrence=1 · introduced test · mocha:v1|namespace=vscode@05c208e9e28d8c1c723fa08f85e2b7a96092e8e5|file=vs/platform/agentHost/test/node/codex/codexSessionConfigKeys.test|title=codexSessionConfigKeys resolveSessionConfig preserves legacy read-only permissions on restore|occurrence=1codexSessionConfigKeys.t…Focused concept · codexAppServerClient.ts ×15 · 238 introduced LOCcodexAppServerClient.ts …

Graph controls are ready.

Interactive rendering requires JavaScript and WebGL. Use the native relationship evidence on this page while the interactive map is unavailable.

Native relationship evidence

Every exact file and test below is linked only from the concept that introduces it.

Introduced tests

Every collected test enters the hierarchy at exactly one concept.

No tests are introduced at this concept. Its intent tests are introduced by other concepts.

Introduced code

Every collected source range enters the hierarchy at exactly one concept.

1 file ranked by introduced lines: 238 introduced LOC across 15 ranges. Expand a file to inspect source; the > gutter marks introduced lines.

src/vs/platform/agentHost/node/codex/codexAppServerClient.ts 238 introduced LOC · 15 ranges

Open complete file

1 > /*--------------------------------------------------------------------------------------------- codexAppServerClient.ts
2 > * Copyright (c) Microsoft Corporation. All rights reserved.
3 > * Licensed under the MIT License. See License.txt in the project root for license information.
4 > *--------------------------------------------------------------------------------------------*/
5 >
6 > import type { Readable, Writable } from 'stream';
7 > import { CancellationError } from '../../../../base/common/errors.js';
8 > import { Emitter, Event } from '../../../../base/common/event.js';
9 > import { Disposable, type IDisposable, toDisposable } from '../../../../base/common/lifecycle.js';
10 > import { hasKey } from '../../../../base/common/types.js';
11 > import type { ClientNotification } from './protocol/generated/ClientNotification.js';
12 > import type { ClientRequest } from './protocol/generated/ClientRequest.js';
13 > import type { RequestId } from './protocol/generated/RequestId.js';
14 > import type { ServerNotification } from './protocol/generated/ServerNotification.js';
15 > import type { ServerRequest } from './protocol/generated/ServerRequest.js';
16 >
17 > // #region Wire types
18 > //
19 > // JSON-RPC 2.0 over NDJSON, with the `"jsonrpc": "2.0"` field *omitted on
20 > // the wire* per the codex app-server convention. The generated
21 > // `ClientRequest` / `ClientNotification` / `ServerRequest` /
22 > // `ServerNotification` unions encode `method` + `params` shapes; we add
23 > // `id` + `result` / `error` envelopes on top.
24 >
25 > interface IWireResponseSuccess<R = unknown> {
26 > readonly id: RequestId;
27 > readonly result: R;
28 > readonly error?: undefined;
29 > readonly method?: undefined;
30 > }
31 >
32 > interface IWireResponseError {
33 > readonly id: RequestId;
34 > readonly result?: undefined;
35 > readonly error: { readonly code: number; readonly message: string; readonly data?: unknown };
36 > readonly method?: undefined;
37 > }
38 >
39 > type WireMessage = ClientNotification | ClientRequest | ServerNotification | ServerRequest | IWireResponseSuccess | IWireResponseError;
40 >
41 > // #endregion
42 >
43 > /**
44 > * Standard JSON-RPC error codes.
45 > *
46 > * @see https://www.jsonrpc.org/specification#error_object
47 > */
48 > export const enum JsonRpcErrorCode {
49 > ParseError = -32700,
50 > InvalidRequest = -32600,
51 > MethodNotFound = -32601,
52 > InvalidParams = -32602,
53 > InternalError = -32603,
54 > }
55 >
56 > /**
57 > * Error thrown when a remote request responds with an `error` envelope.
58 > */
59 > export class JsonRpcError extends Error {
60 > constructor(
61 readonly code: number,
62 message: string,
66 this.name = 'JsonRpcError';
67 }
69 >
70 > // #region Typed method projections
71 > //
72 > // Extract `<method>` → `params` / `result` for each direction. The
73 > // generated unions have shape `{ method: "x/y", id?: RequestId, params: P
74 > // }`, so a discriminated-union pick works as a method-keyed lookup.
75 >
76 > type MethodOf<U> = U extends { method: infer M } ? M : never;
77 > type ParamsOf<U, M> = U extends { method: M; params: infer P } ? P : never;
78 >
79 > export type ClientRequestMethod = MethodOf<ClientRequest>;
80 > export type ClientNotificationMethod = MethodOf<ClientNotification>;
81 > export type ServerRequestMethod = MethodOf<ServerRequest>;
82 > export type ServerNotificationMethod = MethodOf<ServerNotification>;
83 >
84 > export type ClientRequestParams<M extends ClientRequestMethod> = ParamsOf<ClientRequest, M>;
85 > export type ClientNotificationParams<M extends ClientNotificationMethod> = ParamsOf<ClientNotification, M>;
86 > export type ServerRequestParams<M extends ServerRequestMethod> = ParamsOf<ServerRequest, M>;
87 > export type ServerNotificationParams<M extends ServerNotificationMethod> = ParamsOf<ServerNotification, M>;
88 >
89 > // `result` for client-issued requests doesn't have a single generated
90 > // union; each method has its own `<X>Response` type. We surface the
91 > // response shape as a generic parameter on `request<M, R>` so callers
92 > // can name the response type explicitly, defaulting to `unknown`.
93 >
94 > // #endregion
95 >
96 > /**
97 > * Result of a server→client request. Either a successful result payload
98 > * or a JSON-RPC error envelope. Implementations of
99 > * {@link ICodexAppServerClient.onRequest} return one of these.
100 > */
101 > export type ServerRequestHandlerResult<R = unknown> =
102 > | { readonly result: R; readonly error?: undefined }
103 > | { readonly result?: undefined; readonly error: { readonly code: number; readonly message: string; readonly data?: unknown } };
104 >
105 > /**
106 > * Subset of `ChildProcessWithoutNullStreams` we actually use, so callers
107 > * can pass either a real child process or an in-memory pair for tests.
108 > */
109 > export interface ICodexAppServerTransport {
110 > readonly stdin: Writable;
111 > readonly stdout: Readable;
112 > /** Force termination. Used as the 2 s grace force-kill fallback. */
113 > kill(signal?: NodeJS.Signals): boolean;
114 > /** Fires when the underlying process exits. */
115 > readonly onExit: Event<{ readonly code: number | null; readonly signal: NodeJS.Signals | null }>;
116 > /** Registers a one-shot exit listener that may outlive client disposal. */
117 > onExitOnce(listener: (e: { readonly code: number | null; readonly signal: NodeJS.Signals | null }) => void): void;
118 > }
119 >
120 > /**
121 > * Generic JSON-RPC client over a {@link ICodexAppServerTransport}.
122 > *
123 > * The client doesn't know anything about codex's domain — it just
124 > * brokers typed requests and notifications in both directions. The
125 > * `CodexAgent` layer above translates this into `IAgent` semantics.
126 > *
127 > * Lifecycle:
128 > * - Construct with an active transport. The client immediately starts
129 > * reading from `transport.stdout`.
130 > * - Send requests / notifications via {@link request} / {@link notify}.
131 > * - Register handlers for server-initiated traffic via
132 > * {@link onNotification} / {@link onRequest}.
133 > * - On `dispose()`: send EOF on stdin, wait up to 2 s for clean exit,
134 > * then SIGKILL. Outstanding requests reject with `CancellationError`.
135 > */
136 > export interface ICodexAppServerClient extends IDisposable {
137 > /** Fires once when the transport exits (clean or otherwise). */
138 > readonly onExit: Event<{ readonly code: number | null; readonly signal: NodeJS.Signals | null }>;
139 >
140 > /** Fires when the underlying transport rejects further writes (process exited unexpectedly). */
141 > readonly onTransportError: Event<Error>;
142 >
143 > /**
144 > * Issue a request. Resolves with the typed response payload, or
145 > * rejects with {@link JsonRpcError} for protocol-level errors and
146 > * {@link CancellationError} on dispose.
147 > */
148 > request<M extends ClientRequestMethod, R = unknown>(
149 > method: M,
150 > params: ClientRequestParams<M>,
151 > ): Promise<R>;
152 >
153 > /**
154 > * Fire-and-forget notification. Does not throw if the transport
155 > * already closed; lost notifications are surfaced via
156 > * `onTransportError`.
157 > */
158 > notify<M extends ClientNotificationMethod>(
159 > method: M,
160 > params: ClientNotificationParams<M>,
161 > ): void;
162 >
163 > /**
164 > * Register a handler for a server-pushed notification.
165 > *
166 > * Only one handler per method; subsequent registrations replace the
167 > * previous handler.
168 > */
169 > onNotification<M extends ServerNotificationMethod>(
170 > method: M,
171 > handler: (params: ServerNotificationParams<M>) => void,
172 > ): IDisposable;
173 >
174 > /**
175 > * Register a handler for a server-initiated request. The handler
176 > * returns a typed result or an error envelope.
177 > *
178 > * Only one handler per method; subsequent registrations replace the
179 > * previous handler. Unregistered methods reply with
180 > * {@link JsonRpcErrorCode.MethodNotFound}.
181 > */
182 > onRequest<M extends ServerRequestMethod, R = unknown>(
183 > method: M,
184 > handler: (params: ServerRequestParams<M>) => Promise<ServerRequestHandlerResult<R>> | ServerRequestHandlerResult<R>,
185 > ): IDisposable;
186 > }
187 >
188 > interface IPendingRequest {
189 > resolve(value: unknown): void;
190 > reject(reason: unknown): void;
191 > readonly method: string;
192 > }
193 >
194 > const GRACE_KILL_MS = 2_000;
195 >
196 > export class CodexAppServerClient extends Disposable implements ICodexAppServerClient {
197 >
198 > private readonly _onExit = this._register(new Emitter<{ readonly code: number | null; readonly signal: NodeJS.Signals | null }>());
199 > readonly onExit = this._onExit.event;
200 >
201 > private readonly _onTransportError = this._register(new Emitter<Error>());
202 > readonly onTransportError = this._onTransportError.event;
203 >
204 > private _nextId = 1;
205 > private readonly _pending = new Map<number, IPendingRequest>();
206 > private readonly _notificationHandlers = new Map<string, (params: unknown) => void>();
207 > private readonly _requestHandlers = new Map<string, (params: unknown) => Promise<ServerRequestHandlerResult<unknown>>>();
208 >
209 > private _exited = false;
210 > private _disposed = false;
211 > private _buf = '';
212 >
213 > constructor(
214 private readonly _transport: ICodexAppServerTransport,
215 private readonly _onLog?: (level: 'info' | 'warn' | 'error', message: string) => void,
221 this._register(this._listenToStdout());
222 }
224 > private _listenToStdout(): IDisposable {
225 const onData = (chunk: string | Buffer) => {
226 const text = typeof chunk === 'string' ? chunk : chunk.toString('utf8');
247 return toDisposable(() => this._transport.stdout.off('data', onData));
248 }
250 > private _dispatch(msg: WireMessage): void {
251 const hasId = hasKey(msg, { id: true });
252 const hasMethod = hasKey(msg, { method: true });
286 this._log('warn', `unrecognized message: ${JSON.stringify(msg).slice(0, 200)}`);
287 }
289 > private async _handleServerRequest(msg: ServerRequest): Promise<void> {
290 const handler = this._requestHandlers.get(msg.method);
291 if (!handler) {
315 }
316 }
318 > private _handleServerNotification(msg: ServerNotification): void {
319 const handler = this._notificationHandlers.get(msg.method);
320 if (!handler) {
331 }
332 }
334 > private _writeMessage(message: unknown): boolean {
335 if (this._exited || this._disposed) {
336 return false;
344 }
345 }
347 > private _handleExit(e: { code: number | null; signal: NodeJS.Signals | null }): void {
348 if (this._exited) {
349 return;
357 this._onExit.fire(e);
358 }
360 > request<M extends ClientRequestMethod, R = unknown>(
361 method: M,
362 params: ClientRequestParams<M>,
378 });
379 }
381 > notify<M extends ClientNotificationMethod>(
382 method: M,
383 params: ClientNotificationParams<M>,
391 this._writeMessage(payload);
392 }
394 > onNotification<M extends ServerNotificationMethod>(
395 method: M,
396 handler: (params: ServerNotificationParams<M>) => void,
403 });
404 }
406 > onRequest<M extends ServerRequestMethod, R = unknown>(
407 method: M,
408 handler: (params: ServerRequestParams<M>) => Promise<ServerRequestHandlerResult<R>> | ServerRequestHandlerResult<R>,
418 });
419 }
421 > override dispose(): void {
422 if (this._disposed) {
423 return;
447 super.dispose();
448 }
450 > private _log(level: 'info' | 'warn' | 'error', message: string): void {
451 this._onLog?.(level, message);
452 }
454 >
455 > /**
456 > * Wrap a {@link import('node:child_process').ChildProcessWithoutNullStreams}
457 > * into an {@link ICodexAppServerTransport}. Tests use a fake transport
458 > * built around `node:stream`'s `PassThrough` or similar.
459 > */
460 > export function transportFromChildProcess(
461 child: { stdin: Writable | null; stdout: Readable | null; kill: (signal?: NodeJS.Signals) => boolean; on: (event: 'exit', listener: (code: number | null, signal: NodeJS.Signals | null) => void) => unknown; once: (event: 'exit', listener: (code: number | null, signal: NodeJS.Signals | null) => void) => unknown; removeListener: (event: 'exit', listener: (code: number | null, signal: NodeJS.Signals | null) => void) => unknown },
462 ): ICodexAppServerTransport {