authorgravatar for crazywolf132@gmail.com0x1f99d <crazywolf132@gmail.com> 2026-03-11 03:46:24+11:00
committergravatar for noreply@github.comGitHub <noreply@github.com> 2026-03-10 09:46:24-07:00
log2c351726ae21a73ac0549500783d5a4de6394214
treeb151bfec1f42230b0b9094f44acff9f16c582654
parent9e891d2e97d65a6e211e3da8ee95807b9a091563
signature Signed by PGP key B5690EEEBB952194

fix(contracts): align terminal restart input type across IPC, WS, and server (#597)


5 files changed, 22 insertions(+), 6 deletions(-)

apps/server/src/terminal/Layers/Manager.test.ts+12-1
......@@ -6,6 +6,7 @@ import {
66 DEFAULT_TERMINAL_ID,
77 type TerminalEvent,
88 type TerminalOpenInput,
9 type TerminalRestartInput,
910} from "@t3tools/contracts";
1011import { afterEach, describe, expect, it } from "vitest";
1112
......@@ -134,6 +135,16 @@ function openInput(overrides: Partial<TerminalOpenInput> = {}): TerminalOpenInpu
134135 };
135136}
136137
138function restartInput(overrides: Partial<TerminalRestartInput> = {}): TerminalRestartInput {
139 return {
140 threadId: "thread-1",
141 cwd: process.cwd(),
142 cols: 100,
143 rows: 24,
144 ...overrides,
145 };
146}
147
137148function historyLogName(threadId: string): string {
138149 return `terminal_${Encoding.encodeBase64Url(threadId)}.log`;
139150}
......@@ -361,7 +372,7 @@ describe("TerminalManager", () => {
361372 firstProcess.emitData("before restart\n");
362373 await waitFor(() => fs.existsSync(historyLogPath(logsDir)));
363374
364 const snapshot = await manager.restart(openInput());
375 const snapshot = await manager.restart(restartInput());
365376 expect(snapshot.history).toBe("");
366377 expect(snapshot.status).toBe("running");
367378 expect(ptyAdapter.spawnInputs).toHaveLength(2);
apps/server/src/terminal/Layers/Manager.ts+4-2
......@@ -8,6 +8,7 @@ import {
88 TerminalCloseInput,
99 TerminalOpenInput,
1010 TerminalResizeInput,
11 TerminalRestartInput,
1112 TerminalWriteInput,
1213 type TerminalEvent,
1314 type TerminalSessionSnapshot,
......@@ -37,6 +38,7 @@ const DEFAULT_OPEN_ROWS = 30;
3738const TERMINAL_ENV_BLOCKLIST = new Set(["PORT", "ELECTRON_RENDERER_PORT", "ELECTRON_RUN_AS_NODE"]);
3839
3940const decodeTerminalOpenInput = Schema.decodeUnknownSync(TerminalOpenInput);
41const decodeTerminalRestartInput = Schema.decodeUnknownSync(TerminalRestartInput);
4042const decodeTerminalWriteInput = Schema.decodeUnknownSync(TerminalWriteInput);
4143const decodeTerminalResizeInput = Schema.decodeUnknownSync(TerminalResizeInput);
4244const decodeTerminalClearInput = Schema.decodeUnknownSync(TerminalClearInput);
......@@ -478,8 +480,8 @@ export class TerminalManagerRuntime extends EventEmitter<TerminalManagerEvents>
478480 });
479481 }
480482
481 async restart(raw: TerminalOpenInput): Promise<TerminalSessionSnapshot> {
482 const input = decodeTerminalOpenInput(raw);
483 async restart(raw: TerminalRestartInput): Promise<TerminalSessionSnapshot> {
484 const input = decodeTerminalRestartInput(raw);
483485 return this.runWithThreadLock(input.threadId, async () => {
484486 await this.assertValidCwd(input.cwd);
485487
apps/server/src/terminal/Services/Manager.ts+2-1
......@@ -12,6 +12,7 @@ import {
1212 TerminalEvent,
1313 TerminalOpenInput,
1414 TerminalResizeInput,
15 TerminalRestartInput,
1516 TerminalSessionSnapshot,
1617 TerminalSessionStatus,
1718 TerminalWriteInput,
......@@ -88,7 +89,7 @@ export interface TerminalManagerShape {
8889 * Always resets history before spawning the new process.
8990 */
9091 readonly restart: (
91 input: TerminalOpenInput,
92 input: TerminalRestartInput,
9293 ) => Effect.Effect<TerminalSessionSnapshot, TerminalError>;
9394
9495 /**
packages/contracts/src/ipc.ts+2-1
......@@ -31,6 +31,7 @@ import type {
3131 TerminalEvent,
3232 TerminalOpenInput,
3333 TerminalResizeInput,
34 TerminalRestartInput,
3435 TerminalSessionSnapshot,
3536 TerminalWriteInput,
3637} from "./terminal";
......@@ -118,7 +119,7 @@ export interface NativeApi {
118119 write: (input: TerminalWriteInput) => Promise<void>;
119120 resize: (input: TerminalResizeInput) => Promise<void>;
120121 clear: (input: TerminalClearInput) => Promise<void>;
121 restart: (input: TerminalOpenInput) => Promise<TerminalSessionSnapshot>;
122 restart: (input: TerminalRestartInput) => Promise<TerminalSessionSnapshot>;
122123 close: (input: TerminalCloseInput) => Promise<void>;
123124 onEvent: (callback: (event: TerminalEvent) => void) => () => void;
124125 };
packages/contracts/src/terminal.ts+2-1
......@@ -60,12 +60,13 @@ export const TerminalClearInput = TerminalSessionInput;
6060export type TerminalClearInput = Schema.Codec.Encoded<typeof TerminalClearInput>;
6161
6262export const TerminalRestartInput = Schema.Struct({
63 ...TerminalThreadInput.fields,
63 ...TerminalSessionInput.fields,
6464 cwd: TrimmedNonEmptyStringSchema,
6565 cols: TerminalColsSchema,
6666 rows: TerminalRowsSchema,
6767 env: Schema.optional(TerminalEnvSchema),
6868});
69export type TerminalRestartInput = Schema.Codec.Encoded<typeof TerminalRestartInput>;
6970
7071export const TerminalCloseInput = Schema.Struct({
7172 ...TerminalThreadInput.fields,