import { Schema } from "effect"; import { TrimmedNonEmptyString } from "./baseSchemas"; export const DEFAULT_TERMINAL_ID = "default"; const TrimmedNonEmptyStringSchema = TrimmedNonEmptyString; const TerminalColsSchema = Schema.Int.check(Schema.isGreaterThanOrEqualTo(20)).check( Schema.isLessThanOrEqualTo(400), ); const TerminalRowsSchema = Schema.Int.check(Schema.isGreaterThanOrEqualTo(5)).check( Schema.isLessThanOrEqualTo(200), ); const TerminalIdSchema = TrimmedNonEmptyStringSchema.check(Schema.isMaxLength(128)); const TerminalEnvKeySchema = Schema.String.check( Schema.isPattern(/^[A-Za-z_][A-Za-z0-9_]*$/), ).check(Schema.isMaxLength(128)); const TerminalEnvValueSchema = Schema.String.check(Schema.isMaxLength(8_192)); const TerminalEnvSchema = Schema.Record(TerminalEnvKeySchema, TerminalEnvValueSchema).check( Schema.isMaxProperties(128), ); const TerminalIdWithDefaultSchema = TerminalIdSchema.pipe( Schema.withDecodingDefault(() => DEFAULT_TERMINAL_ID), ); export const TerminalThreadInput = Schema.Struct({ threadId: TrimmedNonEmptyStringSchema, }); export type TerminalThreadInput = Schema.Codec.Encoded; const TerminalSessionInput = Schema.Struct({ ...TerminalThreadInput.fields, terminalId: TerminalIdWithDefaultSchema, }); export type TerminalSessionInput = Schema.Codec.Encoded; export const TerminalOpenInput = Schema.Struct({ ...TerminalSessionInput.fields, cwd: TrimmedNonEmptyStringSchema, cols: Schema.optional(TerminalColsSchema), rows: Schema.optional(TerminalRowsSchema), env: Schema.optional(TerminalEnvSchema), }); export type TerminalOpenInput = Schema.Codec.Encoded; export const TerminalWriteInput = Schema.Struct({ ...TerminalSessionInput.fields, data: Schema.String.check(Schema.isNonEmpty()).check(Schema.isMaxLength(65_536)), }); export type TerminalWriteInput = Schema.Codec.Encoded; export const TerminalResizeInput = Schema.Struct({ ...TerminalSessionInput.fields, cols: TerminalColsSchema, rows: TerminalRowsSchema, }); export type TerminalResizeInput = Schema.Codec.Encoded; export const TerminalClearInput = TerminalSessionInput; export type TerminalClearInput = Schema.Codec.Encoded; export const TerminalRestartInput = Schema.Struct({ ...TerminalThreadInput.fields, cwd: TrimmedNonEmptyStringSchema, cols: TerminalColsSchema, rows: TerminalRowsSchema, env: Schema.optional(TerminalEnvSchema), }); export const TerminalCloseInput = Schema.Struct({ ...TerminalThreadInput.fields, terminalId: Schema.optional(TerminalIdSchema), deleteHistory: Schema.optional(Schema.Boolean), }); export type TerminalCloseInput = Schema.Codec.Encoded; export const TerminalSessionStatus = Schema.Literals(["starting", "running", "exited", "error"]); export type TerminalSessionStatus = typeof TerminalSessionStatus.Type; export const TerminalSessionSnapshot = Schema.Struct({ threadId: Schema.String.check(Schema.isNonEmpty()), terminalId: Schema.String.check(Schema.isNonEmpty()), cwd: Schema.String.check(Schema.isNonEmpty()), status: TerminalSessionStatus, pid: Schema.NullOr(Schema.Int.check(Schema.isGreaterThan(0))), history: Schema.String, exitCode: Schema.NullOr(Schema.Int), exitSignal: Schema.NullOr(Schema.Int), updatedAt: Schema.String, }); export type TerminalSessionSnapshot = typeof TerminalSessionSnapshot.Type; const TerminalEventBaseSchema = Schema.Struct({ threadId: Schema.String.check(Schema.isNonEmpty()), terminalId: Schema.String.check(Schema.isNonEmpty()), createdAt: Schema.String, }); const TerminalStartedEvent = Schema.Struct({ ...TerminalEventBaseSchema.fields, type: Schema.Literal("started"), snapshot: TerminalSessionSnapshot, }); const TerminalOutputEvent = Schema.Struct({ ...TerminalEventBaseSchema.fields, type: Schema.Literal("output"), data: Schema.String, }); const TerminalExitedEvent = Schema.Struct({ ...TerminalEventBaseSchema.fields, type: Schema.Literal("exited"), exitCode: Schema.NullOr(Schema.Int), exitSignal: Schema.NullOr(Schema.Int), }); const TerminalErrorEvent = Schema.Struct({ ...TerminalEventBaseSchema.fields, type: Schema.Literal("error"), message: Schema.String.check(Schema.isNonEmpty()), }); const TerminalClearedEvent = Schema.Struct({ ...TerminalEventBaseSchema.fields, type: Schema.Literal("cleared"), }); const TerminalRestartedEvent = Schema.Struct({ ...TerminalEventBaseSchema.fields, type: Schema.Literal("restarted"), snapshot: TerminalSessionSnapshot, }); const TerminalActivityEvent = Schema.Struct({ ...TerminalEventBaseSchema.fields, type: Schema.Literal("activity"), hasRunningSubprocess: Schema.Boolean, }); export const TerminalEvent = Schema.Union([ TerminalStartedEvent, TerminalOutputEvent, TerminalExitedEvent, TerminalErrorEvent, TerminalClearedEvent, TerminalRestartedEvent, TerminalActivityEvent, ]); export type TerminalEvent = typeof TerminalEvent.Type;