/
Alex_Ural
/
opencode
Обзор
Документация
Войти
/
Alex_Ural
/
opencode
Код
Запросы
0
Задачи
Вики
Пакеты
0
Релизы
0
Аналитика
Безопасность
dev
packages/core/src/control-plane/move-session.ts
148 строк
5 KB
James Long
refactor(core): remove session layer exports (#34623)
30 июн 2026, 18:44
Не верифицирован
30 июн 2026, 18:44
6387f95
Код
Авторство
О чём код?
export * as MoveSession from "./move-session" import { Context, DateTime, Effect, Layer, Schema } from "effect" import { makeGlobalNode } from "../effect/app-node" import { EventV2 } from "../event" import { Git } from "../git" import { Location } from "../location" import { ProjectV2 } from "../project" import { SessionV2 } from "../session" import { SessionEvent } from "../session/event" import { SessionSchema } from "../session/schema" import { SessionStore } from "../session/store" import { AbsolutePath, RelativePath } from "../schema" import path from "path" export const Destination = Schema.Struct({ directory: AbsolutePath, }).annotate({ identifier: "MoveSession.Destination" }) export type Destination = typeof Destination.Type export const Input = Schema.Struct({ sessionID: SessionSchema.ID, destination: Destination, moveChanges: Schema.optional(Schema.Boolean), }).annotate({ identifier: "MoveSession.Input" }) export type Input = typeof Input.Type export class DestinationProjectMismatchError extends Schema.TaggedErrorClass<DestinationProjectMismatchError>()( "MoveSession.DestinationProjectMismatchError", { expected: ProjectV2.ID, actual: ProjectV2.ID, }, ) {} export class ApplyChangesError extends Schema.TaggedErrorClass<ApplyChangesError>()("MoveSession.ApplyChangesError", { message: Schema.String, }) {} export class CaptureChangesError extends Schema.TaggedErrorClass<CaptureChangesError>()( "MoveSession.CaptureChangesError", { message: Schema.String, }, ) {} export class ResetSourceChangesError extends Schema.TaggedErrorClass<ResetSourceChangesError>()( "MoveSession.ResetSourceChangesError", { directory: AbsolutePath, message: Schema.String, cause: Schema.optional(Schema.Defect()), }, ) {} export type Error = | SessionV2.NotFoundError | DestinationProjectMismatchError | CaptureChangesError | ApplyChangesError | ResetSourceChangesError export interface Interface { readonly moveSession: (input: Input) => Effect.Effect<void, Error> } export class Service extends Context.Service<Service, Interface>()("@opencode/ControlPlaneMoveSession") {} const layer = Layer.effect( Service, Effect.gen(function* () { const git = yield* Git.Service const events = yield* EventV2.Service const project = yield* ProjectV2.Service const sessions = yield* SessionStore.Service const moveSession = Effect.fn("MoveSession.moveSession")(function* (input: Input) { const current = yield* sessions.get(input.sessionID) if (!current) return yield* new SessionV2.NotFoundError({ sessionID: input.sessionID }) const directory = AbsolutePath.make(input.destination.directory) if (current.location.directory === directory) return const source = yield* project.resolve(current.location.directory) const destination = yield* project.resolve(directory) if (current.projectID !== destination.id) { return yield* new DestinationProjectMismatchError({ expected: current.projectID, actual: destination.id }) } const moveChanges = input.moveChanges && source.directory !== destination.directory const sourceRepository = moveChanges ? yield* git.repo.discover(current.location.directory) : undefined if (moveChanges && !sourceRepository) return yield* new CaptureChangesError({ message: "Source is not a Git repository" }) const patch = sourceRepository ? yield* git.change .capture({ repository: sourceRepository, path: current.location.directory }) .pipe(Effect.mapError((error) => new CaptureChangesError({ message: error.message }))) : Git.ChangeSet.make("") if (patch) { const repository = yield* git.repo.discover(directory) if (!repository) return yield* new ApplyChangesError({ message: "Destination is not a Git repository" }) yield* git.change .apply({ repository, path: directory, changes: patch }) .pipe(Effect.mapError((error) => new ApplyChangesError({ message: error.message }))) } yield* events.publish(SessionEvent.Moved, { sessionID: input.sessionID, location: Location.Ref.make({ directory }), subdirectory: RelativePath.make(path.relative(destination.directory, directory).replaceAll("\\", "/")), timestamp: yield* DateTime.now, }) if (patch) { const repository = yield* git.repo.discover(current.location.directory) if (!repository) return yield* new ResetSourceChangesError({ directory: current.location.directory, message: "Source is not a Git repository", }) yield* git.change .discard({ repository, path: current.location.directory, index: "preserve", untracked: "remove", }) .pipe( Effect.mapError( (error) => new ResetSourceChangesError({ directory: current.location.directory, message: error.message, cause: error.cause, }), ), ) } }) return Service.of({ moveSession }) }), ) export const node = makeGlobalNode({ service: Service, layer, deps: [Git.node, EventV2.node, ProjectV2.node, SessionStore.node], })