authorgravatar for 206951365+cursor[bot]@users.noreply.github.comcursor[bot] <206951365+cursor[bot]@users.noreply.github.com> 2026-05-06 10:36:25-07:00
committergravatar for noreply@github.comGitHub <noreply@github.com> 2026-05-06 10:36:25-07:00
log22384ae977a362c547d6f57d4e3d92bbe55ee5db
tree69abe70575df5c0862210ab80b2ec4dc027ee2a2
parent499f1463d5fe80350b34a6d511bdd873dd3d564f
signature Signed by PGP key B5690EEEBB952194

Adopt Effect JSON and DateTime idioms (#2559)

Co-authored-by: Cursor Agent <cursoragent@cursor.com> Co-authored-by: Julius Marminge <juliusmarminge@users.noreply.github.com>

3 files changed, 38 insertions(+), 24 deletions(-)

packages/effect-codex-app-server/src/protocol.test.ts+8-4
......@@ -2,6 +2,7 @@ import * as Deferred from "effect/Deferred";
22import * as Effect from "effect/Effect";
33import * as Fiber from "effect/Fiber";
44import * as Queue from "effect/Queue";
5import * as Schema from "effect/Schema";
56import * as Stream from "effect/Stream";
67
78import * as NodeServices from "@effect/platform-node/NodeServices";
......@@ -13,7 +14,10 @@ import { makeInMemoryStdio } from "./_internal/stdio.ts";
1314
1415const encoder = new TextEncoder();
1516
16const encodeJsonl = (value: unknown) => encoder.encode(`${JSON.stringify(value)}\n`);
17const encodeJsonl = (value: unknown) =>
18 encoder.encode(`${Schema.encodeUnknownSync(Schema.UnknownFromJsonString)(value)}\n`);
19
20const decodeJson = Schema.decodeEffect(Schema.UnknownFromJsonString);
1721
1822it.layer(NodeServices.layer)("effect-codex-app-server protocol", (it) => {
1923 it.effect(
......@@ -60,7 +64,7 @@ it.layer(NodeServices.layer)("effect-codex-app-server protocol", (it) => {
6064 const pendingInitialize = yield* transport
6165 .request("initialize", initializeParams)
6266 .pipe(Effect.forkScoped);
63 assert.deepEqual(JSON.parse(yield* Queue.take(output)), {
67 assert.deepEqual(yield* decodeJson(yield* Queue.take(output)), {
6468 id: 1,
6569 method: "initialize",
6670 params: initializeParams,
......@@ -153,7 +157,7 @@ it.layer(NodeServices.layer)("effect-codex-app-server protocol", (it) => {
153157 },
154158 },
155159 });
156 assert.deepEqual(JSON.parse(yield* Queue.take(output)), {
160 assert.deepEqual(yield* decodeJson(yield* Queue.take(output)), {
157161 id: 77,
158162 result: {
159163 answers: {
......@@ -168,7 +172,7 @@ it.layer(NodeServices.layer)("effect-codex-app-server protocol", (it) => {
168172 78,
169173 CodexError.CodexAppServerRequestError.methodNotFound("x/test"),
170174 );
171 assert.deepEqual(JSON.parse(yield* Queue.take(output)), {
175 assert.deepEqual(yield* decodeJson(yield* Queue.take(output)), {
172176 id: 78,
173177 error: {
174178 code: -32601,
packages/effect-codex-app-server/src/protocol.ts+27-18
......@@ -83,17 +83,35 @@ function isIncomingResponse(value: unknown): value is typeof JsonRpcResponseEnve
8383 return Schema.is(JsonRpcResponseEnvelope)(value);
8484}
8585
86const encodeJsonString = Schema.encodeUnknownEffect(Schema.UnknownFromJsonString);
87const decodeJsonString = Schema.decodeUnknownEffect(Schema.UnknownFromJsonString);
88
8689const encodeWireMessage = (
8790 message: Record<string, unknown>,
8891): Effect.Effect<string, CodexError.CodexAppServerProtocolParseError> =>
89 Effect.try({
90 try: () => `${JSON.stringify(message)}\n`,
91 catch: (cause) =>
92 new CodexError.CodexAppServerProtocolParseError({
93 detail: "Failed to encode Codex App Server message",
94 cause,
95 }),
96 });
92 encodeJsonString(message).pipe(
93 Effect.map((encoded) => `${encoded}\n`),
94 Effect.mapError(
95 (cause) =>
96 new CodexError.CodexAppServerProtocolParseError({
97 detail: "Failed to encode Codex App Server message",
98 cause,
99 }),
100 ),
101 );
102
103const decodeWireMessage = (
104 line: string,
105): Effect.Effect<unknown, CodexError.CodexAppServerProtocolParseError> =>
106 decodeJsonString(line).pipe(
107 Effect.mapError(
108 (cause) =>
109 new CodexError.CodexAppServerProtocolParseError({
110 detail: "Failed to decode Codex App Server wire message",
111 cause,
112 }),
113 ),
114 );
97115
98116const normalizeIncomingError = (error: unknown, detail: string): CodexError.CodexAppServerError =>
99117 Schema.is(CodexError.CodexAppServerError)(error)
......@@ -284,16 +302,7 @@ export const makeCodexAppServerPatchedProtocol = Effect.fn("makeCodexAppServerPa
284302 stage: "raw",
285303 payload: line,
286304 }).pipe(
287 Effect.flatMap(() =>
288 Effect.try({
289 try: () => JSON.parse(line),
290 catch: (cause) =>
291 new CodexError.CodexAppServerProtocolParseError({
292 detail: "Failed to decode Codex App Server wire message",
293 cause,
294 }),
295 }),
296 ),
305 Effect.flatMap(() => decodeWireMessage(line)),
297306 Effect.tap((decoded) =>
298307 logProtocol({
299308 direction: "incoming",
scripts/notify-discord-release.ts+3-2
......@@ -2,7 +2,7 @@
22
33import * as NodeRuntime from "@effect/platform-node/NodeRuntime";
44import * as NodeServices from "@effect/platform-node/NodeServices";
5import { Config, Data, Effect, Layer, Logger, Schema } from "effect";
5import { Config, Data, DateTime, Effect, Layer, Logger, Schema } from "effect";
66import { Argument, Command, Flag } from "effect/unstable/cli";
77import {
88 FetchHttpClient,
......@@ -201,6 +201,7 @@ export const notifyDiscordReleaseCommand = Command.make(
201201 );
202202
203203 const webhookUrl = yield* DiscordWebhookUrl;
204 const timestamp = DateTime.formatIso(yield* DateTime.now);
204205 const payload = buildDiscordReleaseAnnouncement({
205206 target,
206207 roleId,
......@@ -208,7 +209,7 @@ export const notifyDiscordReleaseCommand = Command.make(
208209 version: releaseVersion,
209210 tag,
210211 releaseUrl,
211 timestamp: new Date().toISOString(),
212 timestamp,
212213 });
213214
214215 yield* Effect.logInfo("discord release announcement payload built").pipe(