authorgravatar for julius0216@outlook.comJulius Marminge <julius0216@outlook.com> 2026-06-20 10:57:33-07:00
committergravatar for noreply@github.comGitHub <noreply@github.com> 2026-06-20 10:57:33-07:00
log06752526b3354a560d647251676eb9d5c8a50e82
tree58c475f71a6af9c02e62f14db3d686ca16cdc3a3
parentd87ec967bf5ef884486479e887e74307276d3e74
signature Signed by PGP key B5690EEEBB952194

[codex] Structure unavailable Bun PTY operations (#3394)

Co-authored-by: codex <codex@users.noreply.github.com>

2 files changed, 32 insertions(+), 2 deletions(-)

apps/server/src/terminal/BunPtyAdapter.test.ts created+17
...@@ -0,0 +1,17 @@
1import { expect, it } from "@effect/vitest";
2
3import { BunPtyOperationUnavailableError } from "./BunPtyAdapter.ts";
4
5it("describes unavailable Bun PTY operations structurally", () => {
6 const error = new BunPtyOperationUnavailableError({
7 operation: "resize",
8 pid: 42,
9 });
10
11 expect(error).toMatchObject({
12 _tag: "BunPtyOperationUnavailableError",
13 operation: "resize",
14 pid: 42,
15 });
16 expect(error.message).toBe("Bun PTY resize is unavailable for process 42.");
17});
apps/server/src/terminal/BunPtyAdapter.ts+15-2
...@@ -2,10 +2,23 @@...@@ -2,10 +2,23 @@
22
3import * as Effect from "effect/Effect";3import * as Effect from "effect/Effect";
4import * as Layer from "effect/Layer";4import * as Layer from "effect/Layer";
5import * as Schema from "effect/Schema";
5import { HostProcessPlatform } from "@t3tools/shared/hostProcess";6import { HostProcessPlatform } from "@t3tools/shared/hostProcess";
67
7import * as PtyAdapter from "./PtyAdapter.ts";8import * as PtyAdapter from "./PtyAdapter.ts";
89
10export class BunPtyOperationUnavailableError extends Schema.TaggedErrorClass<BunPtyOperationUnavailableError>()(
11 "BunPtyOperationUnavailableError",
12 {
13 operation: Schema.Literals(["write", "resize"]),
14 pid: Schema.Number,
15 },
16) {
17 override get message(): string {
18 return `Bun PTY ${this.operation} is unavailable for process ${this.pid}.`;
19 }
20}
21
9class BunPtyProcess implements PtyAdapter.PtyProcess {22class BunPtyProcess implements PtyAdapter.PtyProcess {
10 private readonly dataListeners = new Set<(data: string) => void>();23 private readonly dataListeners = new Set<(data: string) => void>();
11 private readonly exitListeners = new Set<(event: PtyAdapter.PtyExitEvent) => void>();24 private readonly exitListeners = new Set<(event: PtyAdapter.PtyExitEvent) => void>();
...@@ -33,14 +46,14 @@ class BunPtyProcess implements PtyAdapter.PtyProcess {...@@ -33,14 +46,14 @@ class BunPtyProcess implements PtyAdapter.PtyProcess {
3346
34 write(data: string): void {47 write(data: string): void {
35 if (!this.process.terminal) {48 if (!this.process.terminal) {
36 throw new Error("Bun PTY terminal handle is unavailable");49 throw new BunPtyOperationUnavailableError({ operation: "write", pid: this.pid });
37 }50 }
38 this.process.terminal.write(data);51 this.process.terminal.write(data);
39 }52 }
4053
41 resize(cols: number, rows: number): void {54 resize(cols: number, rows: number): void {
42 if (!this.process.terminal?.resize) {55 if (!this.process.terminal?.resize) {
43 throw new Error("Bun PTY resize is unavailable");56 throw new BunPtyOperationUnavailableError({ operation: "resize", pid: this.pid });
44 }57 }
45 this.process.terminal.resize(cols, rows);58 this.process.terminal.resize(cols, rows);
46 }59 }