refactor(protocol): extract server contracts (#33708)

This commit is contained in:
Kit Langton 2026-06-25 04:15:31 +02:00 committed by GitHub
commit 56a37c3640
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
77 changed files with 1070 additions and 878 deletions

View file

@ -1,7 +1,7 @@
export * as Credential from "./credential"
import { Schema } from "effect"
import { Integration } from "./integration"
import { IntegrationMethodID } from "./integration-id"
import { ascending } from "./identifier"
import { NonNegativeInt, withStatics } from "./schema"
@ -14,7 +14,7 @@ export type ID = typeof ID.Type
export interface OAuth extends Schema.Schema.Type<typeof OAuth> {}
export const OAuth = Schema.Struct({
type: Schema.Literal("oauth"),
methodID: Integration.MethodID,
methodID: IntegrationMethodID,
refresh: Schema.String,
access: Schema.String,
expires: NonNegativeInt,

View file

@ -31,3 +31,9 @@ export const Match = Schema.Struct({
text: Schema.String,
submatches: Schema.Array(Submatch),
}).annotate({ identifier: "FileSystem.Match" })
export class FindInput extends Schema.Class<FindInput>("FileSystem.FindInput")({
query: Schema.String,
type: Schema.Literals(["file", "directory"]).pipe(Schema.optional),
limit: PositiveInt.pipe(Schema.optional),
}) {}

View file

@ -9,7 +9,9 @@ export { LLM } from "./llm"
export { Location } from "./location"
export { Model } from "./model"
export { Permission } from "./permission"
export { PermissionSaved } from "./permission-saved"
export { Project } from "./project"
export { ProjectCopy } from "./project-copy"
export { Provider } from "./provider"
export { Reference } from "./reference"
export { Revert } from "./revert"
@ -17,6 +19,9 @@ export { Session } from "./session"
export { SessionInput } from "./session-input"
export { SessionMessage } from "./session-message"
export { Skill } from "./skill"
export { Pty } from "./pty"
export { PtyTicket } from "./pty-ticket"
export { Question } from "./question"
export { Workspace } from "./workspace"
export { Prompt, Source, FileAttachment, AgentAttachment } from "./prompt"
export * from "./schema"

View file

@ -0,0 +1,7 @@
import { Schema } from "effect"
export const IntegrationID = Schema.String.pipe(Schema.brand("Integration.ID"))
export type IntegrationID = typeof IntegrationID.Type
export const IntegrationMethodID = Schema.String.pipe(Schema.brand("Integration.MethodID"))
export type IntegrationMethodID = typeof IntegrationMethodID.Type

View file

@ -2,11 +2,15 @@ export * as Integration from "./integration"
import { Schema } from "effect"
import { define, inventory } from "./event"
import { Connection } from "./connection"
import { ascending } from "./identifier"
import { withStatics } from "./schema"
import { IntegrationID, IntegrationMethodID } from "./integration-id"
export const ID = Schema.String.pipe(Schema.brand("Integration.ID"))
export const ID = IntegrationID
export type ID = typeof ID.Type
export const MethodID = Schema.String.pipe(Schema.brand("Integration.MethodID"))
export const MethodID = IntegrationMethodID
export type MethodID = typeof MethodID.Type
export interface When extends Schema.Schema.Type<typeof When> {}
@ -88,3 +92,37 @@ export const Ref = Schema.Struct({
id: ID,
name: Schema.String,
}).annotate({ identifier: "Integration.Ref" })
export class Info extends Schema.Class<Info>("Integration.Info")({
id: ID,
name: Schema.String,
methods: Schema.mutable(Schema.Array(Method)),
connections: Schema.mutable(Schema.Array(Connection.Info)),
}) {}
export const AttemptID = Schema.String.pipe(
Schema.brand("Integration.AttemptID"),
withStatics((schema) => ({ create: () => schema.make("con_" + ascending()) })),
)
export type AttemptID = typeof AttemptID.Type
const AttemptTime = Schema.Struct({
created: Schema.Number,
expires: Schema.Number,
})
export class Attempt extends Schema.Class<Attempt>("Integration.Attempt")({
attemptID: AttemptID,
url: Schema.String,
instructions: Schema.String,
mode: Schema.Literals(["auto", "code"]),
time: AttemptTime,
}) {}
export const AttemptStatus = Schema.Union([
Schema.Struct({ status: Schema.Literal("pending"), time: AttemptTime }),
Schema.Struct({ status: Schema.Literal("complete"), time: AttemptTime }),
Schema.Struct({ status: Schema.Literal("failed"), message: Schema.String, time: AttemptTime }),
Schema.Struct({ status: Schema.Literal("expired"), time: AttemptTime }),
]).pipe(Schema.toTaggedUnion("status"))
export type AttemptStatus = typeof AttemptStatus.Type

View file

@ -1,7 +1,8 @@
export * as Location from "./location"
import { Effect, Schema } from "effect"
import { AbsolutePath } from "./schema"
import { AbsolutePath, optionalOmitUndefined } from "./schema"
import { ProjectID } from "./project-id"
import { WorkspaceID } from "./workspace-id"
export interface Ref extends Schema.Schema.Type<typeof Ref> {}
@ -12,3 +13,16 @@ export const Ref = Schema.Struct({
Schema.withConstructorDefault(Effect.succeed(undefined)),
),
}).annotate({ identifier: "Location.Ref" })
export class Info extends Schema.Class<Info>("Location.Info")({
directory: AbsolutePath,
workspaceID: optionalOmitUndefined(WorkspaceID),
project: Schema.Struct({
id: ProjectID,
directory: AbsolutePath,
}),
}) {}
export function response<S extends Schema.Top>(data: S) {
return Schema.Struct({ location: Info, data })
}

View file

@ -0,0 +1,20 @@
export * as PermissionSaved from "./permission-saved"
import { Schema } from "effect"
import { ascending } from "./identifier"
import { ProjectID } from "./project-id"
import { withStatics } from "./schema"
export const ID = Schema.String.pipe(
Schema.brand("PermissionSaved.ID"),
withStatics((schema) => ({ create: () => schema.make("psv_" + ascending()) })),
)
export type ID = typeof ID.Type
export const Info = Schema.Struct({
id: ID,
projectID: ProjectID,
action: Schema.String,
resource: Schema.String,
}).annotate({ identifier: "PermissionSaved.Info" })
export type Info = typeof Info.Type

View file

@ -0,0 +1,29 @@
export * as ProjectCopy from "./project-copy"
import { Schema } from "effect"
import { ProjectID } from "./project-id"
import { AbsolutePath } from "./schema"
export const StrategyID = Schema.Trim.pipe(Schema.check(Schema.isNonEmpty()), Schema.brand("ProjectCopy.StrategyID"))
export type StrategyID = typeof StrategyID.Type
export const CreateInput = Schema.Struct({
projectID: ProjectID,
strategy: StrategyID,
sourceDirectory: AbsolutePath,
directory: AbsolutePath,
name: Schema.optional(Schema.String),
}).annotate({ identifier: "ProjectCopy.CreateInput" })
export type CreateInput = typeof CreateInput.Type
export const RemoveInput = Schema.Struct({
projectID: ProjectID,
directory: AbsolutePath,
force: Schema.Boolean,
}).annotate({ identifier: "ProjectCopy.RemoveInput" })
export type RemoveInput = typeof RemoveInput.Type
export const Copy = Schema.Struct({
directory: AbsolutePath,
}).annotate({ identifier: "ProjectCopy.Copy" })
export type Copy = typeof Copy.Type

View file

@ -0,0 +1,8 @@
import { Schema } from "effect"
import { withStatics } from "./schema"
export const ProjectID = Schema.String.pipe(
Schema.brand("Project.ID"),
withStatics((schema) => ({ global: schema.make("global") })),
)
export type ProjectID = typeof ProjectID.Type

View file

@ -2,12 +2,10 @@ export * as Project from "./project"
import { Schema } from "effect"
import { define, inventory } from "./event"
import { NonNegativeInt, optionalOmitUndefined, withStatics } from "./schema"
import { NonNegativeInt, optionalOmitUndefined } from "./schema"
import { ProjectID } from "./project-id"
export const ID = Schema.String.pipe(
Schema.brand("Project.ID"),
withStatics((schema) => ({ global: schema.make("global") })),
)
export const ID = ProjectID
export type ID = typeof ID.Type
export const Vcs = Schema.Literal("git")

View file

@ -0,0 +1,9 @@
export * as PtyTicket from "./pty-ticket"
import { Schema } from "effect"
import { PositiveInt } from "./schema"
export const ConnectToken = Schema.Struct({
ticket: Schema.String,
expires_in: PositiveInt,
})

View file

@ -3,7 +3,7 @@ export * as Pty from "./pty"
import { Schema } from "effect"
import { define, inventory } from "./event"
import { ascending } from "./identifier"
import { NonNegativeInt } from "./schema"
import { NonNegativeInt, PositiveInt } from "./schema"
import { withStatics } from "./schema"
const IDSchema = Schema.String.check(Schema.isStartsWith("pty")).pipe(Schema.brand("PtyID"))
@ -33,3 +33,23 @@ const Exited = define({ type: "pty.exited", schema: { id: ID, exitCode: NonNegat
const Deleted = define({ type: "pty.deleted", schema: { id: ID } })
export const Event = { Created, Updated, Exited, Deleted, Definitions: inventory(Created, Updated, Exited, Deleted) }
export const PtyEvent = Event
export const CreateInput = Schema.Struct({
command: Schema.optional(Schema.String),
args: Schema.optional(Schema.Array(Schema.String)),
cwd: Schema.optional(Schema.String),
title: Schema.optional(Schema.String),
env: Schema.optional(Schema.Record(Schema.String, Schema.String)),
})
export type CreateInput = typeof CreateInput.Type
export const UpdateInput = Schema.Struct({
title: Schema.optional(Schema.String),
size: Schema.optional(
Schema.Struct({
rows: PositiveInt,
cols: PositiveInt,
}),
),
})
export type UpdateInput = typeof UpdateInput.Type

View file

@ -26,3 +26,11 @@ export const GitSource = Schema.Struct({
export const Source = Schema.Union([LocalSource, GitSource]).pipe(Schema.toTaggedUnion("type"))
export type Source = typeof Source.Type
export class Info extends Schema.Class<Info>("Reference.Info")({
name: Schema.String,
path: AbsolutePath,
description: Schema.String.pipe(Schema.optional),
hidden: Schema.Boolean.pipe(Schema.optional),
source: Source,
}) {}