222 lines · 7.1 KB · TypeScript
RawDownload
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 = typeof TerminalThreadInput.Type; const TerminalSessionInput = Schema.Struct({  ...TerminalThreadInput.fields,  terminalId: TerminalIdWithDefaultSchema,});export type TerminalSessionInput = Schema.Codec.Encoded<typeof TerminalSessionInput>; 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<typeof TerminalOpenInput>; export const TerminalWriteInput = Schema.Struct({  ...TerminalSessionInput.fields,  data: Schema.String.check(Schema.isNonEmpty()).check(Schema.isMaxLength(65_536)),});export type TerminalWriteInput = Schema.Codec.Encoded<typeof TerminalWriteInput>; export const TerminalResizeInput = Schema.Struct({  ...TerminalSessionInput.fields,  cols: TerminalColsSchema,  rows: TerminalRowsSchema,});export type TerminalResizeInput = Schema.Codec.Encoded<typeof TerminalResizeInput>; export const TerminalClearInput = TerminalSessionInput;export type TerminalClearInput = Schema.Codec.Encoded<typeof TerminalClearInput>; export const TerminalRestartInput = Schema.Struct({  ...TerminalSessionInput.fields,  cwd: TrimmedNonEmptyStringSchema,  cols: TerminalColsSchema,  rows: TerminalRowsSchema,  env: Schema.optional(TerminalEnvSchema),});export type TerminalRestartInput = Schema.Codec.Encoded<typeof TerminalRestartInput>; export const TerminalCloseInput = Schema.Struct({  ...TerminalThreadInput.fields,  terminalId: Schema.optional(TerminalIdSchema),  deleteHistory: Schema.optional(Schema.Boolean),});export type TerminalCloseInput = typeof TerminalCloseInput.Type; 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; export class TerminalCwdError extends Schema.TaggedErrorClass<TerminalCwdError>()(  "TerminalCwdError",  {    cwd: Schema.String,    reason: Schema.Literals(["notFound", "notDirectory", "statFailed"]),    cause: Schema.optional(Schema.Defect),  },) {  override get message() {    if (this.reason === "notDirectory") {      return `Terminal cwd is not a directory: ${this.cwd}`;    }    if (this.reason === "notFound") {      return `Terminal cwd does not exist: ${this.cwd}`;    }    const causeMessage =      this.cause && typeof this.cause === "object" && "message" in this.cause        ? this.cause.message        : undefined;    return causeMessage      ? `Failed to access terminal cwd: ${this.cwd} (${causeMessage})`      : `Failed to access terminal cwd: ${this.cwd}`;  }} export class TerminalHistoryError extends Schema.TaggedErrorClass<TerminalHistoryError>()(  "TerminalHistoryError",  {    operation: Schema.Literals(["read", "truncate", "migrate"]),    threadId: Schema.String,    terminalId: Schema.String,    cause: Schema.optional(Schema.Defect),  },) {  override get message() {    return `Failed to ${this.operation} terminal history for thread: ${this.threadId}, terminal: ${this.terminalId}`;  }} export class TerminalSessionLookupError extends Schema.TaggedErrorClass<TerminalSessionLookupError>()(  "TerminalSessionLookupError",  {    threadId: Schema.String,    terminalId: Schema.String,  },) {  override get message() {    return `Unknown terminal thread: ${this.threadId}, terminal: ${this.terminalId}`;  }} export class TerminalNotRunningError extends Schema.TaggedErrorClass<TerminalNotRunningError>()(  "TerminalNotRunningError",  {    threadId: Schema.String,    terminalId: Schema.String,  },) {  override get message() {    return `Terminal is not running for thread: ${this.threadId}, terminal: ${this.terminalId}`;  }} export const TerminalError = Schema.Union([  TerminalCwdError,  TerminalHistoryError,  TerminalSessionLookupError,  TerminalNotRunningError,]);export type TerminalError = typeof TerminalError.Type;