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

@ -6,7 +6,7 @@ import { FSUtil } from "./fs-util"
import { Location } from "./location"
import { PositiveInt, RelativePath } from "./schema"
import { FileSystemSearch } from "./filesystem/search"
import { Entry, FileSystem, Match } from "@opencode-ai/schema/filesystem"
import { Entry, FileSystem, FindInput, Match } from "@opencode-ai/schema/filesystem"
export { Entry, Match, Submatch } from "@opencode-ai/schema/filesystem"
export const ReadInput = Schema.Struct({
@ -28,11 +28,7 @@ export const ListInput = Schema.Struct({
})
export type ListInput = typeof ListInput.Type
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),
}) {}
export { FindInput }
export class GlobInput extends Schema.Class<GlobInput>("FileSystem.GlobInput")({
pattern: Schema.String,

View file

@ -16,9 +16,7 @@ import {
} from "effect"
import { Integration } from "@opencode-ai/schema/integration"
import { Credential } from "./credential"
import { withStatics } from "./schema"
import { State } from "./state"
import { Identifier } from "./util/identifier"
import { EventV2 } from "./event"
import { IntegrationConnection } from "./integration/connection"
@ -28,10 +26,7 @@ export type ID = Integration.ID
export const MethodID = Integration.MethodID
export type MethodID = Integration.MethodID
export const AttemptID = Schema.String.pipe(
Schema.brand("Integration.AttemptID"),
withStatics((schema) => ({ create: () => schema.make("con_" + Identifier.ascending()) })),
)
export const AttemptID = Integration.AttemptID
export type AttemptID = typeof AttemptID.Type
export const When = Integration.When
@ -58,12 +53,8 @@ export type EnvMethod = Integration.EnvMethod
export const Method = Integration.Method
export type Method = Integration.Method
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(IntegrationConnection.Info)),
}) {}
export const Info = Integration.Info
export type Info = Integration.Info
export const Inputs = Integration.Inputs
export type Inputs = Integration.Inputs
@ -102,28 +93,10 @@ export interface EnvImplementation {
export type Implementation = OAuthImplementation | KeyImplementation | EnvImplementation
export class Attempt extends Schema.Class<Attempt>("Integration.Attempt")({
attemptID: AttemptID,
url: Schema.String,
instructions: Schema.String,
mode: Schema.Literals(["auto", "code"]),
time: Schema.Struct({
created: Schema.Number,
expires: Schema.Number,
}),
}) {}
export const Attempt = Integration.Attempt
export type Attempt = Integration.Attempt
const Time = Schema.Struct({
created: Schema.Number,
expires: Schema.Number,
})
export const AttemptStatus = Schema.Union([
Schema.Struct({ status: Schema.Literal("pending"), time: Time }),
Schema.Struct({ status: Schema.Literal("complete"), time: Time }),
Schema.Struct({ status: Schema.Literal("failed"), message: Schema.String, time: Time }),
Schema.Struct({ status: Schema.Literal("expired"), time: Time }),
]).pipe(Schema.toTaggedUnion("status"))
export const AttemptStatus = Integration.AttemptStatus
export type AttemptStatus = typeof AttemptStatus.Type
export class CodeRequiredError extends Schema.TaggedErrorClass<CodeRequiredError>()("Integration.CodeRequired", {

View file

@ -1,30 +1,15 @@
import { Context, Effect, Layer, Schema } from "effect"
import { Ref } from "@opencode-ai/schema/location"
import { Context, Effect, Layer } from "effect"
import { Info, Ref, response } from "@opencode-ai/schema/location"
import { Project } from "./project"
import { AbsolutePath, optionalOmitUndefined } from "./schema"
import { WorkspaceV2 } from "./workspace"
export * as Location from "./location"
export { Ref }
export class Info extends Schema.Class<Info>("Location.Info")({
directory: AbsolutePath,
workspaceID: optionalOmitUndefined(WorkspaceV2.ID),
project: Schema.Struct({
id: Project.ID,
directory: AbsolutePath,
}),
}) {}
export { Info, Ref, response }
export interface Interface extends Info {
readonly vcs?: Project.Vcs
}
export function response<S extends Schema.Top>(data: S) {
return Schema.Struct({ location: Info, data })
}
export class Service extends Context.Service<Service, Interface>()("@opencode/Location") {}
export const layer = (ref: Ref) =>

View file

@ -4,22 +4,13 @@ import { eq } from "drizzle-orm"
import { Context, Effect, Layer, Schema } from "effect"
import { Database } from "../database/database"
import { ProjectV2 } from "../project"
import { withStatics } from "../schema"
import { Identifier } from "../util/identifier"
import { PermissionTable } from "./sql"
import { PermissionSaved } from "@opencode-ai/schema/permission-saved"
export const ID = Schema.String.pipe(
Schema.brand("PermissionSaved.ID"),
withStatics((schema) => ({ create: () => schema.make("psv_" + Identifier.ascending()) })),
)
export const ID = PermissionSaved.ID
export type ID = typeof ID.Type
export const Info = Schema.Struct({
id: ID,
projectID: ProjectV2.ID,
action: Schema.String,
resource: Schema.String,
}).annotate({ identifier: "PermissionSaved.Info" })
export const Info = PermissionSaved.Info
export type Info = typeof Info.Type
export const ListInput = Schema.Struct({

View file

@ -14,24 +14,15 @@ import { EventV2 } from "../event"
import { Database } from "../database/database"
import { Location } from "../location"
import { ProjectDirectoriesEvent } from "@opencode-ai/schema/project-directories"
import { ProjectCopy } from "@opencode-ai/schema/project-copy"
export const StrategyID = Schema.Trim.pipe(Schema.check(Schema.isNonEmpty()), Schema.brand("ProjectCopy.StrategyID"))
export const StrategyID = ProjectCopy.StrategyID
export type StrategyID = typeof StrategyID.Type
export const CreateInput = Schema.Struct({
projectID: Project.ID,
strategy: StrategyID,
sourceDirectory: AbsolutePath,
directory: AbsolutePath,
name: Schema.optional(Schema.String),
}).annotate({ identifier: "ProjectCopy.CreateInput" })
export const CreateInput = ProjectCopy.CreateInput
export type CreateInput = typeof CreateInput.Type
export const RemoveInput = Schema.Struct({
projectID: Project.ID,
directory: AbsolutePath,
force: Schema.Boolean,
}).annotate({ identifier: "ProjectCopy.RemoveInput" })
export const RemoveInput = ProjectCopy.RemoveInput
export type RemoveInput = typeof RemoveInput.Type
export const RefreshInput = Schema.Struct({
@ -45,9 +36,7 @@ export const RefreshResult = Schema.Struct({
}).annotate({ identifier: "ProjectCopy.RefreshResult" })
export type RefreshResult = typeof RefreshResult.Type
export const Copy = Schema.Struct({
directory: AbsolutePath,
}).annotate({ identifier: "ProjectCopy.Copy" })
export const Copy = ProjectCopy.Copy
export type Copy = typeof Copy.Type
export const ListEntry = Schema.Struct({

View file

@ -2,11 +2,10 @@ export * as Pty from "./pty"
import type { Disp, Proc } from "#pty"
import { Context, Effect, Layer, Schema, Types } from "effect"
import { PtyEvent, PtyInfo } from "@opencode-ai/schema/pty"
import { PtyEvent, PtyInfo, Pty } from "@opencode-ai/schema/pty"
import { Config } from "./config"
import { EventV2 } from "./event"
import { Location } from "./location"
import { PositiveInt } from "./schema"
import { PtyID } from "./pty/schema"
import { Shell } from "./shell"
import { lazy } from "./util/lazy"
@ -40,25 +39,11 @@ export const Info = PtyInfo
export type Info = Types.DeepMutable<typeof Info.Type>
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 const CreateInput = Pty.CreateInput
export type CreateInput = Types.DeepMutable<typeof CreateInput.Type>
export const UpdateInput = Schema.Struct({
title: Schema.optional(Schema.String),
size: Schema.optional(
Schema.Struct({
rows: PositiveInt,
cols: PositiveInt,
}),
),
})
export const UpdateInput = Pty.UpdateInput
export type UpdateInput = Types.DeepMutable<typeof UpdateInput.Type>

View file

@ -1,18 +1,15 @@
export * as PtyTicket from "./ticket"
import { WorkspaceV2 } from "../workspace"
import { PositiveInt } from "../schema"
import { PtyTicket } from "@opencode-ai/schema/pty-ticket"
import { PtyID } from "./schema"
import { Cache, Context, Duration, Effect, Layer, Schema } from "effect"
import { Cache, Context, Duration, Effect, Layer } from "effect"
import { LayerNode } from "../effect/layer-node"
const DEFAULT_TTL = Duration.seconds(60)
const CAPACITY = 10_000
export const ConnectToken = Schema.Struct({
ticket: Schema.String,
expires_in: PositiveInt,
})
export const ConnectToken = PtyTicket.ConnectToken
export type Scope = {
readonly ptyID: PtyID

View file

@ -1,6 +1,6 @@
export * as Reference from "./reference"
import { Context, Effect, Layer, Schema, Scope, Types } from "effect"
import { Context, Effect, Layer, Scope, Types } from "effect"
import { Reference } from "@opencode-ai/schema/reference"
import { Global } from "./global"
import { EventV2 } from "./event"
@ -20,13 +20,8 @@ export type Source = Reference.Source
export const Event = Reference.Event
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,
}) {}
export const Info = Reference.Info
export type Info = Reference.Info
type Data = {
sources: Map<string, Types.DeepMutable<Source>>