Skip to content

feat(extension): migrate task transport from gRPC to JSON-RPC over TCP loopback (PR 2/3)#1864

Merged
wenytang-ms merged 17 commits into
developfrom
wenyt/jsonrpc-ts
Jun 1, 2026
Merged

feat(extension): migrate task transport from gRPC to JSON-RPC over TCP loopback (PR 2/3)#1864
wenytang-ms merged 17 commits into
developfrom
wenyt/jsonrpc-ts

Conversation

@wenytang-ms
Copy link
Copy Markdown
Contributor

@wenytang-ms wenytang-ms commented May 28, 2026

Migrate task transport from gRPC to JSON-RPC over TCP loopback (PR 2/3)

Companion to #1863 (PR 1/3, gradle-server Java side). Together they replace the gRPC + Netty + HTTP/2 task transport with JSON-RPC (LSP4J wire format) over a plain TCP loopback connection, permanently eliminating the mid-frame race described in #1815.

This PR is the TypeScript extension half of the hard cut-over: it deletes the gRPC client and rebuilds TaskServerClient on top of vscode-jsonrpc. No version ships between PR 1, PR 2 and PR 3.

What changes

New transport package — extension/src/transport/jsonrpc/

File Role
GradleJsonRpcClient.ts Typed facade over MessageConnection. Exposes the six gradle/* methods (getBuild, runBuild, getProjectDependencies, cancelBuild, cancelBuilds, executeCommand) and demultiplexes the two streaming gradle/*/reply notifications back to per-call callbacks by streamId.
loopbackServer.ts Binds 127.0.0.1:0, returns { port, connection: Promise<MessageConnection> }. Accepts a single inbound socket, wraps it with SocketMessageReader/Writer, enforces a 30 s connect timeout (matches TaskSocketServer.CONNECT_TIMEOUT_MS on the Java side).
protoCodec.ts encodeProto(Uint8Array): string / decodeProto(string): Uint8Array — base64 ↔ proto bytes.
streamId.ts Monotonic id generator for streaming RPCs.
JsonRpcErrors.ts Pinned numeric codes (UNKNOWN=-32000, NOT_FOUND=-32001, CANCELLED=-32002, INTERNAL=-32603) + GradleRpcError shape + isNotFound/isCancelled/isUnknown helpers + toGradleRpcError(ResponseError) converter.
types.ts GradleRequestParams, GradleResponse, GradleStreamPayload — the wire shapes pinned by PR 1.

Architecture flip — extension listens, JVM dials in

PR 1 turned the JVM into a TCP client (TaskSocketServer). PR 2 makes the extension the TCP server:

  • GradleServer.start() now calls createLoopbackListener() before spawning the JVM, then passes the bound ephemeral port via the same --port=<n> arg. This eliminates any window where the JVM could try to connect before the extension is ready.
  • New GradleServer.awaitTaskConnection(): Promise<MessageConnection> exposes the resulting connection to TaskServerClient.

TaskServerClient.ts — full rewrite

  • Drops GrpcClient, grpc.credentials.createInsecure, waitForReady, getChannel().getConnectivityState, and the @grpc/grpc-js/gradle_grpc_pb imports.
  • Replaces them with GradleJsonRpcClient wrapping the MessageConnection received from GradleServer.awaitTaskConnection().
  • Error branching now uses isNotFound(err) / isCancelled(err) / isUnknown(err) from JsonRpcErrors.
  • Drops the retryOnSpuriousCancel wrappers — the Node.js HTTP/2 stream race the helper compensated for cannot occur over plain TCP + LSP4J framing.

GradleRunnerTerminal.ts

  • import { ServiceError, status } from "@grpc/grpc-js" → import from transport/jsonrpc.
  • err.code === status.UNKNOWNisUnknown(err).

Cleanup (no compat shims, per the design)

  • Delete extension/src/proto/gradle_grpc_pb.{js,d.ts} (no longer generated).
  • Delete extension/src/client/retryOnSpuriousCancel.ts and its unit test.
  • extension/build.gradle: drop protobuf.plugins.grpc { … }, drop the per-task grpc { … } wiring, drop ts { option 'service=grpc-node,mode=grpc-js' } so protoc-gen-ts stops emitting service stubs. The js builtin + ts plugin remain — gradle_pb.{js,d.ts} are still generated and used for message classes.
  • extension/package.json: remove @grpc/grpc-js and grpc-tools from devDependencies; add vscode-jsonrpc: ^6.0.0 to dependencies (was already transitively present via vscode-languageclient, now pinned as a direct dep).
  • Extension.ts: drop the now-unused clientLogger (was only used to set the grpc-js global logger).

Wire contract (pinned by PR 1)

Aspect Value
Method namespace gradle/
Methods getBuild, runBuild, getProjectDependencies, cancelBuild, cancelBuilds, executeCommand
Streaming notifications gradle/getBuild/reply, gradle/runBuild/reply
Request params { request: string | null, streamId: number | null }request is base64 of proto bytes; streamId set only on streaming RPCs
Response { reply: string | null } — base64 of terminal *Reply proto bytes (null for streaming RPCs whose full payload was delivered via notifications)
Notification payload { streamId: number, payload: string } — base64 of streamed *Reply proto bytes
Error codes -32000 UNKNOWN, -32001 NOT_FOUND, -32002 CANCELLED, -32603 INTERNAL

JSON-RPC communication design

Streaming model — request + correlated notifications + terminal reply

gRPC server-streaming (GetBuild, RunBuild) is reshaped onto JSON-RPC's request/notification split:

  • The incremental replies arrive as gradle/*/reply notifications, each carrying its streamId.
  • The terminal reply rides on the JSON-RPC response to the original request (or reply: null when the full payload was already delivered via notifications).

This split is required because a JSON-RPC notification has no id to await, while only the response can settle the call's promise. Per-call lifecycle in GradleJsonRpcClient: allocate a streamId → register its sink → send the request → each inbound notification is dispatched to the sink keyed by streamId → the response resolves the promise → the sink is removed in a finally. A late notification arriving after the promise settles finds no sink (Map.getundefined) and is silently dropped, so it can never bleed into another in-flight call.

Cancellation — business-level, not $/cancelRequest

Cancellation does not use JSON-RPC's $/cancelRequest. It keeps the existing business-level contract: a separate cancelBuild RPC carrying the cancellationKey. The streaming request's promise stays open until the server emits a terminal Cancelled reply. This mirrors the previous gRPC behaviour and keeps cancellation semantics identical across the cut-over.

Single connection — strict ordering, deliberate head-of-line tradeoff

All six methods and both notification streams share one TCP socket with LSP4J Content-Length framing, which guarantees strict in-order delivery — this is exactly what makes "all of a stream's notifications arrive before its terminal response" hold, and is the basis of the streaming correctness above. The tradeoff is no multiplexing: concurrent builds are serialized on a single connection. That is intentional — collapsing to one non-multiplexed socket is precisely what removes the HTTP/2 frame race behind #1815.

Connection lifecycle & failure semantics

On socket close/error the MessageConnection fires onClose/onError and any in-flight sendRequest promises reject. There is no auto-reconnect at the transport layer: a dropped connection surfaces as a rejected call, and recovery goes through the existing GradleServer JVM-exit handler + restart() path. This is consistent with dropping retryOnSpuriousCancel — there is no silent retry on the wire.

Security model (current) — and deferred handshake auth

The listener binds 127.0.0.1 only (no remote reachability), accepts only the first inbound connection, and enforces a 30 s connect timeout. The ephemeral port comes from listen(0) (kernel-assigned free port — no port-probe race, no collision-retry needed). A cryptographic handshake nonce to authenticate the connecting JVM (so a same-host process cannot pre-empt the real JVM by connecting to the loopback port first) was considered but is intentionally deferred — not implemented in this PR, tracked as a follow-up. Note: switching ports would not substitute for it, since any loopback port is enumerable and reachable by same-host processes regardless of its number.

Tests

New extension/src/test/unit/transport/GradleJsonRpcClient.test.ts (7 tests, all passing locally):

  • Base64 proto codec roundtrip.
  • getBuild streaming dispatch — multiple notifications, terminal reply: null response.
  • Concurrent streaming calls multiplexed by streamId without cross-pollination.
  • runBuild streaming dispatch.
  • Unary getProjectDependencies / cancelBuild / cancelBuilds / executeCommand roundtrip.
  • ResponseError translation into GradleRpcError for NOT_FOUND / CANCELLED / INTERNAL.

The test wires two MessageConnections back-to-back over PassThrough streams, mirroring the LSP4J piped-streams setup used by PR 1's JsonRpcTransportTest.java.

Existing unit tests: pass (npm run compile, npm run lint:eslint — 0 errors, only pre-existing no-explicit-any warnings unrelated to this PR).

What is intentionally not in this PR

  • proto/gradle.proto still defines service Gradle { … } — unused after this PR, removed in PR 3.
  • The root build.gradle's grpcVersion, grpc-protobuf-lite, etc. — still referenced by the Java module post-PR 1 cleanup (the Java side keeps the proto message classes generated). Final removal in PR 3.

Risk log

Risk Mitigation
vscode-jsonrpc major-version mismatch with the one vscode-languageclient already resolves Pinned to ^6.0.0 matching the resolved transitive; npm dedups to a single instance.
Loopback listener never gets an inbound connect (JVM crashes early) 30 s connect timeout; the existing JVM-process-exit handler in GradleServer.ts continues to handle the failure path.
Removing retryOnSpuriousCancel re-surfaces a transient cancel The retry only ever masked a Node.js HTTP/2 race that does not exist over plain TCP. PR 1's TaskSocketServer uses a single non-multiplexed TCP socket.

Closes #1815 once PR 1 + PR 2 land together (default branch behavior change ships only after both are merged).

wenytang-ms and others added 3 commits May 27, 2026 16:54
…r TCP loopback

Replace the existing gRPC + Netty HTTP/2 transport for the task server with
LSP4J JSON-RPC over a plain TCP loopback socket. This eliminates the
mid-frame HTTP/2 race (vscode-gradle issue #1815) at its source by removing
the Netty stack from the task-server hot path entirely.

What changes on the gradle-server side
- New package 	ransport.jsonrpc exposing six methods on gradle/ segment:
  getBuild, runBuild, getProjectDependencies, cancelBuild, cancelBuilds,
  executeCommand. Streaming RPCs (getBuild/runBuild) deliver intermediate
  progress through gradle/getBuild/reply and gradle/runBuild/reply
  notifications and complete the JSON-RPC request with the terminal reply.
- Protobuf wire schema (proto/gradle.proto) is reused for payload bytes;
  request/response/notification params carry the base64-encoded proto
  bytes plus a stream id. This keeps the message layer stable across the
  migration and avoids a JSON re-encoding of large progress payloads.
- GradleServer becomes a thin bootstrap: it connects out to the Node
  listener on 127.0.0.1:<port>, builds an LSP4J launcher backed by a
  cached worker pool, and blocks until the socket closes.
- Handlers no longer hold gRPC StreamObservers. Streaming handlers take
  (Request, CompletableFuture<GradleResponse>, GradleClient, long streamId);
  unary handlers take (Request, CompletableFuture<GradleResponse>).

Removed
- io.grpc:grpc-protobuf, grpc-stub, grpc-netty (plus grpc-testing)
  dependencies, the protoc-gen-grpc-java plugin, and the
  �uild/generated/source/proto/main/grpc source set.
- TaskService (gRPC service shim) and ErrorMessageBuilder (only used
  by the gRPC error path).
- The Netty HTTP/2 mid-frame log filter and its tests
  (GradleServerFilterTest).
- Forced
etty-bom pin (no longer relevant since Netty is gone from
  the task-server runtime).

Tests
- GradleServerTest now exercises handlers directly via
  CompletableFuture<GradleResponse> and a Mockito-mocked GradleClient,
  so the test surface verifies Gradle Tooling API interactions without
  spinning up a gRPC InProcess channel.
- One extra --add-opens (java.util.concurrent) is added to the test
  JVM args so PowerMock can introspect CompletableFuture on JDK 17+.

This commit is the gradle-server half of the migration. The TypeScript
extension still speaks gRPC and is updated in PR 2; the proto files and
the root-build grpcVersion constant are cleaned up in PR 3.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
…ip tests

Add JsonRpcTransportTest exercising the new transport package end-to-end
over a pair of piped streams. Two Launcher instances are wired together
(server side: GradleService stub + GradleClient remote proxy; client
side: recording GradleClient + GradleService remote proxy) so the full
request/response/notification path is driven without a real socket and
without a dependency on the Gradle Tooling API.

Coverage:
- Base64 protobuf encode/decode roundtrip via JsonRpcCodec.
- All six RPC methods (getBuild, 
unBuild, getProjectDependencies,
  cancelBuild, cancelBuilds, �xecuteCommand) — payload identity,
  stream-id propagation, and null 
eply handling.
- Streaming notifications: getBuild/reply carries the right stream id
  and payload to the client side; 
unBuild/reply is delivered on the
  separate 
unBuild notification channel without leaking into the
  getBuild channel.
- Error mapping across the wire for ResponseErrorException produced by
  JsonRpcCodec.error(...) — covers NOT_FOUND, CANCELLED and
  INTERNAL (the last one via a Throwable carrier).
- Pinned constants for the four error codes that form part of the wire
  contract with the TS client, to catch accidental renumbering.

The handler-level behaviour (Gradle Tooling API interaction, debug init
script, JVM args, etc.) stays covered by GradleServerTest, which talks
to handlers directly via CompletableFuture<GradleResponse> rather than
through the JSON-RPC dispatch layer — so the two test classes between
them cover the wire layer and the business logic without overlapping.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR migrates the extension-side Gradle task transport from gRPC to JSON-RPC over a TCP loopback listener, matching the Java-side transport cut-over and removing the gRPC client/stub path.

Changes:

  • Adds a new transport/jsonrpc package with loopback listener setup, proto/base64 codec, stream ID allocation, JSON-RPC error mapping, and a typed GradleJsonRpcClient.
  • Rewires GradleServer, TaskServerClient, and terminal error handling to use the JSON-RPC connection instead of gRPC.
  • Removes gRPC code generation/dependencies and deletes the spurious-cancel retry helper/tests.

Reviewed changes

Copilot reviewed 17 out of 18 changed files in this pull request and generated 1 comment.

Show a summary per file
File Description
extension/src/transport/jsonrpc/types.ts Defines JSON-RPC wire DTO shapes.
extension/src/transport/jsonrpc/streamId.ts Adds stream ID allocation for multiplexed streaming RPCs.
extension/src/transport/jsonrpc/protoCodec.ts Adds base64 encoding/decoding for protobuf payloads.
extension/src/transport/jsonrpc/loopbackServer.ts Adds loopback TCP listener for JVM callback connection.
extension/src/transport/jsonrpc/JsonRpcErrors.ts Adds JSON-RPC error constants and conversion helpers.
extension/src/transport/jsonrpc/index.ts Exports the new transport package API.
extension/src/transport/jsonrpc/GradleJsonRpcClient.ts Implements typed JSON-RPC facade for Gradle task operations.
extension/src/test/unit/transport/loopbackServer.test.ts Tests listener binding, connection resolution, and logger forwarding.
extension/src/test/unit/transport/GradleJsonRpcClient.test.ts Tests codec, unary RPCs, streaming dispatch, multiplexing, and error translation.
extension/src/test/unit/retryOnSpuriousCancel.test.ts Removes tests for deleted gRPC retry helper.
extension/src/terminal/GradleRunnerTerminal.ts Updates task terminal error handling to JSON-RPC errors.
extension/src/server/GradleServer.ts Creates the loopback listener before spawning the JVM and exposes the accepted connection.
extension/src/Extension.ts Replaces gRPC client logger wiring with JSON-RPC transport logger wiring.
extension/src/client/TaskServerClient.ts Rewrites task client calls from gRPC stubs/streams to GradleJsonRpcClient.
extension/src/client/retryOnSpuriousCancel.ts Deletes the gRPC-specific retry helper.
extension/package.json Removes gRPC dev dependencies and adds direct vscode-jsonrpc dependency.
extension/package-lock.json Updates dependency lockfile for gRPC removal and JSON-RPC direct dependency.
extension/build.gradle Removes gRPC service stub generation while preserving protobuf message generation.
Files not reviewed (1)
  • extension/package-lock.json: Language not supported

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread extension/src/transport/jsonrpc/loopbackServer.ts
@wenytang-ms wenytang-ms changed the base branch from develop to wenyt/jsonrpc-java May 29, 2026 06:19
- GradleServiceImpl: validate JSON-RPC params/request nullability and map
  Base64 decode errors to ERROR_UNKNOWN instead of ERROR_INTERNAL so
  client-side input bugs surface with the correct wire code.
- ExecuteCommandHandler: split error replies so unknown commands return
  ERROR_NOT_FOUND and argument-count violations return ERROR_UNKNOWN;
  reserve ERROR_INTERNAL for genuine server failures.
- GradleServer: extract a workerThreadFactory() that hands out unique
  `gradle-jsonrpc-worker-N` names via AtomicInteger so concurrent
  handlers are distinguishable in thread dumps and logs.

Adds regression coverage:
- JsonRpcTransportTest: 4 new tests for null params, null request,
  invalid Base64, and null cancelBuilds params.
- ExecuteCommandHandlerTest (new): 4 tests covering the new error code
  mapping plus the happy path.
- GradleServerThreadFactoryTest (new): 3 tests covering unique naming,
  daemon flag, and per-instance counter isolation.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@wenytang-ms wenytang-ms changed the base branch from wenyt/jsonrpc-java to develop May 29, 2026 07:22
@wenytang-ms wenytang-ms reopened this May 29, 2026
wenytang-ms and others added 11 commits June 1, 2026 10:26
…P loopback (PR 2/3)

Pairs with PR 1 (gradle-server Java side) to complete the cut-over from
@grpc/grpc-js to vscode-jsonrpc as the wire transport for task RPCs:

- Add `extension/src/transport/jsonrpc/` package: `GradleJsonRpcClient` (typed
  facade over `MessageConnection` exposing the six `gradle/*` methods plus the
  two `gradle/*/reply` streaming notifications), `loopbackServer` (binds
  `127.0.0.1:0` and resolves to a `MessageConnection` on inbound connect),
  `protoCodec`/`streamId`/`JsonRpcErrors` helpers, `types` wire shapes.
- Flip `GradleServer` to listen-then-spawn: the extension now binds the
  ephemeral port before launching the JVM, then passes it via `--port=N`;
  the JVM (PR 1) connects back as a TCP client. Adds
  `GradleServer.awaitTaskConnection()` so the client can pick up the
  inbound `MessageConnection`.
- Rewrite `TaskServerClient` end-to-end against `GradleJsonRpcClient`:
  the six RPCs now go through JSON-RPC, error-branching uses the new
  `JsonRpcErrors` codes (`NOT_FOUND`/`CANCELLED`/`UNKNOWN`/`INTERNAL`)
  via `isNotFound`/`isCancelled`/`isUnknown` helpers, and the gRPC-only
  `retryOnSpuriousCancel` wrappers are dropped (no HTTP/2 stream race
  exists under plain TCP).
- Update `GradleRunnerTerminal.handleError` to use `isUnknown` instead of
  `grpc.status.UNKNOWN`.
- Remove gRPC plumbing: delete `proto/gradle_grpc_pb.{js,d.ts}`,
  `client/retryOnSpuriousCancel.ts`; strip `protobuf.plugins.grpc` /
  `task.plugins.grpc` / `task.plugins.ts { option 'service=...' }` from
  `extension/build.gradle`; drop `@grpc/grpc-js` and `grpc-tools` from
  `devDependencies` and add `vscode-jsonrpc` (^6.0.0) to `dependencies`.
- `Extension.ts`: drop the now-unused gRPC `clientLogger`.

Closes #1815 once PR 1 + PR 2 land together. PR 3 will remove the now-unused
`service Gradle` block from `proto/gradle.proto` and the `grpcVersion`
entry from the root `build.gradle`.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
…oundtrip tests

Mirrors PR 1's `JsonRpcTransportTest` on the TS side. Wires two
`MessageConnection`s back-to-back over `PassThrough` streams and drives
`GradleJsonRpcClient` against a vanilla server-side `MessageConnection`,
 covering:

- Base64 proto codec roundtrip.
- `getBuild` streaming dispatch (multiple notifications, terminal null response).
- Concurrent streaming calls multiplexed by `streamId` without cross-pollination.
- `runBuild` streaming dispatch.
- Unary `getProjectDependencies` / `cancelBuild` / `cancelBuilds` / `executeCommand`.
- `ResponseError` translation back into `GradleRpcError` for the
  `NOT_FOUND` / `CANCELLED` / `INTERNAL` codes that callers branch on.

Also removes the obsolete `retryOnSpuriousCancel` test now that the helper
it covered is gone from the gRPC cut-over.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Self-review caught that `GradleServer.start()` was binding the loopback
listener before the `getGradleServerEnv()` null-check. On the no-Java path
the early `return` left the listener bound, the 30 s connect timer armed,
and the `awaitTaskConnection()` promise un-consumed (`_onDidStart` never
fires when env is missing, so `TaskServerClient.connectToServer` is never
reached). The eventual rejection surfaced as an `UnhandledPromiseRejection`.

Move the listener creation below the env check so the no-Java path leaves
no bound socket or pending promise behind.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
…sport diagnostics

Forward vscode-jsonrpc protocol logs into a project Logger channel so transport-level errors/warnings are visible in the existing Gradle output, matching the prior Logger("grpc") behaviour without coupling the transport package to the project Logger class.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
…ding

Two unit tests for createLoopbackListener:  - Asserts an ephemeral 127.0.0.1 port is bound and the connection promise    resolves on the first inbound socket.  - Asserts a user-supplied vscode-jsonrpc Logger receives protocol-level    diagnostics by sending a framed payload that is neither request, response,    nor notification and confirming the spy's �rror callback was invoked.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
…accept

If createLoopbackListener().dispose() runs before any inbound JVM socket is accepted (e.g. GradleServer's exit handler tearing the listener down after a failed JVM spawn), the connection promise was left unsettled, making TaskServerClient.connectToServer() and other awaiters hang forever.

Capture the reject callback and invoke it from dispose() when no socket has been accepted, with a regression test.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
The Java handlers send the terminal GetBuildReply (containing
GET_BUILD_RESULT) and terminal RunBuildReply (containing CANCELLED or
RUN_BUILD_RESULT) as the JSON-RPC response body, not as a stream
notification. The TS side was discarding the response and only processing
stream notifications, so getBuild always returned undefined and the task
list never populated.

Extract the reply handler into a local function and invoke it on the
terminal reply returned by getBuild()/runBuild() before returning.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Regression coverage for the fix in 6f8f396: the terminal GetBuildReply
/ RunBuildReply (carrying GET_BUILD_RESULT or RUN_BUILD_RESULT) arrives
on the JSON-RPC response body, not as a stream notification. The new
cases assert that getBuild()/runBuild() return the decoded terminal
reply so callers can read the build result.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@wenytang-ms wenytang-ms changed the base branch from develop to wenyt/jsonrpc-java June 1, 2026 05:28
Base automatically changed from wenyt/jsonrpc-java to develop June 1, 2026 05:44
@wenytang-ms wenytang-ms merged commit 299c90b into develop Jun 1, 2026
6 checks passed
@wenytang-ms wenytang-ms deleted the wenyt/jsonrpc-ts branch June 1, 2026 06:07
wenytang-ms added a commit that referenced this pull request Jun 1, 2026
…1867)

Both transport halves now speak JSON-RPC over a TCP loopback socket
(#1863 PR 1/3, #1864 PR 2/3). This final cleanup removes the now-dead
gRPC references so the repo has zero gRPC plumbing and is ready to cut
a release.

- proto/gradle.proto: delete the `service Gradle { ... }` block (all
  message definitions stay - they remain the JSON-RPC payload schema).
- build.gradle: delete the unused `grpcVersion` ext property.
- cgmanifest.json: drop the 4 stale io.grpc maven entries (deps removed
  in PR 1/3).
- ThirdPartyNotices.txt: drop the grpc notice + renumber the index.
- npm-package: drop the unused `@grpc/grpc-js` dependency + refresh lock.
- extension/webpack.config.js: drop the dead `@grpc/proto-loader` external.
- docs (README/ARCHITECTURE/CONTRIBUTING): describe the transport as
  JSON-RPC over TCP loopback instead of gRPC.
- code comments: reword stale/legacy "gRPC" mentions to "legacy
  transport" while keeping the error-code-parity rationale.

No runtime behavior change; no proto schema change; log/telemetry paths
untouched.
wenytang-ms added a commit that referenced this pull request Jun 1, 2026
Follow-up cleanup after the JSON-RPC transport migration (#1863, #1864,
#1867). These three message types were the last grpc-named identifiers
left in the codebase.

- proto/gradle.proto: GrpcGradleClosure/Method/Field ->
  GradleClosureProto/MethodProto/FieldProto (and the pluginClosures field
  reference). Renaming a message does not change protobuf wire format
  (field numbers/tags are unchanged), and both ends regenerate from the
  same proto.
- GetBuildHandler.java: updated imports and usages. The "Proto" suffix
  avoids colliding with the existing com.microsoft.gradle.api domain
  models GradleClosure/Method/Field used in the same file.
- .vscode/settings.json: drop the now-unused "Grpc" cSpell word ("Proto"
  is already present).

Verified: extension proto regenerated, tsc passes; gradle-server proto
codegen + GetBuildHandler resolve the new symbols; spotless clean.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Gradle Encountered end-of-stream mid-frame

3 participants