refactor(core): drop forwarding shim modules (#51670)

This commit is contained in:
Kit Langton
2026-09-27 14:47:19 -07:00
committed by GitHub
parent 3d109828ff
commit 28bb0a7158
11 changed files with 43 additions and 63 deletions
-6
View File
@@ -1,6 +0,0 @@
export * as File from "./file.js"
import { FileDiff } from "@opencode/schema/file-diff"
export const Diff = FileDiff.Info
export type Diff = typeof Diff.Type
+3 -3
View File
@@ -7,7 +7,7 @@ import { AbsolutePath, RelativePath } from "./schema.js"
import { FSUtil } from "@opencode/util/fs-util"
import { AppProcess } from "@opencode/util/process"
import { makeGlobalNode } from "@opencode/util/effect/app-node"
import { File } from "./file.js"
import { FileDiff } from "@opencode/schema/file-diff"
import { KeyedMutex } from "./effect/keyed-mutex.js"
import { VcsPatch } from "./vcs/patch.js"
import { gitExecutable } from "./util/git-executable.js"
@@ -152,7 +152,7 @@ export interface Interface {
to: TreeID
context?: number
paths?: readonly RelativePath[]
}) => Effect.Effect<readonly File.Diff[], OperationError>
}) => Effect.Effect<readonly FileDiff.Info[], OperationError>
readonly restore: (input: {
repository: Repository
files: ReadonlyMap<RelativePath, TreeID>
@@ -571,7 +571,7 @@ const layer = Layer.effect(
additions: stat?.additions ?? 0,
deletions: stat?.deletions ?? 0,
patch: stat?.binary ? "" : (patches.get(entry.file) ?? VcsPatch.emptyPatch(entry.file)),
} satisfies File.Diff
} satisfies FileDiff.Info
})
})
-2
View File
@@ -45,8 +45,6 @@ export const ResourceTemplate = Mcp.ResourceTemplate
export type ResourceTemplate = Mcp.ResourceTemplate
export const ResourceCatalog = Mcp.ResourceCatalog
export type ResourceCatalog = Mcp.ResourceCatalog
export const ResourceContentPart = Mcp.ResourceContentPart
export type ResourceContentPart = Mcp.ResourceContentPart
export const ResourceContent = Mcp.ResourceContent
export type ResourceContent = Mcp.ResourceContent
+20 -18
View File
@@ -6,7 +6,6 @@ import { Context, Effect, Layer, Schema, Types } from "effect"
import { Pty } from "@opencode/schema/pty"
import { Bus } from "./bus.js"
import { Location } from "./location.js"
import { PtyID } from "./pty/schema.js"
import { ShellSelect } from "./shell/select.js"
import { lazy } from "./util/lazy.js"
@@ -35,6 +34,9 @@ type Active = {
listeners: Disp[]
}
export const ID = Pty.ID
export type ID = Pty.ID
export const Info = Pty.Info
export type Info = Types.DeepMutable<typeof Info.Type>
@@ -69,21 +71,21 @@ export type Attachment = {
}
export class NotFoundError extends Schema.TaggedError<NotFoundError>()("Pty.NotFoundError", {
ptyID: PtyID,
ptyID: ID,
}) {}
export class ExitedError extends Schema.TaggedError<ExitedError>()("Pty.ExitedError", {
ptyID: PtyID,
ptyID: ID,
}) {}
export interface Interface {
readonly list: () => Effect.Effect<Info[]>
readonly get: (id: PtyID) => Effect.Effect<Info, NotFoundError>
readonly get: (id: ID) => Effect.Effect<Info, NotFoundError>
readonly create: (input: CreateInput) => Effect.Effect<Info>
readonly update: (id: PtyID, input: UpdateInput) => Effect.Effect<Info, NotFoundError>
readonly remove: (id: PtyID) => Effect.Effect<void, NotFoundError>
readonly write: (id: PtyID, data: string) => Effect.Effect<void, NotFoundError>
readonly attach: (id: PtyID, input: AttachInput) => Effect.Effect<Attachment, NotFoundError | ExitedError>
readonly update: (id: ID, input: UpdateInput) => Effect.Effect<Info, NotFoundError>
readonly remove: (id: ID) => Effect.Effect<void, NotFoundError>
readonly write: (id: ID, data: string) => Effect.Effect<void, NotFoundError>
readonly attach: (id: ID, input: AttachInput) => Effect.Effect<Attachment, NotFoundError | ExitedError>
}
export class Service extends Context.Service<Service, Interface>()("@opencode/Pty") {}
@@ -96,8 +98,8 @@ const layer = Layer.effect(
const shell = yield* ShellSelect.Service
const context = yield* Effect.context()
const runFork = Effect.runForkWith(context)
const sessions = new Map<PtyID, Active>()
const exitOrder: PtyID[] = []
const sessions = new Map<ID, Active>()
const exitOrder: ID[] = []
function notifyEnd(session: Active, event: { exitCode?: number }) {
for (const subscriber of session.subscribers.values()) {
@@ -131,13 +133,13 @@ const layer = Layer.effect(
}),
)
const requireSession = Effect.fn("Pty.requireSession")(function* (id: PtyID) {
const requireSession = Effect.fn("Pty.requireSession")(function* (id: ID) {
const session = sessions.get(id)
if (!session) return yield* new NotFoundError({ ptyID: id })
return session
})
const removeSession = Effect.fnUntraced(function* (id: PtyID) {
const removeSession = Effect.fnUntraced(function* (id: ID) {
const session = sessions.get(id)
if (!session) return
sessions.delete(id)
@@ -148,7 +150,7 @@ const layer = Layer.effect(
yield* bus.publish(Pty.Event.Deleted, { id: session.info.id })
})
const remove = Effect.fn("Pty.remove")(function* (id: PtyID) {
const remove = Effect.fn("Pty.remove")(function* (id: ID) {
yield* requireSession(id)
yield* removeSession(id)
})
@@ -157,12 +159,12 @@ const layer = Layer.effect(
return Array.from(sessions.values()).map((session) => session.info)
})
const get = Effect.fn("Pty.get")(function* (id: PtyID) {
const get = Effect.fn("Pty.get")(function* (id: ID) {
return (yield* requireSession(id)).info
})
const create = Effect.fn("Pty.create")(function* (input: CreateInput) {
const id = PtyID.ascending()
const id = ID.ascending()
const command = input.command || (yield* shell.resolve({ priority: "config" }))
const args = ShellSelect.login(command) ? [...(input.args ?? []), "-l"] : [...(input.args ?? [])]
const cwd = input.cwd || location.directory
@@ -242,7 +244,7 @@ const layer = Layer.effect(
return info
})
const update = Effect.fn("Pty.update")(function* (id: PtyID, input: UpdateInput) {
const update = Effect.fn("Pty.update")(function* (id: ID, input: UpdateInput) {
const session = yield* requireSession(id)
if (input.title) session.info.title = input.title
if (input.size && session.info.status === "running") session.process.resize(input.size.cols, input.size.rows)
@@ -250,12 +252,12 @@ const layer = Layer.effect(
return session.info
})
const write = Effect.fn("Pty.write")(function* (id: PtyID, data: string) {
const write = Effect.fn("Pty.write")(function* (id: ID, data: string) {
const session = yield* requireSession(id)
if (session.info.status === "running") session.process.write(data)
})
const attach = Effect.fn("Pty.attach")(function* (id: PtyID, input: AttachInput) {
const attach = Effect.fn("Pty.attach")(function* (id: ID, input: AttachInput) {
const session = yield* requireSession(id)
if (session.info.status !== "running") return yield* new ExitedError({ ptyID: id })
yield* Effect.logInfo("client attached to session", { id, directory: location.directory })
-1
View File
@@ -1 +0,0 @@
export { ID as PtyID } from "@opencode/schema/pty"
+2 -2
View File
@@ -2,7 +2,7 @@ export * as PtyTicket from "./ticket.js"
import type { Workspace } from "@opencode/schema/workspace"
import { PtyTicket } from "@opencode/schema/pty-ticket"
import { PtyID } from "./schema.js"
import type { Pty } from "@opencode/schema/pty"
import { Cache, Context, Duration, Effect, Layer } from "effect"
import { makeGlobalNode } from "@opencode/util/effect/app-node"
@@ -12,7 +12,7 @@ const CAPACITY = 10_000
export const ConnectToken = PtyTicket.ConnectToken
export type Scope = {
readonly ptyID: PtyID
readonly ptyID: Pty.ID
readonly directory?: string
readonly workspaceID?: Workspace.ID
}
-13
View File
@@ -29,19 +29,6 @@ export class ModelUnavailableError extends Schema.TaggedError<ModelUnavailableEr
return `Model unavailable: ${this.providerID}/${this.modelID}`
}
}
export const VariantUnavailableError = ModelResolver.VariantUnavailableError
export type VariantUnavailableError = ModelResolver.VariantUnavailableError
export const UnsupportedPackageError = ModelResolver.UnsupportedPackageError
export type UnsupportedPackageError = ModelResolver.UnsupportedPackageError
export const ModelConfigurationError = ModelResolver.ModelConfigurationError
export type ModelConfigurationError = ModelResolver.ModelConfigurationError
export const ModelInitializationError = ModelResolver.ModelInitializationError
export type ModelInitializationError = ModelResolver.ModelInitializationError
export const UnresolvedProviderVariablesError = ModelResolver.UnresolvedProviderVariablesError
export type UnresolvedProviderVariablesError = ModelResolver.UnresolvedProviderVariablesError
export const UnsupportedCompactionError = ModelResolver.UnsupportedCompactionError
export type UnsupportedCompactionError = ModelResolver.UnsupportedCompactionError
export type Error = ModelNotSelectedError | ModelUnavailableError | ModelResolver.Error
export type Resolved = ModelResolver.Resolved
@@ -4,6 +4,7 @@ import { SessionError } from "@opencode/schema/session-error"
import { Permission } from "../permission.js"
import { Integration } from "../integration.js"
import { AgentNotFoundError, StepFailedError } from "./error.js"
import { ModelResolver } from "../model-resolver.js"
import { SessionRunnerModel } from "./runner/model.js"
export function toSessionError(cause: unknown): SessionError.Error {
@@ -48,17 +49,17 @@ export function toSessionError(cause: unknown): SessionError.Error {
return unwrapped.message === "" ? { ...unwrapped, type: "tool.execution", message: cause.message } : unwrapped
}
if (cause instanceof StepFailedError) return cause.error
if (cause instanceof SessionRunnerModel.UnsupportedCompactionError)
if (cause instanceof ModelResolver.UnsupportedCompactionError)
return { type: "provider.unsupported-operation", message: cause.message }
if (cause instanceof AgentNotFoundError) return { type: "unknown", message: cause.message }
if (
cause instanceof SessionRunnerModel.ModelNotSelectedError ||
cause instanceof SessionRunnerModel.ModelUnavailableError ||
cause instanceof SessionRunnerModel.VariantUnavailableError ||
cause instanceof SessionRunnerModel.UnsupportedPackageError ||
cause instanceof SessionRunnerModel.ModelConfigurationError ||
cause instanceof SessionRunnerModel.ModelInitializationError ||
cause instanceof SessionRunnerModel.UnresolvedProviderVariablesError
cause instanceof ModelResolver.VariantUnavailableError ||
cause instanceof ModelResolver.UnsupportedPackageError ||
cause instanceof ModelResolver.ModelConfigurationError ||
cause instanceof ModelResolver.ModelInitializationError ||
cause instanceof ModelResolver.UnresolvedProviderVariablesError
)
return { type: "provider.no-route", message: cause.message }
if (cause instanceof Integration.AuthorizationError) return { type: "provider.auth", message: cause.message }
+2 -2
View File
@@ -3,7 +3,7 @@ export * as Snapshot from "./snapshot.js"
import { makeLocationNode } from "@opencode/util/effect/app-node"
import path from "path"
import { Context, Effect, Fiber, Layer, Schema, Scope } from "effect"
import { File } from "./file.js"
import { FileDiff } from "@opencode/schema/file-diff"
import { FSUtil } from "@opencode/util/fs-util"
import { Git } from "./git.js"
import { Global } from "@opencode/util/global"
@@ -58,7 +58,7 @@ export interface Interface extends State.Transformable<Editor> {
* Generate structured per-file diffs between two captured trees. `context`
* controls unchanged lines around each unified diff hunk.
*/
readonly diff: (input: DiffInput) => Effect.Effect<readonly File.Diff[], Error>
readonly diff: (input: DiffInput) => Effect.Effect<readonly FileDiff.Info[], Error>
/**
* Restore selected project-relative paths from their associated trees. A path
+4 -5
View File
@@ -5,13 +5,12 @@ import { LayerNode } from "@opencode/util/effect/layer-node"
import { Bus } from "@opencode/core/bus"
import { Location } from "@opencode/core/location"
import { Pty } from "@opencode/core/pty"
import { PtyID } from "@opencode/core/pty/schema"
import { AbsolutePath } from "@opencode/core/schema"
import { ShellSelect } from "@opencode/core/shell/select"
import { location } from "../fixture/location"
import { testEffect } from "../lib/effect"
type PtyEvent = { type: "created" | "exited" | "deleted"; id: PtyID }
type PtyEvent = { type: "created" | "exited" | "deleted"; id: Pty.ID }
const locationLayer = Layer.succeed(
Location.Service,
@@ -46,7 +45,7 @@ const createPty = Effect.fn("PtySessionTest.createPty")(function* (command: stri
)
})
const waitForEvents = (events: Queue.Queue<PtyEvent>, id: PtyID, count: number) =>
const waitForEvents = (events: Queue.Queue<PtyEvent>, id: Pty.ID, count: number) =>
Effect.gen(function* () {
const picked: Array<PtyEvent["type"]> = []
while (picked.length < count) {
@@ -61,7 +60,7 @@ const waitForEvents = (events: Queue.Queue<PtyEvent>, id: PtyID, count: number)
}),
)
const attachCollecting = Effect.fn("PtySessionTest.attachCollecting")(function* (id: PtyID, cursor?: number) {
const attachCollecting = Effect.fn("PtySessionTest.attachCollecting")(function* (id: Pty.ID, cursor?: number) {
const pty = yield* Pty.Service
const output = yield* Queue.unbounded<string>()
const ended = yield* Deferred.make<{ exitCode?: number }>()
@@ -90,7 +89,7 @@ describe("pty", () => {
it.live("returns typed not found errors for missing sessions", () =>
Effect.gen(function* () {
const pty = yield* Pty.Service
const id = PtyID.make("pty_missing")
const id = Pty.ID.make("pty_missing")
for (const result of [
yield* pty.get(id).pipe(Effect.asVoid, Effect.exit),
+5 -5
View File
@@ -1,7 +1,7 @@
import { describe, expect } from "bun:test"
import { Effect, Layer } from "effect"
import { LayerNode } from "@opencode/util/effect/layer-node"
import { PtyID } from "@opencode/core/pty/schema"
import { Pty } from "@opencode/core/pty"
import { PtyTicket } from "@opencode/core/pty/ticket"
import { Workspace } from "@opencode/core/workspace"
import { testEffect } from "../lib/effect"
@@ -17,7 +17,7 @@ describe("PTY websocket tickets", () => {
it.live("consumes tickets once", () =>
Effect.gen(function* () {
const tickets = yield* PtyTicket.Service
const scope = { ptyID: PtyID.ascending(), directory: "/tmp/a" }
const scope = { ptyID: Pty.ID.ascending(), directory: "/tmp/a" }
const issued = yield* tickets.issue(scope)
expect(yield* tickets.consume({ ...scope, ticket: issued.ticket })).toBe(true)
@@ -28,7 +28,7 @@ describe("PTY websocket tickets", () => {
it.live("rejects tickets scoped to a different request", () =>
Effect.gen(function* () {
const tickets = yield* PtyTicket.Service
const ptyID = PtyID.ascending()
const ptyID = Pty.ID.ascending()
const issued = yield* tickets.issue({ ptyID, directory: "/tmp/a" })
expect(yield* tickets.consume({ ptyID, directory: "/tmp/b", ticket: issued.ticket })).toBe(false)
@@ -39,7 +39,7 @@ describe("PTY websocket tickets", () => {
itExpiring.live("rejects tickets after the TTL elapses", () =>
Effect.gen(function* () {
const tickets = yield* PtyTicket.Service
const ptyID = PtyID.ascending()
const ptyID = Pty.ID.ascending()
const issued = yield* tickets.issue({ ptyID })
yield* Effect.promise(() => new Promise((resolve) => setTimeout(resolve, 25)))
@@ -51,7 +51,7 @@ describe("PTY websocket tickets", () => {
it.live("rejects tickets scoped to a different workspace", () =>
Effect.gen(function* () {
const tickets = yield* PtyTicket.Service
const ptyID = PtyID.ascending()
const ptyID = Pty.ID.ascending()
const workspaceID = Workspace.ID.ascending()
const issued = yield* tickets.issue({ ptyID, workspaceID })